/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: QueryDesignView.cxx,v $ * $Revision: 1.96.8.1 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_dbaccess.hxx" #ifndef DBAUI_QUERYDESIGNVIEW_HXX #include "QueryDesignView.hxx" #endif #ifndef DBAUI_QUERYTABLEVIEW_HXX #include "QueryTableView.hxx" #endif #ifndef DBAUI_QUERY_TABLEWINDOW_HXX #include "QTableWindow.hxx" #endif #ifndef _SV_TOOLBOX_HXX #include #endif #ifndef DBAUI_QUERYCONTROLLER_HXX #include "querycontroller.hxx" #endif #ifndef _SV_SPLIT_HXX #include #endif #ifndef _UNDO_HXX #include #endif #ifndef TOOLS_DIAGNOSE_EX_H #include #endif #ifndef DBAUI_QYDLGTAB_HXX #include "adtabdlg.hxx" #endif #ifndef _SV_SVAPP_HXX #include #endif #ifndef _SV_COMBOBOX_HXX #include #endif #ifndef _SV_MSGBOX_HXX #include #endif #ifndef DBACCESS_UI_BROWSER_ID_HXX #include "browserids.hxx" #endif #ifndef DBAUI_QUERYDESIGN_OSELECTIONBROWSEBOX_HXX #include "SelectionBrowseBox.hxx" #endif #ifndef _DBU_QRY_HRC_ #include "dbu_qry.hrc" #endif #ifndef _UTL_CONFIGMGR_HXX_ #include #endif #ifndef _COMPHELPER_TYPES_HXX_ #include #endif #ifndef _CONNECTIVITY_DBTOOLS_HXX_ #include #endif #ifndef _DBHELPER_DBEXCEPTION_HXX_ #include #endif #ifndef _COM_SUN_STAR_I18N_XLOCALEDATA_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_ #include #endif #ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_ #include #endif #ifndef _CONNECTIVITY_PCOLUMN_HXX_ #include #endif #ifndef DBAUI_QUERYTABLECONNECTION_HXX #include "QTableConnection.hxx" #endif #ifndef DBAUI_CONNECTIONLINE_HXX #include "ConnectionLine.hxx" #endif #ifndef DBAUI_CONNECTIONLINEDATA_HXX #include "ConnectionLineData.hxx" #endif #ifndef DBAUI_QTABLECONNECTIONDATA_HXX #include "QTableConnectionData.hxx" #endif #ifndef DBACCESS_SHARED_DBUSTRINGS_HRC #include "dbustrings.hrc" #endif #ifndef _COMPHELPER_EXTRACT_HXX_ #include #endif #ifndef DBAUI_TOOLS_HXX #include "UITools.hxx" #endif #ifndef DBAUI_QUERYCONTAINERWINDOW_HXX #include "querycontainerwindow.hxx" #endif #ifndef DBAUI_QUERYTABLEVIEW_HXX #include "QueryTableView.hxx" #endif #ifndef _DBAUI_SQLMESSAGE_HXX_ #include "sqlmessage.hxx" #endif #ifndef INCLUDED_SVTOOLS_SYSLOCALE_HXX #include #endif using namespace ::dbaui; using namespace ::utl; using namespace ::connectivity; using namespace ::dbtools; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::i18n; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::container; #define SQL_ISRULEOR2(pParseNode, e1,e2) ((pParseNode)->isRule() && (\ (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e1) || \ (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e2))) // here we define our functions used in the anonymous namespace to get our header file smaller // please look at the book LargeScale C++ to know why namespace { static const ::rtl::OUString C_AND = ::rtl::OUString::createFromAscii(" AND "); static const ::rtl::OUString C_OR = ::rtl::OUString::createFromAscii(" OR "); // forward declarations sal_Bool InsertJoin( const OQueryDesignView* _pView, const ::connectivity::OSQLParseNode *pNode); SqlParseError InstallFields(OQueryDesignView* _pView, const ::connectivity::OSQLParseNode* pNode, OJoinTableView::OTableWindowMap* pTabList ); SqlParseError GetGroupCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode* pSelectRoot ); SqlParseError GetHavingCriteria(OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode* pSelectRoot, sal_uInt16& rLevel ); SqlParseError GetOrderCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode* pParseRoot ); SqlParseError AddFunctionCondition(OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, const sal_uInt16 nLevel, sal_Bool bHaving, bool _bAddOrOnOneLine); void fillFunctionInfo( OQueryDesignView* _pView ,const ::connectivity::OSQLParseNode* pNode ,const ::rtl::OUString& sFunctionTerm ,OTableFieldDescRef& aInfo); //------------------------------------------------------------------------------ ::rtl::OUString quoteTableAlias(sal_Bool _bQuote, const ::rtl::OUString& _sAliasName, const ::rtl::OUString& _sQuote) { ::rtl::OUString sRet; if ( _bQuote && _sAliasName.getLength() ) { sRet = ::dbtools::quoteName(_sQuote,_sAliasName); const static ::rtl::OUString sTableSeparater('.'); sRet += sTableSeparater; } return sRet; } //------------------------------------------------------------------------------ ::rtl::OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef) { Reference< XConnection> xConnection = static_cast(_pView->getController()).getConnection(); ::rtl::OUString sTableRange; if ( _pTableRef ) { sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef); if ( !sTableRange.getLength() ) _pTableRef->parseNodeToStr(sTableRange,xConnection,NULL,sal_False,sal_False); } return sTableRange; } //------------------------------------------------------------------------------ void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType,OTableFieldDescRef _aDragLeft,OTableFieldDescRef _aDragRight,bool _bNatural = false) { OQueryTableView* pTableView = static_cast(_pView->getTableView()); OQueryTableConnection* pConn = static_cast( pTableView->GetTabConn(static_cast(_aDragLeft->GetTabWindow()),static_cast(_aDragRight->GetTabWindow()),true)); if ( !pConn ) { OQueryTableConnectionData* pInfoData = new OQueryTableConnectionData(); TTableConnectionData::value_type aInfoData(pInfoData); pInfoData->InitFromDrag(_aDragLeft, _aDragRight); pInfoData->SetJoinType(_eJoinType); if ( _bNatural ) { aInfoData->ResetConnLines(); pInfoData->setNatural(_bNatural); try { Reference xReferencedTableColumns(aInfoData->getReferencedTable()->getColumns()); Sequence< ::rtl::OUString> aSeq = aInfoData->getReferencingTable()->getColumns()->getElementNames(); const ::rtl::OUString* pIter = aSeq.getConstArray(); const ::rtl::OUString* pEnd = pIter + aSeq.getLength(); for(;pIter != pEnd;++pIter) { if ( xReferencedTableColumns->hasByName(*pIter) ) aInfoData->AppendConnLine(*pIter,*pIter); } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } OQueryTableConnection aInfo(pTableView, aInfoData); // da ein OQueryTableConnection-Objekt nie den Besitz der uebergebenen Daten uebernimmt, sondern sich nur den Zeiger merkt, // ist dieser Zeiger auf eine lokale Variable hier unkritisch, denn aInfoData und aInfo haben die selbe Lebensdauer pTableView->NotifyTabConnection( aInfo ); } else { ::rtl::OUString aSourceFieldName(_aDragLeft->GetField()); ::rtl::OUString aDestFieldName(_aDragRight->GetField()); // the connection could point on the other side if(pConn->GetSourceWin() == _aDragRight->GetTabWindow()) { ::rtl::OUString aTmp(aSourceFieldName); aSourceFieldName = aDestFieldName; aDestFieldName = aTmp; } pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName); pConn->UpdateLineList(); // Modified-Flag // SetModified(); // und neu zeichnen pConn->RecalcLines(); // fuer das unten folgende Invalidate muss ich dieser neuen Connection erst mal die Moeglichkeit geben, // ihr BoundingRect zu ermitteln pConn->InvalidateConnection(); } } //------------------------------------------------------------------------------ ::rtl::OUString ParseCondition( OQueryController& rController ,const ::connectivity::OSQLParseNode* pCondition ,const ::rtl::OUString _sDecimal ,const ::com::sun::star::lang::Locale& _rLocale ,sal_uInt32 _nStartIndex) { ::rtl::OUString aCondition; Reference< XConnection> xConnection = rController.getConnection(); if ( xConnection.is() ) { sal_uInt32 nCount = pCondition->count(); for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i) pCondition->getChild(i)->parseNodeToPredicateStr(aCondition, xConnection, rController.getNumberFormatter(), _rLocale, static_cast(_sDecimal.toChar()), &rController.getParser().getContext()); } return aCondition; } //------------------------------------------------------------------------------ SqlParseError FillOuterJoins(OQueryDesignView* _pView, const ::connectivity::OSQLParseNode* pTableRefList) { SqlParseError eErrorCode = eOk; sal_uInt32 nCount = pTableRefList->count(); sal_Bool bError = sal_False; for (sal_uInt32 i=0; !bError && i < nCount; ++i) { const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i); const ::connectivity::OSQLParseNode* pJoinNode = NULL; if ( SQL_ISRULE( pParseNode, qualified_join ) || SQL_ISRULE( pParseNode, joined_table ) || SQL_ISRULE( pParseNode, cross_union ) ) pJoinNode = pParseNode; else if( SQL_ISRULE(pParseNode,table_ref) && pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}' pJoinNode = pParseNode->getChild(2); if ( pJoinNode ) { if ( !InsertJoin(_pView,pJoinNode) ) bError = sal_True; } } // check if error occured if ( bError ) eErrorCode = eIllegalJoin; return eErrorCode; } // ----------------------------------------------------------------------------- /** FillDragInfo fills the field description out of the table */ //------------------------------------------------------------------------------ SqlParseError FillDragInfo( const OQueryDesignView* _pView, const ::connectivity::OSQLParseNode* pColumnRef, OTableFieldDescRef& _rDragInfo) { SqlParseError eErrorCode = eOk; sal_Bool bErg = sal_False; ::rtl::OUString aTableRange,aColumnName; sal_uInt16 nCntAccount; ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast(_pView->getController()).getParseIterator(); rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange ); if ( aTableRange.getLength() ) { OQueryTableWindow* pSTW = static_cast(_pView->getTableView())->FindTable( aTableRange ); bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) ); } if ( !bErg ) { bErg = static_cast(_pView->getTableView())->FindTableFromField(aColumnName, _rDragInfo, nCntAccount); if ( !bErg ) bErg = _pView->HasFieldByAliasName(aColumnName, _rDragInfo); } if ( !bErg ) { eErrorCode = eColumnNotFound; String sError(ModuleRes(STR_QRY_COLUMN_NOT_FOUND)); sError.SearchAndReplaceAscii("$name$",aColumnName); _pView->getController().appendError( sError ); try { Reference xMeta = _pView->getController().getConnection()->getMetaData(); if ( xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ) _pView->getController().appendError( String( ModuleRes( STR_QRY_CHECK_CASESENSITIVE ) ) ); } catch(Exception&) { } } return eErrorCode; } //------------------------------------------------------------------------------ ::rtl::OUString BuildJoinCriteria( const Reference< XConnection>& _xConnection, OConnectionLineDataVec* pLineDataList, OQueryTableConnectionData* pData) { ::rtl::OUStringBuffer aCondition; if ( _xConnection.is() ) { OConnectionLineDataVec::iterator aIter = pLineDataList->begin(); OConnectionLineDataVec::iterator aEnd = pLineDataList->end(); try { const Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData(); const ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString(); const ::rtl::OUString sEqual(RTL_CONSTASCII_USTRINGPARAM(" = ")); for(;aIter != aEnd;++aIter) { OConnectionLineDataRef pLineData = *aIter; if(aCondition.getLength()) aCondition.append(C_AND); aCondition.append(quoteTableAlias(sal_True,pData->GetAliasName(JTCS_FROM),aQuote)); aCondition.append(::dbtools::quoteName(aQuote, pLineData->GetFieldName(JTCS_FROM) )); aCondition.append(sEqual); aCondition.append(quoteTableAlias(sal_True,pData->GetAliasName(JTCS_TO),aQuote)); aCondition.append(::dbtools::quoteName(aQuote, pLineData->GetFieldName(JTCS_TO) )); } } catch(SQLException&) { OSL_ASSERT(!"Failure while building Join criteria!"); } } return aCondition.makeStringAndClear(); } //------------------------------------------------------------------------------ /** JoinCycle looks for a join cycle and append it to the string @param _xConnection the connection @param _pEntryConn the table connection which holds the data @param _pEntryTabTo the corresponding table window @param _rJoin the String which will contain the resulting string */ void JoinCycle( const Reference< XConnection>& _xConnection, OQueryTableConnection* _pEntryConn, const OQueryTableWindow* _pEntryTabTo, ::rtl::OUString& _rJoin ) { OSL_ENSURE(_pEntryConn,"TableConnection can not be null!"); OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get()); if ( pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn() ) { sal_Bool bBrace = sal_False; if(_rJoin.getLength() && _rJoin.lastIndexOf(')') == (_rJoin.getLength()-1)) { bBrace = sal_True; _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1,::rtl::OUString(' ')); } (_rJoin += C_AND) += BuildJoinCriteria(_xConnection,pData->GetConnLineDataList(),pData); if(bBrace) _rJoin += ::rtl::OUString(')'); _pEntryConn->SetVisited(sal_True); } } //------------------------------------------------------------------------------ ::rtl::OUString BuildTable( const Reference< XConnection>& _xConnection, const OQueryTableWindow* pEntryTab, bool _bForce = false ) { ::rtl::OUString aDBName(pEntryTab->GetComposedName()); // Reference< XConnection> xConnection = static_cast(_pView->getController()).getConnection(); if( _xConnection.is() ) { try { Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData(); ::rtl::OUString sCatalog, sSchema, sTable; ::dbtools::qualifiedNameComponents( xMetaData, aDBName, sCatalog, sSchema, sTable, ::dbtools::eInDataManipulation ); ::rtl::OUString aTableListStr = ::dbtools::composeTableNameForSelect( _xConnection, sCatalog, sSchema, sTable ); ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString(); if ( _bForce || isAppendTableAliasEnabled( _xConnection ) || pEntryTab->GetAliasName() != aDBName ) { aTableListStr += ::rtl::OUString::createFromAscii(" "); if ( generateAsBeforeTableAlias( _xConnection ) ) aTableListStr += ::rtl::OUString::createFromAscii("AS "); aTableListStr += ::dbtools::quoteName( aQuote, pEntryTab->GetAliasName() ); } aDBName = aTableListStr; } catch(const SQLException&) { DBG_UNHANDLED_EXCEPTION(); } } return aDBName; } //------------------------------------------------------------------------------ ::rtl::OUString BuildJoin( const Reference< XConnection>& _xConnection, const ::rtl::OUString& rLh, const ::rtl::OUString& rRh, OQueryTableConnectionData* pData) { String aErg(rLh); if ( pData->isNatural() && pData->GetJoinType() != CROSS_JOIN ) aErg.AppendAscii(" NATURAL "); switch(pData->GetJoinType()) { case LEFT_JOIN: aErg.AppendAscii(" LEFT OUTER "); break; case RIGHT_JOIN: aErg.AppendAscii(" RIGHT OUTER "); break; case CROSS_JOIN: OSL_ENSURE(!pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!"); aErg.AppendAscii(" CROSS "); break; case INNER_JOIN: OSL_ENSURE(pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!"); aErg.AppendAscii(" INNER "); break; default: aErg.AppendAscii(" FULL OUTER "); break; } aErg.AppendAscii("JOIN "); aErg += String(rRh); if ( CROSS_JOIN != pData->GetJoinType() && !pData->isNatural() ) { aErg.AppendAscii(" ON "); aErg += String(BuildJoinCriteria(_xConnection,pData->GetConnLineDataList(),pData)); } return aErg; } //------------------------------------------------------------------------------ ::rtl::OUString BuildJoin( const Reference< XConnection>& _xConnection, OQueryTableWindow* pLh, OQueryTableWindow* pRh, OQueryTableConnectionData* pData ) { bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural(); return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData); } //------------------------------------------------------------------------------ ::rtl::OUString BuildJoin( const Reference< XConnection>& _xConnection, const ::rtl::OUString &rLh, OQueryTableWindow* pRh, OQueryTableConnectionData* pData ) { return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData); } //------------------------------------------------------------------------------ ::rtl::OUString BuildJoin( const Reference< XConnection>& _xConnection, OQueryTableWindow* pLh, const ::rtl::OUString &rRh, OQueryTableConnectionData* pData ) { return BuildJoin(_xConnection,BuildTable(_xConnection,pLh),rRh,pData); } //------------------------------------------------------------------------------ void GetNextJoin( const Reference< XConnection>& _xConnection, OQueryTableConnection* pEntryConn, OQueryTableWindow* pEntryTabTo, ::rtl::OUString &aJoin) { OQueryTableConnectionData* pEntryConnData = static_cast(pEntryConn->GetData().get()); if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() ) return; // Reference< XConnection> xConnection = static_cast(_pView->getController()).getConnection(); if(!aJoin.getLength()) { OQueryTableWindow* pEntryTabFrom = static_cast(pEntryConn->GetSourceWin()); aJoin = BuildJoin(_xConnection,pEntryTabFrom,pEntryTabTo,pEntryConnData); } else if(pEntryTabTo == pEntryConn->GetDestWin()) { aJoin = BuildJoin(_xConnection,aJoin,pEntryTabTo,pEntryConnData); } else if(pEntryTabTo == pEntryConn->GetSourceWin()) { aJoin = BuildJoin(_xConnection,pEntryTabTo,aJoin,pEntryConnData); } pEntryConn->SetVisited(sal_True); // first search for the "to" window const ::std::vector* pConnections = pEntryConn->GetParent()->getTableConnections(); ::std::vector::const_iterator aIter = pConnections->begin(); ::std::vector::const_iterator aEnd = pConnections->end(); for(;aIter != aEnd;++aIter) { OQueryTableConnection* pNext = static_cast(*aIter); if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo)) { OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast(pNext->GetDestWin()) : static_cast(pNext->GetSourceWin()); // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited JoinCycle(_xConnection,pNext,pEntryTab,aJoin); if(!pNext->IsVisited()) GetNextJoin(_xConnection,pNext,pEntryTab,aJoin); } } // when nothing found found look for the "from" window if(aIter == aEnd) { OQueryTableWindow* pEntryTabFrom = static_cast(pEntryConn->GetSourceWin()); aIter = pConnections->begin(); for(;aIter != aEnd;++aIter) { OQueryTableConnection* pNext = static_cast(*aIter); if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom)) { OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast(pNext->GetDestWin()) : static_cast(pNext->GetSourceWin()); // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited JoinCycle(_xConnection,pNext,pEntryTab,aJoin); if(!pNext->IsVisited()) GetNextJoin(_xConnection,pNext,pEntryTab,aJoin); } } } } //------------------------------------------------------------------------------ SqlParseError InsertJoinConnection( const OQueryDesignView* _pView, const ::connectivity::OSQLParseNode *pNode, const EJoinType& _eJoinType) { SqlParseError eErrorCode = eOk; if (pNode->count() == 3 && // Ausdruck is geklammert SQL_ISPUNCTUATION(pNode->getChild(0),"(") && SQL_ISPUNCTUATION(pNode->getChild(2),")")) { eErrorCode = InsertJoinConnection(_pView,pNode->getChild(1), _eJoinType); } else if (SQL_ISRULEOR2(pNode,search_condition,boolean_term) && // AND/OR-Verknuepfung: pNode->count() == 3) { // nur AND Verknüpfung zulassen if (!SQL_ISTOKEN(pNode->getChild(1),AND)) eErrorCode = eIllegalJoinCondition; else if ( eOk == (eErrorCode = InsertJoinConnection(_pView,pNode->getChild(0), _eJoinType)) ) eErrorCode = InsertJoinConnection(_pView,pNode->getChild(2), _eJoinType); } else if (SQL_ISRULE(pNode,comparison_predicate)) { // only the comparison of columns is allowed DBG_ASSERT(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Fehler im Parse Tree"); if (!(SQL_ISRULE(pNode->getChild(0),column_ref) && SQL_ISRULE(pNode->getChild(2),column_ref) && pNode->getChild(1)->getNodeType() == SQL_NODE_EQUAL)) { String sError(ModuleRes(STR_QRY_JOIN_COLUMN_COMPARE)); _pView->getController().appendError( sError ); return eIllegalJoin; } OTableFieldDescRef aDragLeft = new OTableFieldDesc(); OTableFieldDescRef aDragRight = new OTableFieldDesc(); if ( eOk != ( eErrorCode = FillDragInfo(_pView,pNode->getChild(0),aDragLeft)) || eOk != ( eErrorCode = FillDragInfo(_pView,pNode->getChild(2),aDragRight))) return eErrorCode; insertConnection(_pView,_eJoinType,aDragLeft,aDragRight); } else eErrorCode = eIllegalJoin; return eErrorCode; } //------------------------------------------------------------------------------ sal_Bool GetInnerJoinCriteria( const OQueryDesignView* _pView, const ::connectivity::OSQLParseNode *pCondition) { return InsertJoinConnection(_pView,pCondition, INNER_JOIN) != eOk; } //------------------------------------------------------------------------------ ::rtl::OUString GenerateSelectList( const OQueryDesignView* _pView, OTableFields& _rFieldList, sal_Bool bAlias) { Reference< XConnection> xConnection = static_cast(_pView->getController()).getConnection(); if ( !xConnection.is() ) return ::rtl::OUString(); ::rtl::OUStringBuffer aTmpStr,aFieldListStr; sal_Bool bAsterix = sal_False; int nVis = 0; OTableFields::iterator aIter = _rFieldList.begin(); OTableFields::iterator aEnd = _rFieldList.end(); for(;aIter != aEnd;++aIter) { OTableFieldDescRef pEntryField = *aIter; if ( pEntryField->IsVisible() ) { if ( pEntryField->GetField().toChar() == '*' ) bAsterix = sal_True; ++nVis; } } if(nVis == 1) bAsterix = sal_False; try { const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); const ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString(); OJoinTableView::OTableWindowMap* pTabList = _pView->getTableView()->GetTabWinMap(); const static ::rtl::OUString sFieldSeparator(RTL_CONSTASCII_USTRINGPARAM(", ")); const static ::rtl::OUString s_sAs(RTL_CONSTASCII_USTRINGPARAM(" AS ")); aIter = _rFieldList.begin(); for(;aIter != aEnd;++aIter) { OTableFieldDescRef pEntryField = *aIter; ::rtl::OUString rFieldName = pEntryField->GetField(); if ( rFieldName.getLength() && pEntryField->IsVisible() ) { aTmpStr = ::rtl::OUString(); const ::rtl::OUString rAlias = pEntryField->GetAlias(); const ::rtl::OUString rFieldAlias = pEntryField->GetFieldAlias(); aTmpStr.append(quoteTableAlias((bAlias || bAsterix),rAlias,aQuote)); // if we have a none numeric field, the table alias could be in the name // otherwise we are not allowed to do this (e.g. 0.1 * PRICE ) if ( !pEntryField->isNumeric() ) { // we have to look if we have alias.* here but before we have to check if the column doesn't already exist String sTemp = rFieldName; OTableFieldDescRef aInfo = new OTableFieldDesc(); OJoinTableView::OTableWindowMap::iterator tableIter = pTabList->begin(); OJoinTableView::OTableWindowMap::iterator tableEnd = pTabList->end(); sal_Bool bFound = sal_False; for(;!bFound && tableIter != tableEnd ;++tableIter) { OQueryTableWindow* pTabWin = static_cast(tableIter->second); bFound = pTabWin->ExistsField( rFieldName, aInfo ); if ( bFound ) rFieldName = aInfo->GetField(); } if ( ( rFieldName.toChar() != '*' ) && ( rFieldName.indexOf( aQuote ) == -1 ) ) { OSL_ENSURE(pEntryField->GetTable().getLength(),"No table field name!"); aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName)); } else aTmpStr.append(rFieldName); } else aTmpStr.append(rFieldName); if ( pEntryField->isAggreateFunction() ) { DBG_ASSERT(pEntryField->GetFunction().getLength(),"Functionname darf hier nicht leer sein! ;-("); ::rtl::OUStringBuffer aTmpStr2( pEntryField->GetFunction()); aTmpStr2.appendAscii("("); aTmpStr2.append(aTmpStr.makeStringAndClear()); aTmpStr2.appendAscii(")"); aTmpStr = aTmpStr2; } if (rFieldAlias.getLength() && (rFieldName.toChar() != '*' || pEntryField->isNumericOrAggreateFunction() || pEntryField->isOtherFunction())) { aTmpStr.append(s_sAs); aTmpStr.append(::dbtools::quoteName(aQuote, rFieldAlias)); } aFieldListStr.append(aTmpStr.makeStringAndClear()); aFieldListStr.append(sFieldSeparator); } } if(aFieldListStr.getLength()) aFieldListStr.setLength(aFieldListStr.getLength()-2); } catch(SQLException&) { OSL_ASSERT(!"Failure while building select list!"); } return aFieldListStr.makeStringAndClear(); } //------------------------------------------------------------------------------ sal_Bool GenerateCriterias( OQueryDesignView* _pView, ::rtl::OUStringBuffer& rRetStr, ::rtl::OUStringBuffer& rHavingStr, OTableFields& _rFieldList, sal_Bool bMulti ) { // * darf keine Filter enthalten : habe ich die entsprechende Warnung schon angezeigt ? sal_Bool bCritsOnAsterikWarning = sal_False; // ** TMFS ** ::rtl::OUString aFieldName,aCriteria,aWhereStr,aHavingStr,aWork/*,aOrderStr*/; // Zeilenweise werden die Ausdr"ucke mit AND verknuepft sal_uInt16 nMaxCriteria = 0; OTableFields::iterator aIter = _rFieldList.begin(); OTableFields::iterator aEnd = _rFieldList.end(); for(;aIter != aEnd;++aIter) { nMaxCriteria = ::std::max(nMaxCriteria,(sal_uInt16)(*aIter)->GetCriteria().size()); } Reference< XConnection> xConnection = static_cast(_pView->getController()).getConnection(); if(!xConnection.is()) return FALSE; try { const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); const ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString(); const IParseContext& rContext = static_cast(_pView->getController()).getParser().getContext(); for (sal_uInt16 i=0 ; i < nMaxCriteria ; i++) { aHavingStr = aWhereStr = ::rtl::OUString(); for(aIter = _rFieldList.begin();aIter != aEnd;++aIter) { OTableFieldDescRef pEntryField = *aIter; aFieldName = pEntryField->GetField(); if (!aFieldName.getLength()) continue; aCriteria = pEntryField->GetCriteria( i ); if ( aCriteria.getLength() ) { // * is not allowed to contain any filter, only when used in combination an aggregate function if ( aFieldName.toChar() == '*' && pEntryField->isNoneFunction() ) { // only show the messagebox the first time if (!bCritsOnAsterikWarning) ErrorBox(_pView, ModuleRes( ERR_QRY_CRITERIA_ON_ASTERISK)).Execute(); bCritsOnAsterikWarning = sal_True; continue; } aWork = ::rtl::OUString(); aWork += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote); if ( (pEntryField->GetFunctionType() & (FKT_OTHER|FKT_NUMERIC)) || (aFieldName.toChar() == '*') ) aWork += aFieldName; else aWork += ::dbtools::quoteName(aQuote, aFieldName); if ( pEntryField->isAggreateFunction() || pEntryField->IsGroupBy() ) { if (!aHavingStr.getLength()) // noch keine Kriterien aHavingStr += ::rtl::OUString('('); // Klammern else aHavingStr += C_AND; if ( pEntryField->isAggreateFunction() ) { OSL_ENSURE(pEntryField->GetFunction().getLength(),"No function name for aggregate given!"); aHavingStr += pEntryField->GetFunction(); aHavingStr += ::rtl::OUString('('); // Klammern aHavingStr += aWork; aHavingStr += ::rtl::OUString(')'); // Klammern } else aHavingStr += aWork; ::rtl::OUString aTmp = aCriteria; ::rtl::OUString aErrorMsg; Reference xColumn; ::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn)); if (pParseNode.get()) { if (bMulti && !(pEntryField->isOtherFunction() || (aFieldName.toChar() == '*'))) pParseNode->replaceNodeValue(pEntryField->GetAlias(),aFieldName); ::rtl::OUString sHavingStr = aHavingStr; sal_uInt32 nCount = pParseNode->count(); for( sal_uInt32 node = 1 ; node < nCount ; ++node) pParseNode->getChild(node)->parseNodeToStr( sHavingStr, xConnection, &rContext, sal_False, !pEntryField->isOtherFunction()); aHavingStr = sHavingStr; } else aHavingStr += aCriteria; } else { if ( !aWhereStr.getLength() ) // noch keine Kriterien aWhereStr += ::rtl::OUString('('); // Klammern else aWhereStr += C_AND; aWhereStr += ::rtl::OUString(' '); // aCriteria could have some german numbers so I have to be sure here ::rtl::OUString aTmp = aCriteria; ::rtl::OUString aErrorMsg; Reference xColumn; ::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn)); if (pParseNode.get()) { if (bMulti && !(pEntryField->isOtherFunction() || (aFieldName.toChar() == '*'))) pParseNode->replaceNodeValue(pEntryField->GetAlias(),aFieldName); ::rtl::OUString aWhere = aWhereStr; pParseNode->parseNodeToStr( aWhere, xConnection, &rContext, sal_False, !pEntryField->isOtherFunction() ); aWhereStr = aWhere; } else { aWhereStr += aWork; aWhereStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("=")); aWhereStr += aCriteria; } } } // nur einmal für jedes Feld else if ( !i && pEntryField->isCondition() ) { if (!aWhereStr.getLength()) // noch keine Kriterien aWhereStr += ::rtl::OUString('('); // Klammern else aWhereStr += C_AND; aWhereStr += pEntryField->GetField(); } } if (aWhereStr.getLength()) { aWhereStr += ::rtl::OUString(')'); // Klammern zu fuer 'AND' Zweig if (rRetStr.getLength()) // schon Feldbedingungen ? rRetStr.append(C_OR); else // Klammern auf fuer 'OR' Zweig rRetStr.append(sal_Unicode('(')); rRetStr.append(aWhereStr); } if (aHavingStr.getLength()) { aHavingStr += ::rtl::OUString(')'); // Klammern zu fuer 'AND' Zweig if (rHavingStr.getLength()) // schon Feldbedingungen ? rHavingStr.append(C_OR); else // Klammern auf fuer 'OR' Zweig rHavingStr.append(sal_Unicode('(')); rHavingStr.append(aHavingStr); } } if (rRetStr.getLength()) rRetStr.append(sal_Unicode(')')); // Klammern zu fuer 'OR' Zweig if (rHavingStr.getLength()) rHavingStr.append(sal_Unicode(')')); // Klammern zu fuer 'OR' Zweig } catch(SQLException&) { OSL_ASSERT(!"Failure while building where clause!"); } return sal_True; } //------------------------------------------------------------------------------ SqlParseError GenerateOrder( OQueryDesignView* _pView, OTableFields& _rFieldList, sal_Bool bMulti, ::rtl::OUString& _rsRet) { const OQueryController& rController = static_cast(_pView->getController()); Reference< XConnection> xConnection = rController.getConnection(); if ( !xConnection.is() ) return eNoConnection; SqlParseError eErrorCode = eOk; ::rtl::OUString aColumnName; ::rtl::OUString aWorkStr; try { const bool bColumnAliasInOrderBy = rController.getSdbMetaData().supportsColumnAliasInOrderBy(); Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString(); // * darf keine Filter enthalten : habe ich die entsprechende Warnung schon angezeigt ? sal_Bool bCritsOnAsterikWarning = sal_False; // ** TMFS ** OTableFields::iterator aIter = _rFieldList.begin(); OTableFields::iterator aEnd = _rFieldList.end(); for(;aIter != aEnd;++aIter) { OTableFieldDescRef pEntryField = *aIter; EOrderDir eOrder = pEntryField->GetOrderDir(); // nur wenn eine Sortierung und ein Tabellenname vorhanden ist-> erzeugen // sonst werden die Expressions vom Order By im GenerateCriteria mit erzeugt if ( eOrder != ORDER_NONE ) { aColumnName = pEntryField->GetField(); if(aColumnName.toChar() == '*') { // die entsprechende MessageBox nur beim ersten mal anzeigen if (!bCritsOnAsterikWarning) ErrorBox(_pView, ModuleRes( ERR_QRY_ORDERBY_ON_ASTERISK)).Execute(); bCritsOnAsterikWarning = sal_True; continue; } if ( bColumnAliasInOrderBy && pEntryField->GetFieldAlias().getLength() ) { aWorkStr += ::dbtools::quoteName(aQuote, pEntryField->GetFieldAlias()); } else if ( pEntryField->isNumericOrAggreateFunction() ) { DBG_ASSERT(pEntryField->GetFunction().getLength(),"Functionname darf hier nicht leer sein! ;-("); aWorkStr += pEntryField->GetFunction(); aWorkStr += ::rtl::OUString('('); aWorkStr += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote); // only quote column name when we don't have a numeric if ( pEntryField->isNumeric() ) aWorkStr += aColumnName; else aWorkStr += ::dbtools::quoteName(aQuote, aColumnName); aWorkStr += ::rtl::OUString(')'); } else if ( pEntryField->isOtherFunction() ) { aWorkStr += aColumnName; } else { aWorkStr += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote); aWorkStr += ::dbtools::quoteName(aQuote, aColumnName); } aWorkStr += ::rtl::OUString(' '); aWorkStr += String::CreateFromAscii( ";ASC;DESC" ).GetToken( (USHORT)eOrder ); aWorkStr += ::rtl::OUString(','); } } { String sTemp(aWorkStr); sTemp.EraseTrailingChars( ',' ); aWorkStr = sTemp; } if ( aWorkStr.getLength() ) { const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy(); String sToken(aWorkStr); if ( nMaxOrder && nMaxOrder < sToken.GetTokenCount(',') ) eErrorCode = eStatementTooLong; else { _rsRet = ::rtl::OUString::createFromAscii(" ORDER BY "); _rsRet += aWorkStr; } } } catch(SQLException&) { OSL_ASSERT(!"Failure while building group by!"); } return eErrorCode; } //------------------------------------------------------------------------------ void GenerateInnerJoinCriterias(const Reference< XConnection>& _xConnection, ::rtl::OUString& _rJoinCrit, const ::std::vector* _pConnList) { ::std::vector::const_iterator aIter = _pConnList->begin(); ::std::vector::const_iterator aEnd = _pConnList->end(); for(;aIter != aEnd;++aIter) { const OQueryTableConnection* pEntryConn = static_cast(*aIter); OQueryTableConnectionData* pEntryConnData = static_cast(pEntryConn->GetData().get()); if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() ) { if(_rJoinCrit.getLength()) _rJoinCrit += C_AND; _rJoinCrit += BuildJoinCriteria(_xConnection,pEntryConnData->GetConnLineDataList(),pEntryConnData); } } } //------------------------------------------------------------------------------ void searchAndAppendName(const Reference< XConnection>& _xConnection, const OQueryTableWindow* _pTableWindow, ::std::map< ::rtl::OUString,sal_Bool,::comphelper::UStringMixLess>& _rTableNames, ::rtl::OUString& _rsTableListStr ) { ::rtl::OUString sTabName(BuildTable(_xConnection,_pTableWindow)); if(_rTableNames.find(sTabName) == _rTableNames.end()) { _rTableNames[sTabName] = sal_True; _rsTableListStr += sTabName; _rsTableListStr += ::rtl::OUString(','); } } //------------------------------------------------------------------------------ ::rtl::OUString GenerateFromClause( const Reference< XConnection>& _xConnection, const OQueryTableView::OTableWindowMap* pTabList, const ::std::vector* pConnList ) { ::rtl::OUString aTableListStr; // wird gebraucht um sicher zustelllen das eine Tabelle nicht doppelt vorkommt ::std::map< ::rtl::OUString,sal_Bool,::comphelper::UStringMixLess> aTableNames; // generate outer join clause in from if(!pConnList->empty()) { ::std::vector::const_iterator aIter = pConnList->begin(); ::std::vector::const_iterator aEnd = pConnList->end(); for(;aIter != aEnd;++aIter) static_cast(*aIter)->SetVisited(sal_False); aIter = pConnList->begin(); const sal_Bool bUseEscape = ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_OUTERJOINESCAPE ); for(;aIter != aEnd;++aIter) { OQueryTableConnection* pEntryConn = static_cast(*aIter); if(!pEntryConn->IsVisited()) { ::rtl::OUString aJoin; GetNextJoin(_xConnection,pEntryConn,static_cast(pEntryConn->GetDestWin()),aJoin); if(aJoin.getLength()) { // insert tables into table list to avoid double entries OQueryTableWindow* pEntryTabFrom = static_cast(pEntryConn->GetSourceWin()); OQueryTableWindow* pEntryTabTo = static_cast(pEntryConn->GetDestWin()); ::rtl::OUString sTabName(BuildTable(_xConnection,pEntryTabFrom)); if(aTableNames.find(sTabName) == aTableNames.end()) aTableNames[sTabName] = sal_True; sTabName = BuildTable(_xConnection,pEntryTabTo); if(aTableNames.find(sTabName) == aTableNames.end()) aTableNames[sTabName] = sal_True; ::rtl::OUString aStr; switch(static_cast(pEntryConn->GetData().get())->GetJoinType()) { case LEFT_JOIN: case RIGHT_JOIN: case FULL_JOIN: { // create outer join if ( bUseEscape ) aStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("{ OJ ")); aStr += aJoin; if ( bUseEscape ) aStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" }")); } break; default: aStr += aJoin; break; } aStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(",")); aTableListStr += aStr; } } } // and now all inner joins aIter = pConnList->begin(); for(;aIter != aEnd;++aIter) { OQueryTableConnection* pEntryConn = static_cast(*aIter); if(!pEntryConn->IsVisited()) { searchAndAppendName(_xConnection, static_cast(pEntryConn->GetSourceWin()), aTableNames, aTableListStr); searchAndAppendName(_xConnection, static_cast(pEntryConn->GetDestWin()), aTableNames, aTableListStr); } } } // all tables that haven't a connection to anyone OQueryTableView::OTableWindowMap::const_iterator aTabIter = pTabList->begin(); OQueryTableView::OTableWindowMap::const_iterator aTabEnd = pTabList->end(); for(;aTabIter != aTabEnd;++aTabIter) { const OQueryTableWindow* pEntryTab = static_cast(aTabIter->second); if(!pEntryTab->ExistsAConn()) { aTableListStr += BuildTable(_xConnection,pEntryTab); aTableListStr += ::rtl::OUString(','); } } if(aTableListStr.getLength()) aTableListStr = aTableListStr.replaceAt(aTableListStr.getLength()-1,1, ::rtl::OUString() ); return aTableListStr; } //------------------------------------------------------------------------------ ::rtl::OUString GenerateGroupBy(const OQueryDesignView* _pView,OTableFields& _rFieldList, sal_Bool bMulti ) { OQueryController& rController = static_cast(_pView->getController()); const Reference< XConnection> xConnection = rController.getConnection(); if(!xConnection.is()) return ::rtl::OUString(); ::std::map< rtl::OUString,bool> aGroupByNames; ::rtl::OUString aGroupByStr; try { const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); const ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString(); OTableFields::iterator aIter = _rFieldList.begin(); OTableFields::iterator aEnd = _rFieldList.end(); for(;aIter != aEnd;++aIter) { OTableFieldDescRef pEntryField = *aIter; if ( pEntryField->IsGroupBy() ) { DBG_ASSERT(pEntryField->GetField().getLength(),"Kein FieldName vorhanden!;-("); ::rtl::OUString sGroupByPart = quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote); // only quote the field name when it isn't calculated if ( pEntryField->isNoneFunction() ) { sGroupByPart += ::dbtools::quoteName(aQuote, pEntryField->GetField()); } else { ::rtl::OUString aTmp = pEntryField->GetField(); ::rtl::OUString aErrorMsg; Reference xColumn; ::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn)); if (pParseNode.get()) { ::rtl::OUString sGroupBy; pParseNode->parseNodeToStr( sGroupBy, xConnection, &rController.getParser().getContext(), sal_False, !pEntryField->isOtherFunction()); sGroupByPart += sGroupBy; } else sGroupByPart += pEntryField->GetField(); } if ( aGroupByNames.find(sGroupByPart) == aGroupByNames.end() ) { aGroupByNames.insert(::std::map< rtl::OUString,bool>::value_type(sGroupByPart,true)); aGroupByStr += sGroupByPart; aGroupByStr += ::rtl::OUString(','); } } } if ( aGroupByStr.getLength() ) { aGroupByStr = aGroupByStr.replaceAt(aGroupByStr.getLength()-1,1, ::rtl::OUString(' ') ); ::rtl::OUString aGroupByStr2 = ::rtl::OUString::createFromAscii(" GROUP BY "); aGroupByStr2 += aGroupByStr; aGroupByStr = aGroupByStr2; } } catch(SQLException&) { OSL_ASSERT(!"Failure while building group by!"); } return aGroupByStr; } // ----------------------------------------------------------------------------- SqlParseError GetORCriteria(OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, sal_uInt16& nLevel , sal_Bool bHaving = sal_False, bool bAddOrOnOneLine = false); // ----------------------------------------------------------------------------- SqlParseError GetSelectionCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode* pNode, sal_uInt16& rLevel ) { if (!SQL_ISRULE(pNode, select_statement)) return eNoSelectStatement; // nyi: mehr Pruefung auf korrekte Struktur! pNode = pNode ? pNode->getChild(3)->getChild(1) : NULL; // no where clause found if (!pNode || pNode->isLeaf()) return eOk; // Naechster freier Satz ... SqlParseError eErrorCode = eOk; ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1); if ( pCondition ) // no where clause { // now we have to chech the other conditions // first make the logical easier ::connectivity::OSQLParseNode::negateSearchCondition(pCondition); ::connectivity::OSQLParseNode *pNodeTmp = pNode->getChild(1); ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp); pNodeTmp = pNode->getChild(1); ::connectivity::OSQLParseNode::absorptions(pNodeTmp); pNodeTmp = pNode->getChild(1); // compress sort the criteria @see http://www.openoffice.org/issues/show_bug.cgi?id=24079 OSQLParseNode::compress(pNodeTmp); pNodeTmp = pNode->getChild(1); // first extract the inner joins conditions GetInnerJoinCriteria(_pView,pNodeTmp); // now simplify again, join are checked in ComparisonPredicate ::connectivity::OSQLParseNode::absorptions(pNodeTmp); pNodeTmp = pNode->getChild(1); // it could happen that pCondition is not more valid eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pNodeTmp, rLevel); } return eErrorCode; } //------------------------------------------------------------------------------ SqlParseError GetANDCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, sal_uInt16& nLevel, sal_Bool bHaving, bool bAddOrOnOneLine); //------------------------------------------------------------------------------ SqlParseError ComparisonPredicate(OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, const sal_uInt16 nLevel, sal_Bool bHaving, bool bAddOrOnOneLine); //------------------------------------------------------------------------------ SqlParseError GetORCriteria(OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, sal_uInt16& nLevel , sal_Bool bHaving, bool bAddOrOnOneLine) { SqlParseError eErrorCode = eOk; // Runde Klammern um den Ausdruck if (pCondition->count() == 3 && SQL_ISPUNCTUATION(pCondition->getChild(0),"(") && SQL_ISPUNCTUATION(pCondition->getChild(2),")")) { eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pCondition->getChild(1),nLevel,bHaving,bAddOrOnOneLine); } // oder Verknuepfung // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term else if (SQL_ISRULE(pCondition,search_condition)) { for (int i = 0; i < 3 && eErrorCode == eOk ; i+=2) { const ::connectivity::OSQLParseNode* pChild = pCondition->getChild(i); if ( SQL_ISRULE(pChild,search_condition) ) eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pChild,nLevel,bHaving,bAddOrOnOneLine); else { eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pChild, nLevel,bHaving, i == 0 ? false : bAddOrOnOneLine); if ( !bAddOrOnOneLine) nLevel++; } } } else eErrorCode = GetANDCriteria( _pView,_pSelectionBrw,pCondition, nLevel, bHaving,bAddOrOnOneLine ); return eErrorCode; } //-------------------------------------------------------------------------------------------------- bool CheckOrCriteria(const ::connectivity::OSQLParseNode* _pCondition,::connectivity::OSQLParseNode* _pFirstColumnRef) { bool bRet = true; ::connectivity::OSQLParseNode* pFirstColumnRef = _pFirstColumnRef; for (int i = 0; i < 3 && bRet; i+=2) { const ::connectivity::OSQLParseNode* pChild = _pCondition->getChild(i); if ( SQL_ISRULE(pChild,search_condition) ) bRet = CheckOrCriteria(pChild,pFirstColumnRef); else { // this is a simple way to test columns are the same, may be we have to adjust this algo a little bit in future. :-) ::connectivity::OSQLParseNode* pSecondColumnRef = pChild->getByRule(::connectivity::OSQLParseNode::column_ref); if ( pFirstColumnRef && pSecondColumnRef ) bRet = *pFirstColumnRef == *pSecondColumnRef; else if ( !pFirstColumnRef ) pFirstColumnRef = pSecondColumnRef; } } return bRet; } //-------------------------------------------------------------------------------------------------- SqlParseError GetANDCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, sal_uInt16& nLevel, sal_Bool bHaving, bool bAddOrOnOneLine) { const ::com::sun::star::lang::Locale aLocale = _pView->getLocale(); const ::rtl::OUString sDecimal = _pView->getDecimalSeparator(); // ich werde ein paar Mal einen gecasteten Pointer auf meinen ::com::sun::star::sdbcx::Container brauchen OQueryController& rController = static_cast(_pView->getController()); SqlParseError eErrorCode = eOk; // Runde Klammern if (SQL_ISRULE(pCondition,boolean_primary)) { // check if we have to put the or criteria on one line. const ::connectivity::OSQLParseNode* pSearchCondition = pCondition->getChild(1); bool bMustAddOrOnOneLine = CheckOrCriteria(pSearchCondition,NULL); if ( SQL_ISRULE( pSearchCondition, search_condition) ) // we have a or { _pSelectionBrw->DuplicateConditionLevel( nLevel); eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(0), nLevel,bHaving,bMustAddOrOnOneLine ); ++nLevel; eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(2), nLevel,bHaving,bMustAddOrOnOneLine ); } else eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition, nLevel,bHaving,bMustAddOrOnOneLine ); } // Das erste Element ist (wieder) eine AND-Verknuepfung else if ( SQL_ISRULE(pCondition,boolean_term) ) { OSL_ENSURE(pCondition->count() == 3,"Illegal definifiton of boolean_term"); eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(0), nLevel,bHaving,bAddOrOnOneLine ); if ( eErrorCode == eOk ) eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(2), nLevel,bHaving,bAddOrOnOneLine ); } else if (SQL_ISRULE( pCondition, comparison_predicate)) { eErrorCode = ComparisonPredicate(_pView,_pSelectionBrw,pCondition,nLevel,bHaving,bAddOrOnOneLine); } else if( SQL_ISRULE(pCondition,like_predicate) ) { const ::connectivity::OSQLParseNode* pValueExp = pCondition->getChild(0); if (SQL_ISRULE(pValueExp, column_ref ) ) { ::rtl::OUString aColumnName; ::rtl::OUString aCondition; Reference< XConnection> xConnection = rController.getConnection(); if ( xConnection.is() ) { Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); // the international doesn't matter I have a string pCondition->parseNodeToPredicateStr(aCondition, xConnection, rController.getNumberFormatter(), aLocale, static_cast(sDecimal.toChar()), &rController.getParser().getContext()); pValueExp->parseNodeToPredicateStr( aColumnName, xConnection, rController.getNumberFormatter(), aLocale, static_cast(sDecimal.toChar()), &rController.getParser().getContext()); // don't display the column name aCondition = aCondition.copy(aColumnName.getLength()); aCondition = aCondition.trim(); } OTableFieldDescRef aDragLeft = new OTableFieldDesc(); if ( eOk == ( eErrorCode = FillDragInfo(_pView,pValueExp,aDragLeft) )) { if ( bHaving ) aDragLeft->SetGroupBy(sal_True); _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); } } else if(SQL_ISRULEOR2(pValueExp,general_set_fct ,set_fct_spec) || SQL_ISRULEOR2(pValueExp,position_exp,extract_exp) || SQL_ISRULEOR2(pValueExp,fold,char_substring_fct) || SQL_ISRULEOR2(pValueExp,length_exp,char_value_fct)) { AddFunctionCondition( _pView, _pSelectionBrw, pCondition, nLevel, bHaving, bAddOrOnOneLine); } else { eErrorCode = eNoColumnInLike; String sError(ModuleRes(STR_QRY_LIKE_LEFT_NO_COLUMN)); _pView->getController().appendError( sError ); } } else if( SQL_ISRULEOR2(pCondition,test_for_null,in_predicate) || SQL_ISRULEOR2(pCondition,all_or_any_predicate,between_predicate)) { if ( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) ) { AddFunctionCondition( _pView, _pSelectionBrw, pCondition, nLevel, bHaving, bAddOrOnOneLine); } else if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) ) { // parse condition ::rtl::OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1); OTableFieldDescRef aDragLeft = new OTableFieldDesc(); if ( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) ) { if ( bHaving ) aDragLeft->SetGroupBy(sal_True); _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine); } } else { // Funktions-Bedingung parsen ::rtl::OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1); Reference< XConnection> xConnection = rController.getConnection(); Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); // the international doesn't matter I have a string ::rtl::OUString sName; pCondition->getChild(0)->parseNodeToPredicateStr(sName, xConnection, rController.getNumberFormatter(), aLocale, static_cast(sDecimal.toChar()), &rController.getParser().getContext()); OTableFieldDescRef aDragLeft = new OTableFieldDesc(); aDragLeft->SetField(sName); aDragLeft->SetFunctionType(FKT_OTHER); if ( bHaving ) aDragLeft->SetGroupBy(sal_True); _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine); } } else if( SQL_ISRULEOR2(pCondition,existence_test,unique_test) ) { // Funktions-Bedingung parsen ::rtl::OUString aCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,0); OTableFieldDescRef aDragLeft = new OTableFieldDesc(); aDragLeft->SetField(aCondition); aDragLeft->SetFunctionType(FKT_CONDITION); eErrorCode = _pSelectionBrw->InsertField(aDragLeft,BROWSER_INVALIDID,sal_False,sal_True).isValid() ? eOk : eTooManyColumns; } else //! TODO not supported yet eErrorCode = eStatementTooComplex; // Fehler einfach weiterreichen. return eErrorCode; } //------------------------------------------------------------------------------ SqlParseError AddFunctionCondition(OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, const sal_uInt16 nLevel, sal_Bool bHaving, bool bAddOrOnOneLine) { SqlParseError eErrorCode = eOk; OQueryController& rController = static_cast(_pView->getController()); OSQLParseNode* pFunction = pCondition->getChild(0); OSL_ENSURE(SQL_ISRULEOR2(pFunction,general_set_fct ,set_fct_spec) || SQL_ISRULEOR2(pFunction,position_exp,extract_exp) || SQL_ISRULEOR2(pFunction,fold,char_substring_fct) || SQL_ISRULEOR2(pFunction,length_exp,char_value_fct),"Illegal call!"); ::rtl::OUString aCondition; OTableFieldDescRef aDragLeft = new OTableFieldDesc(); ::rtl::OUString aColumnName; Reference< XConnection> xConnection = rController.getConnection(); if(xConnection.is()) { Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); pCondition->parseNodeToPredicateStr(aCondition, xConnection, rController.getNumberFormatter(), _pView->getLocale(), static_cast(_pView->getDecimalSeparator().toChar()), &rController.getParser().getContext()); pFunction->parseNodeToStr( aColumnName, xConnection, &rController.getParser().getContext(), sal_True, sal_True); // quote is to true because we need quoted elements inside the function // i75557 //pFunction->parseNodeToPredicateStr(aColumnName, // xConnection, // rController.getNumberFormatter(), // _pView->getLocale(), // static_cast(_pView->getDecimalSeparator().toChar()), // &rController.getParser().getContext()); // don't display the column name aCondition = aCondition.copy(aColumnName.getLength()); aCondition = aCondition.trim(); if ( aCondition.indexOf('=',0) == 0 ) // ignore the equal sign aCondition = aCondition.copy(1); if ( SQL_ISRULE(pFunction, general_set_fct ) ) { sal_Int32 nFunctionType = FKT_AGGREGATE; OSQLParseNode* pParamNode = pFunction->getChild(pFunction->count()-2); if ( pParamNode && pParamNode->getTokenValue().toChar() == '*' ) { OJoinTableView::OTableWindowMap* pTabList = _pView->getTableView()->GetTabWinMap(); OJoinTableView::OTableWindowMap::iterator aIter = pTabList->begin(); OJoinTableView::OTableWindowMap::iterator aTabEnd = pTabList->end(); for(;aIter != aTabEnd;++aIter) { OQueryTableWindow* pTabWin = static_cast(aIter->second); if (pTabWin->ExistsField( ::rtl::OUString::createFromAscii("*"), aDragLeft )) { aDragLeft->SetAlias(String()); aDragLeft->SetTable(String()); break; } } } else if( eOk != ( eErrorCode = FillDragInfo(_pView,pParamNode,aDragLeft)) && SQL_ISRULE(pParamNode,num_value_exp) ) { ::rtl::OUString sParameterValue; pParamNode->parseNodeToStr( sParameterValue, xConnection, &rController.getParser().getContext()); nFunctionType |= FKT_NUMERIC; aDragLeft->SetField(sParameterValue); eErrorCode = eOk; } aDragLeft->SetFunctionType(nFunctionType); if ( bHaving ) aDragLeft->SetGroupBy(sal_True); sal_Int32 nIndex = 0; aDragLeft->SetFunction(aColumnName.getToken(0,'(',nIndex)); } else { // bei unbekannten Funktionen wird der gesamte Text in das Field gechrieben aDragLeft->SetField(aColumnName); if(bHaving) aDragLeft->SetGroupBy(sal_True); aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC); } _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); } return eErrorCode; } //------------------------------------------------------------------------------ SqlParseError ComparisonPredicate(OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode * pCondition, const sal_uInt16 nLevel, sal_Bool bHaving ,bool bAddOrOnOneLine) { SqlParseError eErrorCode = eOk; OQueryController& rController = static_cast(_pView->getController()); DBG_ASSERT(SQL_ISRULE( pCondition, comparison_predicate),"ComparisonPredicate: pCondition ist kein ComparisonPredicate"); if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) || SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref) ) { ::rtl::OUString aCondition; OTableFieldDescRef aDragLeft = new OTableFieldDesc(); if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) && SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) ) { OTableFieldDescRef aDragRight = new OTableFieldDesc(); if (eOk != ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) || eOk != ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(2),aDragRight))) return eErrorCode; OQueryTableConnection* pConn = static_cast( _pView->getTableView()->GetTabConn(static_cast(aDragLeft->GetTabWindow()), static_cast(aDragRight->GetTabWindow()), true)); if ( pConn ) { OConnectionLineDataVec* pLineDataList = pConn->GetData()->GetConnLineDataList(); OConnectionLineDataVec::iterator aIter = pLineDataList->begin(); OConnectionLineDataVec::iterator aEnd = pLineDataList->end(); for(;aIter != aEnd;++aIter) { if((*aIter)->GetSourceFieldName() == aDragLeft->GetField() || (*aIter)->GetDestFieldName() == aDragLeft->GetField() ) break; } if(aIter != aEnd) return eOk; } } sal_uInt32 nPos = 0; if(SQL_ISRULE(pCondition->getChild(0), column_ref )) { nPos = 0; sal_uInt32 i=1; // don't display the equal if (pCondition->getChild(i)->getNodeType() == SQL_NODE_EQUAL) i++; // Bedingung parsen aCondition = ParseCondition(rController ,pCondition ,_pView->getDecimalSeparator() ,_pView->getLocale() ,i); } else if( SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) ) { nPos = pCondition->count()-1; sal_Int32 i = static_cast(pCondition->count() - 2); switch (pCondition->getChild(i)->getNodeType()) { case SQL_NODE_EQUAL: // don't display the equal i--; break; case SQL_NODE_LESS: // take the opposite as we change the order i--; aCondition = aCondition + ::rtl::OUString::createFromAscii(">"); break; case SQL_NODE_LESSEQ: // take the opposite as we change the order i--; aCondition = aCondition + ::rtl::OUString::createFromAscii(">="); break; case SQL_NODE_GREAT: // take the opposite as we change the order i--; aCondition = aCondition + ::rtl::OUString::createFromAscii("<"); break; case SQL_NODE_GREATEQ: // take the opposite as we change the order i--; aCondition = aCondition + ::rtl::OUString::createFromAscii("<="); break; default: break; } // go backward Reference< XConnection> xConnection = rController.getConnection(); if(xConnection.is()) { Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); for (; i >= 0; i--) pCondition->getChild(i)->parseNodeToPredicateStr(aCondition, xConnection, rController.getNumberFormatter(), _pView->getLocale(), static_cast(_pView->getDecimalSeparator().toChar()), &rController.getParser().getContext()); } } // else ??? if( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(nPos),aDragLeft))) { if(bHaving) aDragLeft->SetGroupBy(sal_True); _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); } } else if( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) ) { AddFunctionCondition( _pView, _pSelectionBrw, pCondition, nLevel, bHaving, bAddOrOnOneLine); } else // kann sich nur um einen Expr. Ausdruck handeln { ::rtl::OUString aName,aCondition; ::connectivity::OSQLParseNode *pLhs = pCondition->getChild(0); ::connectivity::OSQLParseNode *pRhs = pCondition->getChild(2); // Feldnamen Reference< XConnection> xConnection = rController.getConnection(); if(xConnection.is()) { pLhs->parseNodeToStr(aName, xConnection, &rController.getParser().getContext(), sal_True); // Kriterium aCondition = pCondition->getChild(1)->getTokenValue(); pRhs->parseNodeToPredicateStr(aCondition, xConnection, rController.getNumberFormatter(), _pView->getLocale(), static_cast(_pView->getDecimalSeparator().toChar()), &rController.getParser().getContext()); } OTableFieldDescRef aDragLeft = new OTableFieldDesc(); aDragLeft->SetField(aName); aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC); // und anh"angen _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); } return eErrorCode; } //------------------------------------------------------------------------------ namespace { OQueryTableWindow* lcl_findColumnInTables( const ::rtl::OUString& _rColumName, const OJoinTableView::OTableWindowMap& _rTabList, OTableFieldDescRef& _rInfo ) { OJoinTableView::OTableWindowMap::const_iterator aIter = _rTabList.begin(); OJoinTableView::OTableWindowMap::const_iterator aEnd = _rTabList.end(); for ( ; aIter != aEnd; ++aIter ) { OQueryTableWindow* pTabWin = static_cast< OQueryTableWindow* >( aIter->second ); if ( pTabWin && pTabWin->ExistsField( _rColumName, _rInfo ) ) return pTabWin; } return NULL; } } //------------------------------------------------------------------------------ void InsertColumnRef(const OQueryDesignView* _pView, const ::connectivity::OSQLParseNode * pColumnRef, ::rtl::OUString& aColumnName, const ::rtl::OUString& aColumnAlias, ::rtl::OUString& aTableRange, OTableFieldDescRef& _raInfo, OJoinTableView::OTableWindowMap* pTabList) { // Tabellennamen zusammen setzen ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast(_pView->getController()).getParseIterator(); rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange ); sal_Bool bFound(sal_False); DBG_ASSERT(aColumnName.getLength(),"Columnname darf nicht leer sein"); if (!aTableRange.getLength()) { // SELECT column, ... bFound = NULL != lcl_findColumnInTables( aColumnName, *pTabList, _raInfo ); if ( bFound && ( aColumnName.toChar() != '*' ) ) _raInfo->SetFieldAlias(aColumnAlias); } else { // SELECT range.column, ... OQueryTableWindow* pTabWin = static_cast(_pView->getTableView())->FindTable(aTableRange); if (pTabWin && pTabWin->ExistsField(aColumnName, _raInfo)) { if(aColumnName.toChar() != '*') _raInfo->SetFieldAlias(aColumnAlias); bFound = sal_True; } } if (!bFound) { _raInfo->SetTable(::rtl::OUString()); _raInfo->SetAlias(::rtl::OUString()); _raInfo->SetField(aColumnName); _raInfo->SetFieldAlias(aColumnAlias); // nyi : hier ein fortlaufendes Expr_1, Expr_2 ... _raInfo->SetFunctionType(FKT_OTHER); } } //----------------------------------------------------------------------------- sal_Bool checkJoinConditions( const OQueryDesignView* _pView, const ::connectivity::OSQLParseNode* _pNode ) { const ::connectivity::OSQLParseNode* pJoinNode = NULL; sal_Bool bRet = sal_True; if (SQL_ISRULE(_pNode,qualified_join)) pJoinNode = _pNode; else if (SQL_ISRULE(_pNode,table_ref) && _pNode->count() == 3 && SQL_ISPUNCTUATION(_pNode->getChild(0),"(") && SQL_ISPUNCTUATION(_pNode->getChild(2),")") ) // '(' joined_table ')' pJoinNode = _pNode->getChild(1); else if (! ( SQL_ISRULE(_pNode, table_ref) && _pNode->count() == 2) ) // table_node table_primary_as_range_column bRet = sal_False; if (pJoinNode && !InsertJoin(_pView,pJoinNode)) bRet = sal_False; return bRet; } //----------------------------------------------------------------------------- sal_Bool InsertJoin(const OQueryDesignView* _pView, const ::connectivity::OSQLParseNode *pNode) { DBG_ASSERT( SQL_ISRULE( pNode, qualified_join ) || SQL_ISRULE( pNode, joined_table ) || SQL_ISRULE( pNode, cross_union ), "OQueryDesignView::InsertJoin: Fehler im Parse Tree"); if (SQL_ISRULE(pNode,joined_table)) return InsertJoin(_pView,pNode->getChild(1)); // first check the left and right side const ::connectivity::OSQLParseNode* pRightTableRef = pNode->getChild(3); // table_ref if ( SQL_ISRULE(pNode, qualified_join) && SQL_ISTOKEN(pNode->getChild(1),NATURAL) ) pRightTableRef = pNode->getChild(4); // table_ref if ( !checkJoinConditions(_pView,pNode->getChild(0)) || !checkJoinConditions(_pView,pRightTableRef)) return sal_False; // named column join wird später vieleicht noch implementiert // SQL_ISRULE(pNode->getChild(4),named_columns_join) EJoinType eJoinType = INNER_JOIN; bool bNatural = false; if ( SQL_ISRULE(pNode, qualified_join) ) { ::connectivity::OSQLParseNode* pJoinType = pNode->getChild(1); // join_type if ( SQL_ISTOKEN(pJoinType,NATURAL) ) { bNatural = true; pJoinType = pNode->getChild(2); } if (SQL_ISRULE(pJoinType,join_type) && SQL_ISTOKEN(pJoinType->getChild(0),INNER)) { eJoinType = INNER_JOIN; } else { if (SQL_ISRULE(pJoinType,join_type)) // eine Ebene tiefer pJoinType = pJoinType->getChild(0); if (SQL_ISTOKEN(pJoinType->getChild(0),LEFT)) eJoinType = LEFT_JOIN; else if(SQL_ISTOKEN(pJoinType->getChild(0),RIGHT)) eJoinType = RIGHT_JOIN; else eJoinType = FULL_JOIN; } if ( SQL_ISRULE(pNode->getChild(4),join_condition) ) { if ( InsertJoinConnection(_pView,pNode->getChild(4)->getChild(1), eJoinType) != eOk ) return sal_False; } } else if ( SQL_ISRULE(pNode, cross_union) ) { eJoinType = CROSS_JOIN; pRightTableRef = pNode->getChild(pNode->count() - 1); } else return sal_False; if ( eJoinType == CROSS_JOIN || bNatural ) { OQueryTableWindow* pLeftWindow = static_cast(_pView->getTableView())->FindTable( getTableRange(_pView,pNode->getChild(0)) ); OQueryTableWindow* pRightWindow = static_cast(_pView->getTableView())->FindTable( getTableRange(_pView,pRightTableRef) ); OSL_ENSURE(pLeftWindow && pRightWindow,"Table Windows could not be found!"); if ( !pLeftWindow || !pRightWindow ) return sal_False; OTableFieldDescRef aDragLeft = new OTableFieldDesc(); aDragLeft->SetTabWindow(pLeftWindow); aDragLeft->SetTable(pLeftWindow->GetTableName()); aDragLeft->SetAlias(pLeftWindow->GetAliasName()); OTableFieldDescRef aDragRight = new OTableFieldDesc(); aDragRight->SetTabWindow(pRightWindow); aDragRight->SetTable(pRightWindow->GetTableName()); aDragRight->SetAlias(pRightWindow->GetAliasName()); insertConnection(_pView,eJoinType,aDragLeft,aDragRight,bNatural); } return sal_True; } //------------------------------------------------------------------------------ void insertUnUsedFields(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw) { // now we have to insert the fields which aren't in the statement OQueryController& rController = static_cast(_pView->getController()); OTableFields& rUnUsedFields = rController.getUnUsedFields(); OTableFields::iterator aEnd = rUnUsedFields.end(); for(OTableFields::iterator aIter = rUnUsedFields.begin();aIter != aEnd;++aIter) if(_pSelectionBrw->InsertField(*aIter,BROWSER_INVALIDID,sal_False,sal_False).isValid()) (*aIter) = NULL; OTableFields().swap( rUnUsedFields ); } //------------------------------------------------------------------------------ SqlParseError InitFromParseNodeImpl(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw) { SqlParseError eErrorCode = eOk; OQueryController& rController = static_cast(_pView->getController()); _pSelectionBrw->PreFill(); _pSelectionBrw->SetReadOnly(rController.isReadOnly()); _pSelectionBrw->Fill(); ::connectivity::OSQLParseTreeIterator& aIterator = rController.getParseIterator(); const ::connectivity::OSQLParseNode* pParseTree = aIterator.getParseTree(); do { if ( !pParseTree ) { // now we have to insert the fields which aren't in the statement insertUnUsedFields(_pView,_pSelectionBrw); break; } if ( !rController.isEsacpeProcessing() ) // not allowed in this mode { eErrorCode = eNativeMode; break; } if ( !( SQL_ISRULE( pParseTree, select_statement ) ) ) { eErrorCode = eNoSelectStatement; break; } Reference< XConnection> xConnection = rController.getConnection(); if ( !xConnection.is() ) { DBG_ERROR( "InitFromParseNodeImpl: no connection? no connection!" ); break; } const OSQLTables& aMap = aIterator.getTables(); ::comphelper::UStringMixLess aTmp(aMap.key_comp()); ::comphelper::UStringMixEqual aKeyComp( aTmp.isCaseSensitive() ); Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); try { sal_Int32 nMax = xMetaData->getMaxTablesInSelect(); if ( nMax && nMax < (sal_Int32)aMap.size() ) { eErrorCode = eTooManyTables; break; } ::rtl::OUString sComposedName; ::rtl::OUString aQualifierName; ::rtl::OUString sAlias; OQueryTableView* pTableView = static_cast(_pView->getTableView()); pTableView->clearLayoutInformation(); OSQLTables::const_iterator aIter = aMap.begin(); OSQLTables::const_iterator aEnd = aMap.end(); for(;aIter != aEnd;++aIter) { OSQLTable xTable = aIter->second; Reference< XPropertySet > xTableProps( xTable, UNO_QUERY_THROW ); sAlias = aIter->first; // check whether this is a query Reference< XPropertySetInfo > xPSI = xTableProps->getPropertySetInfo(); bool bIsQuery = xPSI.is() && xPSI->hasPropertyByName( PROPERTY_COMMAND ); if ( bIsQuery ) OSL_VERIFY( xTableProps->getPropertyValue( PROPERTY_NAME ) >>= sComposedName ); else { sComposedName = ::dbtools::composeTableName( xMetaData, xTableProps, ::dbtools::eInDataManipulation, false, false, false ); // if the alias is the complete (composed) table, then shorten it if ( aKeyComp( sComposedName, aIter->first ) ) { ::rtl::OUString sCatalog, sSchema, sTable; ::dbtools::qualifiedNameComponents( xMetaData, sComposedName, sCatalog, sSchema, sTable, ::dbtools::eInDataManipulation ); sAlias = sTable; } } // find the existent window for this alias OQueryTableWindow* pExistentWin = pTableView->FindTable( sAlias ); if ( !pExistentWin ) { pTableView->AddTabWin( sComposedName, sAlias, sal_False ); // don't create data here } else { // there already exists a window for this alias .... if ( !aKeyComp( pExistentWin->GetData()->GetComposedName(), sComposedName ) ) // ... but for another complete table name -> new window pTableView->AddTabWin(sComposedName, sAlias); } } // now delete the data for which we haven't any tablewindow OJoinTableView::OTableWindowMap aTableMap(*pTableView->GetTabWinMap()); OJoinTableView::OTableWindowMap::iterator aIterTableMap = aTableMap.begin(); OJoinTableView::OTableWindowMap::iterator aIterTableEnd = aTableMap.end(); for(;aIterTableMap != aIterTableEnd;++aIterTableMap) { if(aMap.find(aIterTableMap->second->GetComposedName()) == aMap.end() && aMap.find(aIterTableMap->first) == aMap.end()) pTableView->RemoveTabWin(aIterTableMap->second); } if ( eOk == (eErrorCode = FillOuterJoins(_pView,pParseTree->getChild(3)->getChild(0)->getChild(1))) ) { // check if we have a distinct statement if(SQL_ISTOKEN(pParseTree->getChild(1),DISTINCT)) { rController.setDistinct(sal_True); rController.InvalidateFeature(SID_QUERY_DISTINCT_VALUES); } if ( (eErrorCode = InstallFields(_pView,pParseTree, pTableView->GetTabWinMap())) == eOk ) { // GetSelectionCriteria must be called before GetHavingCriteria sal_uInt16 nLevel=0; if ( eOk == (eErrorCode = GetSelectionCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) ) { if ( eOk == (eErrorCode = GetGroupCriteria(_pView,_pSelectionBrw,pParseTree)) ) { if ( eOk == (eErrorCode = GetHavingCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) ) { if ( eOk == (eErrorCode = GetOrderCriteria(_pView,_pSelectionBrw,pParseTree)) ) insertUnUsedFields(_pView,_pSelectionBrw); } } } } } } catch(SQLException&) { OSL_ASSERT(!"getMaxTablesInSelect!"); } } while ( false ); // Durch das Neuerzeugen wurden wieder Undo-Actions in den Manager gestellt rController.getUndoMgr()->Clear(); _pSelectionBrw->Invalidate(); return eErrorCode; } //------------------------------------------------------------------------------ /** fillSelectSubList @return when columns could be inserted otherwise */ //------------------------------------------------------------------------------ SqlParseError fillSelectSubList( OQueryDesignView* _pView, OJoinTableView::OTableWindowMap* _pTabList) { SqlParseError eErrorCode = eOk; sal_Bool bFirstField = sal_True; ::rtl::OUString sAsterix(RTL_CONSTASCII_USTRINGPARAM("*")); OJoinTableView::OTableWindowMap::iterator aIter = _pTabList->begin(); OJoinTableView::OTableWindowMap::iterator aEnd = _pTabList->end(); for(;aIter != aEnd && eOk == eErrorCode ;++aIter) { OQueryTableWindow* pTabWin = static_cast(aIter->second); OTableFieldDescRef aInfo = new OTableFieldDesc(); if (pTabWin->ExistsField( sAsterix, aInfo )) { eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField); bFirstField = sal_False; } } return eErrorCode; } //------------------------------------------------------------------------------ void fillFunctionInfo( OQueryDesignView* _pView ,const ::connectivity::OSQLParseNode* pNode ,const ::rtl::OUString& sFunctionTerm ,OTableFieldDescRef& aInfo) { // get the type out of the funtion name OQueryController& rController = static_cast(_pView->getController()); sal_Int32 nDataType = DataType::DOUBLE; ::rtl::OUString sFieldName = sFunctionTerm; OSQLParseNode* pFunctionName = pNode->getChild(0); if ( !SQL_ISPUNCTUATION(pFunctionName,"{") ) { if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct) ) pFunctionName = pFunctionName->getChild(0); ::rtl::OUString sFunctionName = pFunctionName->getTokenValue(); if ( !sFunctionName.getLength() ) sFunctionName = ::rtl::OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8); nDataType = OSQLParser::getFunctionReturnType( sFunctionName ,&rController.getParser().getContext()); } aInfo->SetDataType(nDataType); aInfo->SetFieldType(TAB_NORMAL_FIELD); aInfo->SetField(sFieldName); aInfo->SetTabWindow(NULL); } //------------------------------------------------------------------------------ SqlParseError InstallFields(OQueryDesignView* _pView, const ::connectivity::OSQLParseNode* pNode, OJoinTableView::OTableWindowMap* pTabList ) { if( pNode==0 || !SQL_ISRULE(pNode,select_statement)) return eNoSelectStatement; ::connectivity::OSQLParseNode* pParseTree = pNode->getChild(2); sal_Bool bFirstField = sal_True; // bei der Initialisierung muß auf alle Faelle das erste Feld neu aktiviert werden SqlParseError eErrorCode = eOk; if ( pParseTree->isRule() && SQL_ISPUNCTUATION(pParseTree->getChild(0),"*") ) { // SELECT * ... eErrorCode = fillSelectSubList(_pView,pTabList); } else if (SQL_ISRULE(pParseTree,scalar_exp_commalist) ) { // SELECT column, ... OQueryController& rController = static_cast(_pView->getController()); Reference< XConnection> xConnection = rController.getConnection(); ::rtl::OUString aColumnName,aTableRange; for (sal_uInt32 i = 0; i < pParseTree->count() && eOk == eErrorCode ; ++i) { ::connectivity::OSQLParseNode * pColumnRef = pParseTree->getChild(i); do { if ( SQL_ISRULE(pColumnRef,select_sublist) ) { eErrorCode = fillSelectSubList(_pView,pTabList); break; } if ( SQL_ISRULE(pColumnRef,derived_column) ) { if ( !xConnection.is() ) break; ::rtl::OUString aColumnAlias(rController.getParseIterator().getColumnAlias(pColumnRef)); // kann leer sein pColumnRef = pColumnRef->getChild(0); OTableFieldDescRef aInfo = new OTableFieldDesc(); if ( pColumnRef->count() == 3 && SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") && SQL_ISPUNCTUATION(pColumnRef->getChild(2),")") ) pColumnRef = pColumnRef->getChild(1); if (SQL_ISRULE(pColumnRef,column_ref)) { InsertColumnRef(_pView,pColumnRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList); eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField); bFirstField = sal_False; } else if(SQL_ISRULEOR2(pColumnRef,general_set_fct ,set_fct_spec) || SQL_ISRULEOR2(pColumnRef,position_exp,extract_exp) || SQL_ISRULEOR2(pColumnRef,fold,char_substring_fct) || SQL_ISRULEOR2(pColumnRef,length_exp,char_value_fct)) { ::rtl::OUString aColumns; pColumnRef->parseNodeToStr( aColumns, xConnection, &rController.getParser().getContext(), sal_True, sal_True); // quote is to true because we need quoted elements inside the function sal_Int32 nFunctionType = FKT_NONE; ::connectivity::OSQLParseNode* pParamRef = NULL; sal_Int32 nColumnRefPos = pColumnRef->count() - 2; if ( nColumnRefPos >= 0 && static_cast(nColumnRefPos) < pColumnRef->count() ) pParamRef = pColumnRef->getChild(nColumnRefPos); if ( SQL_ISRULE(pColumnRef,general_set_fct) && SQL_ISRULE(pParamRef,column_ref) ) { // Parameter auf Columnref pr"ufen InsertColumnRef(_pView,pParamRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList); } else if ( SQL_ISRULE(pColumnRef,general_set_fct) ) { if ( pParamRef && pParamRef->getTokenValue().toChar() == '*' ) { OJoinTableView::OTableWindowMap::iterator aIter = pTabList->begin(); OJoinTableView::OTableWindowMap::iterator aEnd = pTabList->end(); for(;aIter != aEnd;++aIter) { OQueryTableWindow* pTabWin = static_cast(aIter->second); if (pTabWin->ExistsField( ::rtl::OUString::createFromAscii("*"), aInfo )) { aInfo->SetAlias(String()); aInfo->SetTable(String()); break; } } } else { ::rtl::OUString sFieldName = aColumns; if ( pParamRef ) { // we got an aggregate function but without column name inside // so we set the whole argument of the function as field name nFunctionType |= FKT_NUMERIC; sFieldName = ::rtl::OUString(); pParamRef->parseNodeToStr( sFieldName, xConnection, &rController.getParser().getContext(), sal_True, sal_True); // quote is to true because we need quoted elements inside the function } aInfo->SetDataType(DataType::DOUBLE); aInfo->SetFieldType(TAB_NORMAL_FIELD); aInfo->SetField(sFieldName); } aInfo->SetTabWindow(NULL); aInfo->SetFieldAlias(aColumnAlias); } else { fillFunctionInfo(_pView,pColumnRef,aColumns,aInfo); aInfo->SetFieldAlias(aColumnAlias); } if ( SQL_ISRULE(pColumnRef,general_set_fct) ) { aInfo->SetFunctionType(nFunctionType|FKT_AGGREGATE); String aCol(aColumns); aInfo->SetFunction(aCol.GetToken(0,'(').EraseTrailingChars(' ')); } else aInfo->SetFunctionType(nFunctionType|FKT_OTHER); eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField); bFirstField = sal_False; } else //if(SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term)) { ::rtl::OUString aColumns; pColumnRef->parseNodeToStr( aColumns, xConnection, &rController.getParser().getContext(), sal_True, sal_True); // quote is to true because we need quoted elements inside the function aInfo->SetTabWindow( NULL ); // since we support queries in queries, the thingie might belong to an existing "table" OQueryTableWindow* pExistingTable = lcl_findColumnInTables( aColumns, *pTabList, aInfo ); if ( pExistingTable ) { aInfo->SetTabWindow( pExistingTable ); aInfo->SetTable( pExistingTable->GetTableName() ); aInfo->SetAlias( pExistingTable->GetAliasName() ); } aInfo->SetDataType(DataType::DOUBLE); aInfo->SetFieldType(TAB_NORMAL_FIELD); aInfo->SetField(aColumns); aInfo->SetFieldAlias(aColumnAlias); aInfo->SetFunctionType(FKT_NUMERIC | FKT_OTHER); eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField); bFirstField = sal_False; } break; } DBG_ERROR( "InstallFields: don't know how to interpret this parse node!" ); } while ( false ); } } else eErrorCode = eStatementTooComplex; return eErrorCode; } //------------------------------------------------------------------------------ SqlParseError GetOrderCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode* pParseRoot ) { SqlParseError eErrorCode = eOk; if (!pParseRoot->getChild(3)->getChild(4)->isLeaf()) { ::connectivity::OSQLParseNode* pNode = pParseRoot->getChild(3)->getChild(4)->getChild(2); ::connectivity::OSQLParseNode* pParamRef = NULL; OQueryController& rController = static_cast(_pView->getController()); EOrderDir eOrderDir; OTableFieldDescRef aDragLeft = new OTableFieldDesc(); for( sal_uInt32 i=0 ; icount() ; i++ ) { eOrderDir = ORDER_ASC; ::connectivity::OSQLParseNode* pChild = pNode->getChild( i ); if (SQL_ISTOKEN( pChild->getChild(1), DESC ) ) eOrderDir = ORDER_DESC; ::connectivity::OSQLParseNode* pArgument = pChild->getChild(0); if(SQL_ISRULE(pArgument,column_ref)) { if( eOk == FillDragInfo(_pView,pArgument,aDragLeft)) _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i); else // it could be a alias name for a field { ::rtl::OUString aTableRange,aColumnName; ::connectivity::OSQLParseTreeIterator& rParseIter = rController.getParseIterator(); rParseIter.getColumnRange( pArgument, aColumnName, aTableRange ); OTableFields& aList = rController.getTableFieldDesc(); OTableFields::iterator aIter = aList.begin(); OTableFields::iterator aEnd = aList.end(); for(;aIter != aEnd;++aIter) { OTableFieldDescRef pEntry = *aIter; if(pEntry.isValid() && pEntry->GetFieldAlias() == aColumnName) pEntry->SetOrderDir( eOrderDir ); } } } else if(SQL_ISRULE(pArgument, general_set_fct ) && SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) && eOk == FillDragInfo(_pView,pParamRef,aDragLeft)) _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i ); else if( SQL_ISRULE(pArgument, set_fct_spec ) ) { Reference< XConnection> xConnection = rController.getConnection(); if(xConnection.is()) { ::rtl::OUString sCondition; pArgument->parseNodeToPredicateStr(sCondition, xConnection, rController.getNumberFormatter(), _pView->getLocale(), static_cast(_pView->getDecimalSeparator().toChar()), &rController.getParser().getContext()); fillFunctionInfo(_pView,pArgument,sCondition,aDragLeft); aDragLeft->SetFunctionType(FKT_OTHER); aDragLeft->SetOrderDir(eOrderDir); aDragLeft->SetVisible(sal_False); _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i ); } else eErrorCode = eColumnNotFound; } else eErrorCode = eColumnNotFound; } } return eErrorCode; } //------------------------------------------------------------------------------ SqlParseError GetHavingCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode* pSelectRoot, sal_uInt16& rLevel ) { SqlParseError eErrorCode = eOk; if (!pSelectRoot->getChild(3)->getChild(3)->isLeaf()) eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSelectRoot->getChild(3)->getChild(3)->getChild(1),rLevel, sal_True); return eErrorCode; } //------------------------------------------------------------------------------ SqlParseError GetGroupCriteria( OQueryDesignView* _pView, OSelectionBrowseBox* _pSelectionBrw, const ::connectivity::OSQLParseNode* pSelectRoot ) { SqlParseError eErrorCode = eOk; if (!pSelectRoot->getChild(3)->getChild(2)->isLeaf()) { OQueryController& rController = static_cast(_pView->getController()); ::connectivity::OSQLParseNode* pGroupBy = pSelectRoot->getChild(3)->getChild(2)->getChild(2); OTableFieldDescRef aDragInfo = new OTableFieldDesc(); for( sal_uInt32 i=0 ; i < pGroupBy->count() && eOk == eErrorCode; ++i ) { ::connectivity::OSQLParseNode* pParamRef = NULL; ::connectivity::OSQLParseNode* pArgument = pGroupBy->getChild( i ); if(SQL_ISRULE(pArgument,column_ref)) { if ( eOk == (eErrorCode = FillDragInfo(_pView,pArgument,aDragInfo)) ) { aDragInfo->SetGroupBy(sal_True); _pSelectionBrw->AddGroupBy(aDragInfo,i); } } else if(SQL_ISRULE(pArgument, general_set_fct ) && SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) && eOk == FillDragInfo(_pView,pParamRef,aDragInfo)) { aDragInfo->SetGroupBy(sal_True); _pSelectionBrw->AddGroupBy( aDragInfo, i ); } else if( SQL_ISRULE(pArgument, set_fct_spec ) ) { Reference< XConnection> xConnection = rController.getConnection(); if(xConnection.is()) { ::rtl::OUString sGroupByExpression; pArgument->parseNodeToStr( sGroupByExpression, xConnection, &rController.getParser().getContext(), sal_True, sal_True); // quote is to true because we need quoted elements inside the function fillFunctionInfo(_pView,pArgument,sGroupByExpression,aDragInfo); aDragInfo->SetFunctionType(FKT_OTHER); aDragInfo->SetGroupBy(sal_True); aDragInfo->SetVisible(sal_False); _pSelectionBrw->AddGroupBy( aDragInfo, i ); } else eErrorCode = eColumnNotFound; } } } return eErrorCode; } //------------------------------------------------------------------------------ String getParseErrorMessage( SqlParseError _eErrorCode ) { USHORT nResId; switch(_eErrorCode) { case eIllegalJoin: nResId = STR_QRY_ILLEGAL_JOIN; break; case eStatementTooLong: nResId = STR_QRY_TOO_LONG_STATEMENT; break; case eNoConnection: nResId = STR_QRY_SYNTAX; break; case eNoSelectStatement: nResId = STR_QRY_NOSELECT; break; case eColumnInLikeNotFound: nResId = STR_QRY_SYNTAX; break; case eNoColumnInLike: nResId = STR_QRY_SYNTAX; break; case eColumnNotFound: nResId = STR_QRY_SYNTAX; break; case eNativeMode: nResId = STR_QRY_NATIVE; break; case eTooManyTables: nResId = STR_QRY_TOO_MANY_TABLES; break; case eTooManyConditions: nResId = STR_QRY_TOOMANYCOND; break; case eTooManyColumns: nResId = STR_QRY_TOO_MANY_COLUMNS; break; case eStatementTooComplex: nResId = STR_QRY_TOOCOMPLEX; break; default: nResId = STR_QRY_SYNTAX; break; } ; return String( ModuleRes( nResId ) ); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ } // end of anonymouse namespace DBG_NAME(OQueryDesignView) OQueryDesignView::OQueryDesignView( OQueryContainerWindow* _pParent, OQueryController& _rController, const Reference< XMultiServiceFactory >& _rFactory) :OQueryView( _pParent, _rController, _rFactory ) ,m_aSplitter( this ) ,m_eChildFocus(NONE) ,m_bInKeyEvent(sal_False) ,m_bInSplitHandler( sal_False ) { DBG_CTOR(OQueryDesignView,NULL); try { SvtSysLocale aSysLocale; m_aLocale = aSysLocale.GetLocaleData().getLocale(); m_sDecimalSep = aSysLocale.GetLocaleData().getNumDecimalSep(); } catch(Exception&) { } m_pSelectionBox = new OSelectionBrowseBox(this); setNoneVisbleRow(static_cast(getController()).getVisibleRows()); m_pSelectionBox->Show(); // Splitter einrichten m_aSplitter.SetSplitHdl(LINK(this, OQueryDesignView,SplitHdl)); m_aSplitter.Show(); } // ----------------------------------------------------------------------------- OQueryDesignView::~OQueryDesignView() { if ( m_pTableView ) ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); ::std::auto_ptr aTemp(m_pSelectionBox); m_pSelectionBox = NULL; DBG_DTOR(OQueryDesignView,NULL); } //------------------------------------------------------------------------------ IMPL_LINK( OQueryDesignView, SplitHdl, void*, /*p*/ ) { if (!getController().isReadOnly()) { m_bInSplitHandler = sal_True; m_aSplitter.SetPosPixel( Point( m_aSplitter.GetPosPixel().X(),m_aSplitter.GetSplitPosPixel() ) ); static_cast(getController()).setSplitPos(m_aSplitter.GetSplitPosPixel()); static_cast(getController()).setModified(); Resize(); m_bInSplitHandler = sal_True; } return 0L; } // ------------------------------------------------------------------------- void OQueryDesignView::Construct() { m_pTableView = new OQueryTableView(m_pScrollWindow,this); ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow)); OQueryView::Construct(); } // ----------------------------------------------------------------------------- void OQueryDesignView::initialize() { if(static_cast(getController()).getSplitPos() != -1) { m_aSplitter.SetPosPixel( Point( m_aSplitter.GetPosPixel().X(),static_cast(getController()).getSplitPos() ) ); m_aSplitter.SetSplitPosPixel(static_cast(getController()).getSplitPos()); } m_pSelectionBox->initialize(); reset(); } // ------------------------------------------------------------------------- void OQueryDesignView::resizeDocumentView(Rectangle& _rPlayground) { Point aPlaygroundPos( _rPlayground.TopLeft() ); Size aPlaygroundSize( _rPlayground.GetSize() ); // calc the split pos, and forward it to the controller sal_Int32 nSplitPos = static_cast(getController()).getSplitPos(); if ( 0 != aPlaygroundSize.Height() ) { if ( ( -1 == nSplitPos ) || ( nSplitPos >= aPlaygroundSize.Height() ) ) { // let the selection browse box determine an optimal size Size aSelectionBoxSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize ); nSplitPos = aPlaygroundSize.Height() - aSelectionBoxSize.Height() - m_aSplitter.GetSizePixel().Height(); // still an invalid size? if ( nSplitPos == -1 || nSplitPos >= aPlaygroundSize.Height() ) nSplitPos = sal_Int32(aPlaygroundSize.Height()*0.6); static_cast(getController()).setSplitPos(nSplitPos); } if ( !m_bInSplitHandler ) { // the resize is triggered by something else than the split handler // our main focus is to try to preserve the size of the selectionbrowse box Size aSelBoxSize = m_pSelectionBox->GetSizePixel(); if ( aSelBoxSize.Height() ) { // keep the size of the sel box constant nSplitPos = aPlaygroundSize.Height() - m_aSplitter.GetSizePixel().Height() - aSelBoxSize.Height(); // and if the box is smaller than the optimal size, try to do something about it Size aSelBoxOptSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize ); if ( aSelBoxOptSize.Height() > aSelBoxSize.Height() ) { nSplitPos = aPlaygroundSize.Height() - m_aSplitter.GetSizePixel().Height() - aSelBoxOptSize.Height(); } static_cast< OQueryController& >(getController()).setSplitPos( nSplitPos ); } } } // normalize the split pos Point aSplitPos = Point( _rPlayground.Left(), nSplitPos ); Size aSplitSize = Size( _rPlayground.GetSize().Width(), m_aSplitter.GetSizePixel().Height() ); if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() )) aSplitPos.Y() = aPlaygroundSize.Height() - aSplitSize.Height(); if( aSplitPos.Y() <= aPlaygroundPos.Y() ) aSplitPos.Y() = aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.2); // position the table Size aTableViewSize(aPlaygroundSize.Width(), aSplitPos.Y() - aPlaygroundPos.Y()); m_pScrollWindow->SetPosSizePixel(aPlaygroundPos, aTableViewSize); // position the selection browse box Point aPos( aPlaygroundPos.X(), aSplitPos.Y() + aSplitSize.Height() ); m_pSelectionBox->SetPosSizePixel( aPos, Size( aPlaygroundSize.Width(), aPlaygroundSize.Height() - aSplitSize.Height() - aTableViewSize.Height() )); // set the size of the splitter m_aSplitter.SetPosSizePixel( aSplitPos, aSplitSize ); m_aSplitter.SetDragRectPixel( _rPlayground ); // just for completeness: there is no space left, we occupied it all ... _rPlayground.SetPos( _rPlayground.BottomRight() ); _rPlayground.SetSize( Size( 0, 0 ) ); } // ----------------------------------------------------------------------------- void OQueryDesignView::setReadOnly(sal_Bool _bReadOnly) { m_pSelectionBox->SetReadOnly(_bReadOnly); } // ----------------------------------------------------------------------------- void OQueryDesignView::clear() { m_pSelectionBox->ClearAll(); // clear the whole selection m_pTableView->ClearAll(); } // ----------------------------------------------------------------------------- void OQueryDesignView::setStatement(const ::rtl::OUString& /*_rsStatement*/) { } // ----------------------------------------------------------------------------- void OQueryDesignView::copy() { if( m_eChildFocus == SELECTION) m_pSelectionBox->copy(); } // ----------------------------------------------------------------------------- sal_Bool OQueryDesignView::isCutAllowed() { sal_Bool bAllowed = sal_False; if ( SELECTION == m_eChildFocus ) bAllowed = m_pSelectionBox->isCutAllowed(); return bAllowed; } // ----------------------------------------------------------------------------- sal_Bool OQueryDesignView::isPasteAllowed() { sal_Bool bAllowed = sal_False; if ( SELECTION == m_eChildFocus ) bAllowed = m_pSelectionBox->isPasteAllowed(); return bAllowed; } // ----------------------------------------------------------------------------- sal_Bool OQueryDesignView::isCopyAllowed() { sal_Bool bAllowed = sal_False; if ( SELECTION == m_eChildFocus ) bAllowed = m_pSelectionBox->isCopyAllowed(); return bAllowed; } // ----------------------------------------------------------------------------- void OQueryDesignView::stopTimer() { m_pSelectionBox->stopTimer(); } // ----------------------------------------------------------------------------- void OQueryDesignView::startTimer() { m_pSelectionBox->startTimer(); } // ----------------------------------------------------------------------------- void OQueryDesignView::cut() { if( m_eChildFocus == SELECTION) { m_pSelectionBox->cut(); static_cast(getController()).setModified(sal_True); } } // ----------------------------------------------------------------------------- void OQueryDesignView::paste() { if( m_eChildFocus == SELECTION) { m_pSelectionBox->paste(); static_cast(getController()).setModified(sal_True); } } // ----------------------------------------------------------------------------- void OQueryDesignView::TableDeleted(const ::rtl::OUString& rAliasName) { // Nachricht, dass Tabelle aus dem Fenster gel"oscht wurde DeleteFields(rAliasName); static_cast(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE); // view nochmal bescheid sagen } //------------------------------------------------------------------------------ void OQueryDesignView::DeleteFields( const ::rtl::OUString& rAliasName ) { m_pSelectionBox->DeleteFields( rAliasName ); } // ----------------------------------------------------------------------------- bool OQueryDesignView::HasFieldByAliasName(const ::rtl::OUString& rFieldName, OTableFieldDescRef& rInfo) const { return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo); } // ----------------------------------------------------------------------------- SqlParseError OQueryDesignView::InsertField( const OTableFieldDescRef& rInfo, sal_Bool bVis, sal_Bool bActivate) { return m_pSelectionBox->InsertField( rInfo, BROWSER_INVALIDID,bVis, bActivate ).isValid() ? eOk : eTooManyColumns; } // ----------------------------------------------------------------------------- sal_Int32 OQueryDesignView::getColWidth(sal_uInt16 _nColPos) const { static sal_Int32 s_nDefaultWidth = GetTextWidth(String(RTL_CONSTASCII_USTRINGPARAM("0"))) * 15; sal_Int32 nWidth = static_cast(getController()).getColWidth(_nColPos); if ( !nWidth ) nWidth = s_nDefaultWidth; return nWidth; } //------------------------------------------------------------------------------ void OQueryDesignView::fillValidFields(const ::rtl::OUString& sAliasName, ComboBox* pFieldList) { DBG_ASSERT(pFieldList != NULL, "OQueryDesignView::FillValidFields : What the hell do you think I can do with a NULL-ptr ? This will crash !"); pFieldList->Clear(); sal_Bool bAllTables = sAliasName.getLength() == 0; OJoinTableView::OTableWindowMap* pTabWins = m_pTableView->GetTabWinMap(); ::rtl::OUString strCurrentPrefix; ::std::vector< ::rtl::OUString> aFields; OJoinTableView::OTableWindowMap::iterator aIter = pTabWins->begin(); OJoinTableView::OTableWindowMap::iterator aEnd = pTabWins->end(); for(;aIter != aEnd;++aIter) { OQueryTableWindow* pCurrentWin = static_cast(aIter->second); if (bAllTables || (pCurrentWin->GetAliasName() == sAliasName)) { strCurrentPrefix = pCurrentWin->GetAliasName(); strCurrentPrefix += ::rtl::OUString('.'); pCurrentWin->EnumValidFields(aFields); ::std::vector< ::rtl::OUString>::iterator aStrIter = aFields.begin(); ::std::vector< ::rtl::OUString>::iterator aStrEnd = aFields.end(); for(;aStrIter != aStrEnd;++aStrIter) { if (bAllTables || aStrIter->toChar() == '*') pFieldList->InsertEntry(::rtl::OUString(strCurrentPrefix) += *aStrIter); else pFieldList->InsertEntry(*aStrIter); } if (!bAllTables) // das heisst, dass ich in diesen Block kam, weil der Tabellenname genau der gesuchte war, also bin ich fertig // (dadurch verhindere ich auch das doppelte Einfuegen von Feldern, wenn eine Tabelle mehrmals als TabWin vorkommt) break; } } } // ----------------------------------------------------------------------------- long OQueryDesignView::PreNotify(NotifyEvent& rNEvt) { switch (rNEvt.GetType()) { case EVENT_GETFOCUS: #if OSL_DEBUG_LEVEL > 0 { Window* pFocus = Application::GetFocusWindow(); (void)pFocus; } #endif if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() ) m_eChildFocus = SELECTION; else m_eChildFocus = TABLEVIEW; break; } return OQueryView::PreNotify(rNEvt); } //------------------------------------------------------------------------------ // ----------------------------------------------------------------------------- // check if the statement is correct when not returning false sal_Bool OQueryDesignView::checkStatement() { sal_Bool bRet = sal_True; if ( m_pSelectionBox ) bRet = m_pSelectionBox->Save(); // a error occured so we return no return bRet; } //------------------------------------------------------------------------------- ::rtl::OUString OQueryDesignView::getStatement() { OQueryController& rController = static_cast(getController()); m_rController.clearError(); // used for fields which aren't any longer in the statement OTableFields& rUnUsedFields = rController.getUnUsedFields(); OTableFields().swap( rUnUsedFields ); // create the select columns sal_uInt32 nFieldcount = 0; OTableFields& rFieldList = rController.getTableFieldDesc(); OTableFields::iterator aIter = rFieldList.begin(); OTableFields::iterator aEnd = rFieldList.end(); for(;aIter != aEnd;++aIter) { OTableFieldDescRef pEntryField = *aIter; if ( pEntryField->GetField().getLength() && pEntryField->IsVisible() ) ++nFieldcount; else if (pEntryField->GetField().getLength() && !pEntryField->HasCriteria() && pEntryField->isNoneFunction() && pEntryField->GetOrderDir() == ORDER_NONE && !pEntryField->IsGroupBy() && !pEntryField->GetFunction().getLength() ) rUnUsedFields.push_back(pEntryField); } if ( !nFieldcount ) // keine Felder sichtbar also zur"uck { rUnUsedFields = rFieldList; return ::rtl::OUString(); } OQueryTableView::OTableWindowMap* pTabList = m_pTableView->GetTabWinMap(); sal_uInt32 nTabcount = pTabList->size(); ::rtl::OUString aFieldListStr(GenerateSelectList(this,rFieldList,nTabcount>1)); if( !aFieldListStr.getLength() ) return ::rtl::OUString(); // Ausnahmebehandlung, wenn keine Felder angegeben worden sind // Dann darf die Tabpage nicht gewechselt werden // Im TabBarSelectHdl wird der SQL-::rtl::OUString auf STATEMENT_NOFIELDS abgefragt // und eine Errormeldung erzeugt // ----------------- Tabellenliste aufbauen ---------------------- const ::std::vector* pConnList = m_pTableView->getTableConnections(); Reference< XConnection> xConnection = rController.getConnection(); ::rtl::OUString aTableListStr(GenerateFromClause(xConnection,pTabList,pConnList)); DBG_ASSERT(aTableListStr.getLength(), "OQueryDesignView::getStatement() : unerwartet : habe Felder, aber keine Tabellen !"); // wenn es Felder gibt, koennen die nur durch Einfuegen aus einer schon existenten Tabelle entstanden sein; wenn andererseits // eine Tabelle geloescht wird, verschwinden auch die zugehoerigen Felder -> ergo KANN es das nicht geben, dass Felder // existieren, aber keine Tabellen (und aFieldListStr hat schon eine Laenge, das stelle ich oben sicher) ::rtl::OUStringBuffer aHavingStr,aCriteriaListStr; // ----------------- Kriterien aufbauen ---------------------- if (!GenerateCriterias(this,aCriteriaListStr,aHavingStr,rFieldList, nTabcount > 1)) return ::rtl::OUString(); ::rtl::OUString aJoinCrit; GenerateInnerJoinCriterias(xConnection,aJoinCrit,pConnList); if(aJoinCrit.getLength()) { ::rtl::OUString aTmp = ::rtl::OUString::createFromAscii("( "); aTmp += aJoinCrit; aTmp += ::rtl::OUString::createFromAscii(" )"); if(aCriteriaListStr.getLength()) { aTmp += C_AND; aTmp += aCriteriaListStr.makeStringAndClear(); } aCriteriaListStr = aTmp; } // ----------------- Statement aufbauen ---------------------- ::rtl::OUStringBuffer aSqlCmd(::rtl::OUString::createFromAscii("SELECT ")); if(static_cast(getController()).isDistinct()) aSqlCmd.append(::rtl::OUString::createFromAscii(" DISTINCT ")); aSqlCmd.append(aFieldListStr); aSqlCmd.append(::rtl::OUString::createFromAscii(" FROM ")); aSqlCmd.append(aTableListStr); if (aCriteriaListStr.getLength()) { aSqlCmd.append(::rtl::OUString::createFromAscii(" WHERE ")); aSqlCmd.append(aCriteriaListStr.makeStringAndClear()); } // ----------------- GroupBy aufbauen und Anh"angen ------------ Reference xMeta; if ( xConnection.is() ) xMeta = xConnection->getMetaData(); sal_Bool bUseAlias = nTabcount > 1; if ( xMeta.is() ) bUseAlias = bUseAlias || !xMeta->supportsGroupByUnrelated(); aSqlCmd.append(GenerateGroupBy(this,rFieldList,bUseAlias)); // ----------------- having Anh"angen ------------ if(aHavingStr.getLength()) { aSqlCmd.append(::rtl::OUString::createFromAscii(" HAVING ")); aSqlCmd.append(aHavingStr.makeStringAndClear()); } // ----------------- Sortierung aufbauen und Anh"angen ------------ ::rtl::OUString sOrder; SqlParseError eErrorCode = eOk; if ( (eErrorCode = GenerateOrder(this,rFieldList,nTabcount > 1,sOrder)) == eOk) aSqlCmd.append(sOrder); else { if ( !m_rController.hasError() ) m_rController.appendError( getParseErrorMessage( eErrorCode ) ); m_rController.displayError(); } ::rtl::OUString sSQL = aSqlCmd.makeStringAndClear(); if ( xConnection.is() ) { ::connectivity::OSQLParser& rParser( rController.getParser() ); ::rtl::OUString sErrorMessage; ::std::auto_ptr pParseNode( rParser.parseTree( sErrorMessage, sSQL, sal_True ) ); if ( pParseNode.get() ) { OSQLParseNode* pNode = pParseNode->getChild(3)->getChild(1); if ( pNode->count() > 1 ) { ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1); if ( pCondition ) // no where clause { OSQLParseNode::compress(pCondition); ::rtl::OUString sTemp; pParseNode->parseNodeToStr(sTemp,xConnection); sSQL = sTemp; } } } } return sSQL; } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId,sal_Bool _bEnable) { sal_uInt16 nRow; switch (_nSlotId) { case SID_QUERY_VIEW_FUNCTIONS: nRow = BROW_FUNCTION_ROW; break; case SID_QUERY_VIEW_TABLES: nRow = BROW_TABLE_ROW; break; case SID_QUERY_VIEW_ALIASES: nRow = BROW_COLUMNALIAS_ROW; break; default: // ???????????? nRow = 0; break; } m_pSelectionBox->SetRowVisible(nRow,_bEnable); m_pSelectionBox->Invalidate(); } // ----------------------------------------------------------------------------- sal_Bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId) { sal_uInt16 nRow; switch (_nSlotId) { case SID_QUERY_VIEW_FUNCTIONS: nRow = BROW_FUNCTION_ROW; break; case SID_QUERY_VIEW_TABLES: nRow = BROW_TABLE_ROW; break; case SID_QUERY_VIEW_ALIASES: nRow = BROW_COLUMNALIAS_ROW; break; default: // ????????? nRow = 0; break; } return m_pSelectionBox->IsRowVisible(nRow); } // ----------------------------------------------------------------------------- void OQueryDesignView::SaveUIConfig() { OQueryController& rCtrl = static_cast(getController()); rCtrl.SaveTabWinsPosSize( m_pTableView->GetTabWinMap(), m_pScrollWindow->GetHScrollBar()->GetThumbPos(), m_pScrollWindow->GetVScrollBar()->GetThumbPos() ); // rCtrl.SaveTabFieldsWidth( m_pSelectionBox ); rCtrl.setVisibleRows( m_pSelectionBox->GetNoneVisibleRows() ); if ( m_aSplitter.GetSplitPosPixel() != 0 ) rCtrl.setSplitPos( m_aSplitter.GetSplitPosPixel() ); } // ----------------------------------------------------------------------------- OSQLParseNode* OQueryDesignView::getPredicateTreeFromEntry(OTableFieldDescRef pEntry, const String& _sCriteria, ::rtl::OUString& _rsErrorMessage, Reference& _rxColumn) const { OSL_ENSURE(pEntry.isValid(),"Entry is null!"); if(!pEntry.isValid()) return NULL; Reference< XConnection> xConnection = static_cast(getController()).getConnection(); if(!xConnection.is()) return NULL; ::connectivity::OSQLParser& rParser( static_cast(getController()).getParser() ); OQueryTableWindow* pWin = static_cast(pEntry->GetTabWindow()); String sTest(_sCriteria); // special handling for functions if ( pEntry->GetFunctionType() & (FKT_OTHER | FKT_AGGREGATE | FKT_NUMERIC) ) { // we have a function here so we have to distinguish the type of return value String sFunction; if ( pEntry->isNumericOrAggreateFunction() ) sFunction = pEntry->GetFunction(); if ( !sFunction.Len() ) sFunction = pEntry->GetField(); if(sFunction.GetTokenCount('(') > 1) sFunction = sFunction.GetToken(0,'('); // this should be the name of the function sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sFunction,&rParser.getContext()); if ( nType == DataType::OTHER || (!sFunction.Len() && pEntry->isNumericOrAggreateFunction()) ) { // first try the international version ::rtl::OUString sSql; sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SELECT * ")); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" FROM x WHERE ")); sSql += pEntry->GetField(); sSql += _sCriteria; ::std::auto_ptr pParseNode( rParser.parseTree( _rsErrorMessage, sSql, sal_True ) ); nType = DataType::DOUBLE; if ( pParseNode.get() ) { OSQLParseNode* pColumnRef = pParseNode->getByRule(OSQLParseNode::column_ref); if ( pColumnRef ) { OTableFieldDescRef aField = new OTableFieldDesc(); if ( eOk == FillDragInfo(this,pColumnRef,aField) ) { nType = aField->GetDataType(); } } } } Reference xMeta = xConnection->getMetaData(); parse::OParseColumn* pColumn = new parse::OParseColumn( pEntry->GetField(), ::rtl::OUString(), ::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN, 0, 0, nType, sal_False, sal_False, xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); _rxColumn = pColumn; pColumn->setFunction(sal_True); pColumn->setRealName(pEntry->GetField()); } else { if (pWin) { Reference xColumns = pWin->GetOriginalColumns(); if (xColumns.is() && xColumns->hasByName(pEntry->GetField())) xColumns->getByName(pEntry->GetField()) >>= _rxColumn; } } OSQLParseNode* pParseNode = rParser.predicateTree( _rsErrorMessage, sTest, static_cast(getController()).getNumberFormatter(), _rxColumn); return pParseNode; } // ----------------------------------------------------------------------------- void OQueryDesignView::GetFocus() { OQueryView::GetFocus(); if ( m_pSelectionBox && !m_pSelectionBox->HasChildPathFocus() ) { // first we have to deactivate the current cell to refill when nescessary m_pSelectionBox->DeactivateCell(); m_pSelectionBox->ActivateCell(m_pSelectionBox->GetCurRow(), m_pSelectionBox->GetCurColumnId()); m_pSelectionBox->GrabFocus(); } } // ----------------------------------------------------------------------------- void OQueryDesignView::reset() { m_pTableView->ClearAll(); m_pTableView->ReSync(); } // ----------------------------------------------------------------------------- void OQueryDesignView::setNoneVisbleRow(sal_Int32 _nRows) { m_pSelectionBox->SetNoneVisbleRow(_nRows); } // ----------------------------------------------------------------------------- bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo ) { SqlParseError eErrorCode = eNativeMode; m_rController.clearError(); try { eErrorCode = InitFromParseNodeImpl( this, m_pSelectionBox ); if ( eErrorCode != eOk ) { if ( !m_rController.hasError() ) m_rController.appendError( getParseErrorMessage( eErrorCode ) ); if ( _pErrorInfo ) { *_pErrorInfo = m_rController.getError(); } else { m_rController.displayError(); } } } catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } return eErrorCode == eOk; } // -----------------------------------------------------------------------------