/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_connectivity.hxx" #include "connectivity/sqliterator.hxx" #include "connectivity/sdbcx/VTable.hxx" #include #include #include #include #include #include #include #include #ifdef SQL_TEST_PARSETREEITERATOR #include #endif #include "connectivity/PColumn.hxx" #include "connectivity/dbtools.hxx" #include #include "TConnection.hxx" #include #include #include #include "diagnose_ex.h" #include #define SQL_ISRULEOR2(pParseNode, e1,e2) ((pParseNode)->isRule() && (\ (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e1) || \ (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e2))) using namespace ::comphelper; using namespace ::connectivity; using namespace ::connectivity::sdbcx; using namespace ::dbtools; using namespace ::connectivity::parse; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::container; using namespace ::com::sun::star::sdbcx; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::sdb; namespace connectivity { struct OSQLParseTreeIteratorImpl { ::std::vector< TNodePair > m_aJoinConditions; Reference< XConnection > m_xConnection; Reference< XDatabaseMetaData > m_xDatabaseMetaData; Reference< XNameAccess > m_xTableContainer; Reference< XNameAccess > m_xQueryContainer; ::boost::shared_ptr< OSQLTables > m_pTables; /// all tables which participate in the SQL statement ::boost::shared_ptr< OSQLTables > m_pSubTables; /// all tables from sub queries not the tables from the select tables ::boost::shared_ptr< QueryNameSet > m_pForbiddenQueryNames; sal_uInt32 m_nIncludeMask; bool m_bIsCaseSensitive; OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables ) :m_xConnection( _rxConnection ) ,m_nIncludeMask( OSQLParseTreeIterator::All ) ,m_bIsCaseSensitive( true ) { OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" ); m_xDatabaseMetaData = m_xConnection->getMetaData(); m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers(); m_pTables.reset( new OSQLTables( m_bIsCaseSensitive ) ); m_pSubTables.reset( new OSQLTables( m_bIsCaseSensitive ) ); m_xTableContainer = _rxTables; DatabaseMetaData aMetaData( m_xConnection ); if ( aMetaData.supportsSubqueriesInFrom() ) { // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection // service Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY ); if ( xSuppQueries.is() ) m_xQueryContainer = xSuppQueries->getQueries(); } } public: inline bool isQueryAllowed( const ::rtl::OUString& _rQueryName ) { if ( !m_pForbiddenQueryNames.get() ) return true; if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() ) return true; return false; } }; //------------------------------------------------------------------------- /** helper class for temporarily adding a query name to a list of forbidden query names */ class ForbidQueryName { ::boost::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames; ::rtl::OUString m_sForbiddenQueryName; public: ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, const ::rtl::OUString _rForbiddenQueryName ) :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames ) ,m_sForbiddenQueryName( _rForbiddenQueryName ) { if ( !m_rpAllForbiddenNames.get() ) m_rpAllForbiddenNames.reset( new QueryNameSet ); m_rpAllForbiddenNames->insert( m_sForbiddenQueryName ); } ~ForbidQueryName() { m_rpAllForbiddenNames->erase( m_sForbiddenQueryName ); } }; } //----------------------------------------------------------------------------- OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables, const OSQLParser& _rParser, const OSQLParseNode* pRoot ) :m_rParser( _rParser ) ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection, _rxTables ) ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::OSQLParseTreeIterator" ); setParseTree(pRoot); } //----------------------------------------------------------------------------- OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator& _rParentIterator, const OSQLParser& _rParser, const OSQLParseNode* pRoot ) :m_rParser( _rParser ) ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator.m_pImpl->m_xConnection, _rParentIterator.m_pImpl->m_xTableContainer ) ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::OSQLParseTreeIterator" ); m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames; setParseTree( pRoot ); } //----------------------------------------------------------------------------- OSQLParseTreeIterator::~OSQLParseTreeIterator() { dispose(); } // ----------------------------------------------------------------------------- const OSQLTables& OSQLParseTreeIterator::getTables() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getTables" ); return *m_pImpl->m_pTables; } // ----------------------------------------------------------------------------- bool OSQLParseTreeIterator::isCaseSensitive() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::isCaseSensitive" ); return m_pImpl->m_bIsCaseSensitive; } // ----------------------------------------------------------------------------- void OSQLParseTreeIterator::dispose() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::dispose" ); m_aSelectColumns = NULL; m_aGroupColumns = NULL; m_aOrderColumns = NULL; m_aParameters = NULL; m_pImpl->m_xTableContainer = NULL; m_pImpl->m_xDatabaseMetaData = NULL; m_aCreateColumns = NULL; m_pImpl->m_pTables->clear(); m_pImpl->m_pSubTables->clear(); } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::setParseTree(const OSQLParseNode * pNewParseTree) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::setParseTree" ); m_pImpl->m_pTables->clear(); m_pImpl->m_pSubTables->clear(); m_aSelectColumns = new OSQLColumns(); m_aGroupColumns = new OSQLColumns(); m_aOrderColumns = new OSQLColumns(); m_aParameters = new OSQLColumns(); m_aCreateColumns = new OSQLColumns(); m_pParseTree = pNewParseTree; if (!m_pParseTree) { m_eStatementType = SQL_STATEMENT_UNKNOWN; return; } // falls m_pParseTree aber keine Connection, dann Fehler if ( !m_pImpl->m_xTableContainer.is() ) return; m_aErrors = SQLException(); // Statement-Typ ermitteln ... if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) ) { m_eStatementType = SQL_STATEMENT_SELECT; } else if (SQL_ISRULE(m_pParseTree,insert_statement)) { m_eStatementType = SQL_STATEMENT_INSERT; } else if (SQL_ISRULE(m_pParseTree,update_statement_searched)) { m_eStatementType = SQL_STATEMENT_UPDATE; } else if (SQL_ISRULE(m_pParseTree,delete_statement_searched)) { m_eStatementType = SQL_STATEMENT_DELETE; } else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec)) { m_eStatementType = SQL_STATEMENT_ODBC_CALL; } else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def)) { m_eStatementType = SQL_STATEMENT_CREATE_TABLE; m_pParseTree = m_pParseTree->getChild(0); } else { m_eStatementType = SQL_STATEMENT_UNKNOWN; //aIteratorStatus.setInvalidStatement(); return; } } //----------------------------------------------------------------------------- namespace { //......................................................................... static void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, ::rtl::OUString& _out_rString ) { _out_rString = _rxRow->getString( _nColumnIndex ); if ( _rxRow->wasNull() ) _out_rString= ::rtl::OUString(); } //......................................................................... static ::rtl::OUString lcl_findTableInMetaData( const Reference< XDatabaseMetaData >& _rxDBMeta, const ::rtl::OUString& _rCatalog, const ::rtl::OUString& _rSchema, const ::rtl::OUString& _rTableName ) { ::rtl::OUString sComposedName; static const ::rtl::OUString s_sTableTypeView(RTL_CONSTASCII_USTRINGPARAM("VIEW")); static const ::rtl::OUString s_sTableTypeTable(RTL_CONSTASCII_USTRINGPARAM("TABLE")); static const ::rtl::OUString s_sWildcard = ::rtl::OUString::createFromAscii("%"); // we want all catalogues, all schemas, all tables Sequence< ::rtl::OUString > sTableTypes(3); sTableTypes[0] = s_sTableTypeView; sTableTypes[1] = s_sTableTypeTable; sTableTypes[2] = s_sWildcard; // just to be sure to include anything else .... if ( _rxDBMeta.is() ) { sComposedName = ::rtl::OUString(); Reference< XResultSet> xRes = _rxDBMeta->getTables( _rCatalog.getLength() ? makeAny( _rCatalog ) : Any(), _rSchema.getLength() ? _rSchema : s_sWildcard, _rTableName, sTableTypes ); Reference< XRow > xCurrentRow( xRes, UNO_QUERY ); if ( xCurrentRow.is() && xRes->next() ) { ::rtl::OUString sCatalog, sSchema, sName; impl_getRowString( xCurrentRow, 1, sCatalog ); impl_getRowString( xCurrentRow, 2, sSchema ); impl_getRowString( xCurrentRow, 3, sName ); sComposedName = ::dbtools::composeTableName( _rxDBMeta, sCatalog, sSchema, sName, sal_False, ::dbtools::eInDataManipulation ); } } return sComposedName; } } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable& _rQuery ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::impl_getQueryParameterColumns" ); if ( ( m_pImpl->m_nIncludeMask & Parameters ) != Parameters ) // parameters not to be included in the traversal return; ::vos::ORef< OSQLColumns > pSubQueryParameterColumns( new OSQLColumns() ); // get the command and the EscapeProcessing properties from the sub query ::rtl::OUString sSubQueryCommand; sal_Bool bEscapeProcessing = sal_False; try { Reference< XPropertySet > xQueryProperties( _rQuery, UNO_QUERY_THROW ); OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sSubQueryCommand ); OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing ); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } // parse the sub query do { if ( !bEscapeProcessing || ( sSubQueryCommand.getLength() == 0 ) ) break; ::rtl::OUString sError; ::std::auto_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand, sal_False ) ); if ( !pSubQueryNode.get() ) break; OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() ); aSubQueryIterator.traverseSome( Parameters | SelectColumns ); // SelectColumns might also contain parameters // #i77635# - 2007-07-23 / frank.schoenheit@sun.com pSubQueryParameterColumns = aSubQueryIterator.getParameters(); aSubQueryIterator.dispose(); } while ( false ); // copy the parameters of the sub query to our own parameter array ::std::copy( pSubQueryParameterColumns->get().begin(), pSubQueryParameterColumns->get().end(), ::std::insert_iterator< OSQLColumns::Vector >( m_aParameters->get(), m_aParameters->get().end() ) ); } //----------------------------------------------------------------------------- OSQLTable OSQLParseTreeIterator::impl_locateRecordSource( const ::rtl::OUString& _rComposedName ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::impl_locateRecordSource" ); if ( !_rComposedName.getLength() ) { OSL_ENSURE( false, "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" ); return OSQLTable(); } OSQLTable aReturn; ::rtl::OUString sComposedName( _rComposedName ); try { ::rtl::OUString sCatalog, sSchema, sName; qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::eInDataManipulation ); // check whether there is a query with the given name bool bQueryDoesExist = m_pImpl->m_xQueryContainer.is() && m_pImpl->m_xQueryContainer->hasByName( sComposedName ); // check whether the table container contains an object with the given name if ( !bQueryDoesExist && !m_pImpl->m_xTableContainer->hasByName( sComposedName ) ) sComposedName = lcl_findTableInMetaData( m_pImpl->m_xDatabaseMetaData, sCatalog, sSchema, sName ); bool bTableDoesExist = m_pImpl->m_xTableContainer->hasByName( sComposedName ); // now obtain the object // if we're creating a table, and there already is a table or query with the same name, // this is worth an error if ( SQL_STATEMENT_CREATE_TABLE == m_eStatementType ) { if ( bQueryDoesExist ) impl_appendError( IParseContext::ERROR_INVALID_QUERY_EXIST, &sName ); else if ( bTableDoesExist ) impl_appendError( IParseContext::ERROR_INVALID_TABLE_EXIST, &sName ); else aReturn = impl_createTableObject( sName, sCatalog, sSchema ); } else { // queries win over tables, so if there's a query with this name, take this, no matter if // there's a table, too if ( bQueryDoesExist ) { if ( !m_pImpl->isQueryAllowed( sComposedName ) ) { impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, NULL ) ); return NULL; } m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn; // collect the parameters from the sub query ForbidQueryName aForbidName( *m_pImpl, sComposedName ); impl_getQueryParameterColumns( aReturn ); } else if ( bTableDoesExist ) m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn; else { if ( m_pImpl->m_xQueryContainer.is() ) // the connection on which we're working supports sub queries in from (else // m_xQueryContainer would not have been set), so emit a better error message impl_appendError( IParseContext::ERROR_INVALID_TABLE_OR_QUERY, &sName ); else impl_appendError( IParseContext::ERROR_INVALID_TABLE, &sName ); } } } catch(Exception&) { impl_appendError( IParseContext::ERROR_INVALID_TABLE, &sComposedName ); } return aReturn; } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const ::rtl::OUString & rTableRange ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseOneTableName" ); if ( ( m_pImpl->m_nIncludeMask & TableNames ) != TableNames ) // tables should not be included in the traversal return; OSL_ENSURE(pTableName != NULL,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL"); Any aCatalog; ::rtl::OUString aSchema,aTableName,aComposedName; ::rtl::OUString aTableRange(rTableRange); // Tabellenname abholen OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData); // create the composed name like DOMAIN.USER.TABLE1 aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData, aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : ::rtl::OUString(), aSchema, aTableName, sal_False, ::dbtools::eInDataManipulation); // if there is no alias for the table name assign the orignal name to it if ( !aTableRange.getLength() ) aTableRange = aComposedName; // get the object representing this table/query OSQLTable aTable = impl_locateRecordSource( aComposedName ); if ( aTable.is() ) _rTables[ aTableRange ] = aTable; } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode* i_pJoinCondition) { if (i_pJoinCondition->count() == 3 && // Ausdruck is geklammert SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") && SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")")) { impl_fillJoinConditions(i_pJoinCondition->getChild(1)); } else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR-Verknuepfung: i_pJoinCondition->count() == 3) { // nur AND Verknüpfung zulassen if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) ) { impl_fillJoinConditions(i_pJoinCondition->getChild(0)); impl_fillJoinConditions(i_pJoinCondition->getChild(1)); } } else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate)) { // only the comparison of columns is allowed OSL_ENSURE(i_pJoinCondition->count() == 3,"OQueryDesignView::InsertJoinConnection: Fehler im Parse Tree"); if (SQL_ISRULE(i_pJoinCondition->getChild(0),column_ref) && SQL_ISRULE(i_pJoinCondition->getChild(2),column_ref) && i_pJoinCondition->getChild(1)->getNodeType() == SQL_NODE_EQUAL) { m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) ); } } } //----------------------------------------------------------------------------- ::std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const { return m_pImpl->m_aJoinConditions; } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, ::rtl::OUString& aTableRange ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getQualified_join" ); OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) , "OSQLParseTreeIterator::getQualified_join: illegal node!" ); aTableRange = ::rtl::OUString(); const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange); if ( isTableNode( pNode ) ) traverseOneTableName( _rTables, pNode, aTableRange ); sal_uInt32 nPos = 4; if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL) { nPos = 3; // join_condition,named_columns_join if ( SQL_ISRULE( pTableRef, qualified_join ) ) { const OSQLParseNode* pJoin_spec = pTableRef->getChild(4); if ( SQL_ISRULE( pJoin_spec, join_condition ) ) { impl_fillJoinConditions(pJoin_spec->getChild(1)); } else { const OSQLParseNode* pColumnCommalist = pJoin_spec->getChild(2); // Alle Columns in der column_commalist ... for (sal_uInt32 i = 0; i < pColumnCommalist->count(); i++) { const OSQLParseNode * pCol = pColumnCommalist->getChild(i); // add twice because the column must exists in both tables m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) ); } } } } pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange); if ( isTableNode( pNode ) ) traverseOneTableName( _rTables, pNode, aTableRange ); } //----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,::rtl::OUString& rTableRange ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getTableNode" ); OSL_PRECOND( SQL_ISRULE( pTableRef, table_ref ) || SQL_ISRULE( pTableRef, joined_table ) || SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ), "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" ); const OSQLParseNode* pTableNameNode = NULL; if ( SQL_ISRULE( pTableRef, joined_table ) ) { getQualified_join( _rTables, pTableRef->getChild(1), rTableRange ); } if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) ) { getQualified_join( _rTables, pTableRef, rTableRange ); } else { rTableRange = OSQLParseNode::getTableRange(pTableRef); if ( ( pTableRef->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}' || ( pTableRef->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist ) { getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange ); } else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')' { const OSQLParseNode* pSubQuery = pTableRef->getChild(0); if ( pSubQuery->isToken() ) { getQualified_join( _rTables, pTableRef->getChild(1), rTableRange ); } else { OSL_ENSURE( pSubQuery->count() == 3, "sub queries should have 3 children!" ); const OSQLParseNode* pQueryExpression = pSubQuery->getChild(1); if ( SQL_ISRULE( pQueryExpression, select_statement ) ) { getSelect_statement( *m_pImpl->m_pSubTables, pQueryExpression ); } else { OSL_ENSURE( false, "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" ); } } } else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column { pTableNameNode = pTableRef->getChild(0); } else OSL_ENSURE( false, "OSQLParseTreeIterator::getTableNode: unhandled case!" ); } return pTableNameNode; } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::getSelect_statement(OSQLTables& _rTables,const OSQLParseNode* pSelect) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getSelect_statement" ); if(SQL_ISRULE(pSelect,union_statement)) { getSelect_statement(_rTables,pSelect->getChild(0)); //getSelect_statement(pSelect->getChild(3)); return; } OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1); OSL_ENSURE(pTableRefCommalist != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!"); const OSQLParseNode* pTableName = NULL; ::rtl::OUString aTableRange; for (sal_uInt32 i = 0; i < pTableRefCommalist->count(); i++) { // from clause durchlaufen aTableRange = ::rtl::OUString(); const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i); if ( isTableNode( pTableListElement ) ) { traverseOneTableName( _rTables, pTableListElement, aTableRange ); } else if ( SQL_ISRULE( pTableListElement, table_ref ) ) { // Tabellenreferenz kann aus Tabellennamen, Tabellennamen (+),'('joined_table')'(+) bestehen pTableName = pTableListElement->getChild(0); if( isTableNode( pTableName ) ) { // Tabellennamen gefunden aTableRange = OSQLParseNode::getTableRange(pTableListElement); traverseOneTableName( _rTables, pTableName, aTableRange ); } else if(SQL_ISPUNCTUATION(pTableName,"{")) { // '{' SQL_TOKEN_OJ joined_table '}' getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange ); } else { // '(' joined_table ')' range_variable op_column_commalist getTableNode( _rTables, pTableListElement, aTableRange ); } } else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) ) { getQualified_join( _rTables, pTableListElement, aTableRange ); } else if ( SQL_ISRULE( pTableListElement, joined_table ) ) { getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange ); } // if (! aIteratorStatus.IsSuccessful()) break; } } //----------------------------------------------------------------------------- bool OSQLParseTreeIterator::traverseTableNames(OSQLTables& _rTables) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseTableNames" ); if ( m_pParseTree == NULL ) return false; OSQLParseNode* pTableName = NULL; switch ( m_eStatementType ) { case SQL_STATEMENT_SELECT: getSelect_statement( _rTables, m_pParseTree ); break; case SQL_STATEMENT_CREATE_TABLE: case SQL_STATEMENT_INSERT: case SQL_STATEMENT_DELETE: pTableName = m_pParseTree->getChild(2); break; case SQL_STATEMENT_UPDATE: pTableName = m_pParseTree->getChild(1); break; default: break; } if ( pTableName ) { ::rtl::OUString sTableRange; traverseOneTableName( _rTables, pTableName, sTableRange ); } return !hasErrors(); } //----------------------------------------------------------------------------- ::rtl::OUString OSQLParseTreeIterator::getColumnAlias(const OSQLParseNode* _pDerivedColumn) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getColumnAlias" ); OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!"); ::rtl::OUString sColumnAlias; if(_pDerivedColumn->getChild(1)->count() == 2) sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue(); else if(!_pDerivedColumn->getChild(1)->isRule()) sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue(); return sColumnAlias; } // ----------------------------------------------------------------------------- namespace { void lcl_getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection, ::rtl::OUString& _out_rColumnName, ::rtl::OUString& _out_rTableRange, const OSQLColumns* _pSelectColumns, ::rtl::OUString& _out_rColumnAliasIfPresent ) { _out_rColumnName = _out_rTableRange = _out_rColumnAliasIfPresent = ::rtl::OUString(); if ( SQL_ISRULE( _pColumnRef, column_ref ) ) { if( _pColumnRef->count() > 1 ) { for ( sal_Int32 i=0; i<((sal_Int32)_pColumnRef->count())-2; ++i ) _pColumnRef->getChild(i)->parseNodeToStr( _out_rTableRange, _rxConnection, NULL, sal_False, sal_False ); _out_rColumnName = _pColumnRef->getChild( _pColumnRef->count()-1 )->getChild(0)->getTokenValue(); } else _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue(); // look up the column in the select column, to find an possible alias if ( _pSelectColumns ) { for ( OSQLColumns::Vector::const_iterator lookupColumn = _pSelectColumns->get().begin(); lookupColumn != _pSelectColumns->get().end(); ++lookupColumn ) { Reference< XPropertySet > xColumn( *lookupColumn ); try { ::rtl::OUString sName, sTableName; xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) >>= sName; xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName; if ( sName == _out_rColumnName && sTableName == _out_rTableRange ) xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent; } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } } } else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec)) { // Funktion _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection ); } else if(_pColumnRef->getNodeType() == SQL_NODE_NAME) _out_rColumnName = _pColumnRef->getTokenValue(); } } // ----------------------------------------------------------------------------- void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef, ::rtl::OUString& _rColumnName, ::rtl::OUString& _rTableRange) const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getColumnRange" ); ::rtl::OUString sDummy; lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, NULL, sDummy ); } // ----------------------------------------------------------------------------- void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef, ::rtl::OUString& _rColumnName, ::rtl::OUString& _rTableRange, ::rtl::OUString& _out_rColumnAliasIfPresent ) const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getColumnRange" ); lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent ); } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection, ::rtl::OUString& _out_rColumnName, ::rtl::OUString& _out_rTableRange ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getColumnRange" ); ::rtl::OUString sDummy; lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, NULL, sDummy ); } //----------------------------------------------------------------------------- sal_Bool OSQLParseTreeIterator::getColumnTableRange(const OSQLParseNode* pNode, ::rtl::OUString &rTableRange) const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getColumnTableRange" ); // Ermitteln ob alle Spalten zu einer Tabelle gehoeren if (SQL_ISRULE(pNode,column_ref)) { ::rtl::OUString aColName, aTableRange; getColumnRange(pNode, aColName, aTableRange); if (!aTableRange.getLength()) // keinen gefunden { // dann die Spalte in den Tabellen suchen for (ConstOSQLTablesIterator aIter = m_pImpl->m_pTables->begin(); aIter != m_pImpl->m_pTables->end(); ++aIter) { if (aIter->second.is()) { try { Reference< XNameAccess > xColumns = aIter->second->getColumns(); if(xColumns->hasByName(aColName)) { Reference< XPropertySet > xColumn; if (xColumns->getByName(aColName) >>= xColumn) { OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!"); aTableRange = aIter->first; break; } } } catch(Exception&) { } } } if (!aTableRange.getLength()) return sal_False; } if (!rTableRange.getLength()) rTableRange = aTableRange; else if (rTableRange != aTableRange) return sal_False; } else { for (sal_uInt32 i = 0, ncount = pNode->count(); i < ncount; i++) { if (!getColumnTableRange(pNode->getChild(i), rTableRange)) return sal_False; } } return sal_True; } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode* pSelectNode) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseCreateColumns" ); // aIteratorStatus.Clear(); if (!pSelectNode || m_eStatementType != SQL_STATEMENT_CREATE_TABLE || m_pImpl->m_pTables->empty()) { impl_appendError( IParseContext::ERROR_GENERAL ); return; } if (!SQL_ISRULE(pSelectNode,base_table_element_commalist)) return ; for (sal_uInt32 i = 0; i < pSelectNode->count(); i++) { OSQLParseNode *pColumnRef = pSelectNode->getChild(i); if (SQL_ISRULE(pColumnRef,column_def)) { ::rtl::OUString aColumnName; ::rtl::OUString aTypeName; ::rtl::OUString aTableRange; sal_Int32 nType = DataType::VARCHAR; sal_Int32 nLen = 0; aColumnName = pColumnRef->getChild(0)->getTokenValue(); OSQLParseNode *pDatatype = pColumnRef->getChild(1); if (pDatatype && SQL_ISRULE(pDatatype,character_string_type)) { const OSQLParseNode *pType = pDatatype->getChild(0); aTypeName = pType->getTokenValue(); if (pDatatype->count() == 2 && (pType->getTokenID() == SQL_TOKEN_CHAR || pType->getTokenID() == SQL_TOKEN_CHARACTER )) nType = DataType::CHAR; const OSQLParseNode *pParams = pDatatype->getChild(pDatatype->count()-1); if ( pParams->count() ) { nLen = pParams->getChild(1)->getTokenValue().toInt32(); } } else if(pDatatype && pDatatype->getNodeType() == SQL_NODE_KEYWORD) { aTypeName = ::rtl::OUString::createFromAscii("VARCHAR"); } if (aTypeName.getLength()) { //TODO:Create a new class for create statement to handle field length OParseColumn* pColumn = new OParseColumn(aColumnName,aTypeName,::rtl::OUString(),::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN,0,0,nType,sal_False,sal_False,isCaseSensitive()); pColumn->setFunction(sal_False); pColumn->setRealName(aColumnName); Reference< XPropertySet> xCol = pColumn; m_aCreateColumns->get().push_back(xCol); } } } } //----------------------------------------------------------------------------- bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode* pSelectNode) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseSelectColumnNames" ); if ( ( m_pImpl->m_nIncludeMask & SelectColumns ) != SelectColumns ) return true; if (!pSelectNode || m_eStatementType != SQL_STATEMENT_SELECT || m_pImpl->m_pTables->empty()) { impl_appendError( IParseContext::ERROR_GENERAL ); return false; } if(SQL_ISRULE(pSelectNode,union_statement)) { return traverseSelectColumnNames( pSelectNode->getChild( 0 ) ) /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/; } static ::rtl::OUString aEmptyString; // nyi: mehr Pruefung auf korrekte Struktur! if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*")) { // SELECT * ... setSelectColumnName(m_aSelectColumns,::rtl::OUString::createFromAscii("*"), aEmptyString,aEmptyString); } else if (SQL_ISRULE(pSelectNode->getChild(2),scalar_exp_commalist)) { // SELECT column[,column] oder SELECT COUNT(*) ... OSQLParseNode * pSelection = pSelectNode->getChild(2); for (sal_uInt32 i = 0; i < pSelection->count(); i++) { OSQLParseNode *pColumnRef = pSelection->getChild(i); //if (SQL_ISRULE(pColumnRef,select_sublist)) if (SQL_ISRULE(pColumnRef,derived_column) && SQL_ISRULE(pColumnRef->getChild(0),column_ref) && pColumnRef->getChild(0)->count() == 3 && SQL_ISPUNCTUATION(pColumnRef->getChild(0)->getChild(2),"*")) { // alle Spalten der Tabelle ::rtl::OUString aTableRange; pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); setSelectColumnName(m_aSelectColumns,::rtl::OUString::createFromAscii("*"), aEmptyString,aTableRange); continue; } else if (SQL_ISRULE(pColumnRef,derived_column)) { ::rtl::OUString aColumnAlias(getColumnAlias(pColumnRef)); // kann leer sein ::rtl::OUString sColumnName; ::rtl::OUString aTableRange; sal_Int32 nType = DataType::VARCHAR; sal_Bool bFkt(sal_False); pColumnRef = pColumnRef->getChild(0); if ( pColumnRef->count() == 3 && SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") && SQL_ISPUNCTUATION(pColumnRef->getChild(2),")") ) pColumnRef = pColumnRef->getChild(1); if (SQL_ISRULE(pColumnRef,column_ref)) { getColumnRange(pColumnRef,sColumnName,aTableRange); OSL_ENSURE(sColumnName.getLength(),"Columnname darf nicht leer sein"); } else /*if (SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec) || SQL_ISRULE(pColumnRef,position_exp) || SQL_ISRULE(pColumnRef,extract_exp) || SQL_ISRULE(pColumnRef,length_exp) || SQL_ISRULE(pColumnRef,char_value_fct)|| SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term))*/ { /* Funktionsaufruf vorhanden */ pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, NULL, sal_False, sal_True ); ::rtl::OUString sTableRange; // check if the column is also a parameter traverseORCriteria(pColumnRef); // num_value_exp // gehoeren alle beteiligten Spalten der Funktion zu einer Tabelle if (m_pImpl->m_pTables->size() == 1) { aTableRange = m_pImpl->m_pTables->begin()->first; } else { getColumnTableRange(pColumnRef,aTableRange); } if ( pColumnRef->isRule() ) { bFkt = sal_True; nType = getFunctionReturnType(pColumnRef); } } /* else { aIteratorStatus.setStatementTooComplex(); return; } */ if(!aColumnAlias.getLength()) aColumnAlias = sColumnName; setSelectColumnName(m_aSelectColumns,sColumnName,aColumnAlias,aTableRange,bFkt,nType,SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec)); } } } return !hasErrors(); } //----------------------------------------------------------------------------- bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode* pSelectNode) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseOrderByColumnNames" ); traverseByColumnNames( pSelectNode, sal_True ); return !hasErrors(); } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode* pSelectNode,sal_Bool _bOrder) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseByColumnNames" ); // aIteratorStatus.Clear(); if (pSelectNode == NULL) { //aIteratorStatus.setInvalidStatement(); return; } if (m_eStatementType != SQL_STATEMENT_SELECT) { //aIteratorStatus.setInvalidStatement(); return; } if(SQL_ISRULE(pSelectNode,union_statement)) { traverseByColumnNames(pSelectNode->getChild(0),_bOrder); return; } OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!"); OSQLParseNode * pTableExp = pSelectNode->getChild(3); OSL_ENSURE(pTableExp != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator:table_exp error in parse tree!"); OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); sal_uInt32 nPos = ( _bOrder ? ORDER_BY_CHILD_POS : 2 ); OSQLParseNode * pOptByClause = pTableExp->getChild(nPos); OSL_ENSURE(pOptByClause != NULL,"OSQLParseTreeIterator: error in parse tree!"); if ( pOptByClause->count() == 0 ) return; OSL_ENSURE(pOptByClause->count() == 3,"OSQLParseTreeIterator: error in parse tree!"); OSQLParseNode * pOrderingSpecCommalist = pOptByClause->getChild(2); OSL_ENSURE(pOrderingSpecCommalist != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(!_bOrder || SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OSQLParseTreeIterator:ordering_spec_commalist error in parse tree!"); OSL_ENSURE(pOrderingSpecCommalist->count() > 0,"OSQLParseTreeIterator: error in parse tree!"); ::rtl::OUString sColumnName,aColumnAlias; ::rtl::OUString aTableRange; sal_uInt32 nCount = pOrderingSpecCommalist->count(); for (sal_uInt32 i = 0; i < nCount; ++i) { OSQLParseNode* pColumnRef = pOrderingSpecCommalist->getChild(i); OSL_ENSURE(pColumnRef != NULL,"OSQLParseTreeIterator: error in parse tree!"); if ( _bOrder ) { OSL_ENSURE(SQL_ISRULE(pColumnRef,ordering_spec),"OSQLParseTreeIterator:ordering_spec error in parse tree!"); OSL_ENSURE(pColumnRef->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); pColumnRef = pColumnRef->getChild(0); } aTableRange = ::rtl::OUString(); sColumnName = ::rtl::OUString(); if ( SQL_ISRULE(pColumnRef,column_ref) ) { // Column-Name (und TableRange): if(SQL_ISRULE(pColumnRef,column_ref)) getColumnRange(pColumnRef,sColumnName,aTableRange); else // eine Expression pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); OSL_ENSURE(sColumnName.getLength(),"sColumnName darf nicht leer sein"); } else { // here I found a predicate pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); } OSL_ENSURE(pColumnRef != NULL,"OSQLParseTreeIterator: error in parse tree!"); if ( _bOrder ) { // Ascending/Descending OSQLParseNode * pOptAscDesc = pColumnRef->getParent()->getChild(1); OSL_ENSURE(pOptAscDesc != NULL,"OSQLParseTreeIterator: error in parse tree!"); sal_Bool bAscending = pOptAscDesc && SQL_ISTOKEN(pOptAscDesc,ASC); setOrderByColumnName(sColumnName, aTableRange,bAscending); } else setGroupByColumnName(sColumnName, aTableRange); } } //----------------------------------------------------------------------------- bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode* pSelectNode) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseGroupByColumnNames" ); traverseByColumnNames( pSelectNode, sal_False ); return !hasErrors(); } // ----------------------------------------------------------------------------- namespace { ::rtl::OUString lcl_generateParameterName( const OSQLParseNode& _rParentNode, const OSQLParseNode& _rParamNode ) { ::rtl::OUString sColumnName( RTL_CONSTASCII_USTRINGPARAM( "param" ) ); const sal_Int32 nCount = (sal_Int32)_rParentNode.count(); for ( sal_Int32 i = 0; i < nCount; ++i ) { if ( _rParentNode.getChild(i) == &_rParamNode ) { sColumnName += ::rtl::OUString::valueOf( i+1 ); break; } } return sColumnName; } } // ----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode* _pNode) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseParameters" ); if ( _pNode == NULL ) return; ::rtl::OUString sColumnName, sTableRange, aColumnAlias; const OSQLParseNode* pParent = _pNode->getParent(); if ( pParent != NULL ) { if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X { sal_uInt32 nPos = 0; if ( pParent->getChild(nPos) == _pNode ) nPos = 2; const OSQLParseNode* pOther = pParent->getChild(nPos); if ( SQL_ISRULE( pOther, column_ref ) ) getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias); else pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); } // if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X else if ( SQL_ISRULE(pParent,other_like_predicate_part_2) ) { const OSQLParseNode* pOther = pParent->getParent()->getChild(0); if ( SQL_ISRULE( pOther, column_ref ) ) getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias); else pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); } else if ( SQL_ISRULE(pParent,between_predicate_part_2) ) { const OSQLParseNode* pOther = pParent->getParent()->getChild(0); if ( SQL_ISRULE( pOther, column_ref ) ) getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias); else { pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); lcl_generateParameterName( *pParent, *_pNode ); } } else if ( pParent->getNodeType() == SQL_NODE_COMMALISTRULE ) { lcl_generateParameterName( *pParent, *_pNode ); } } traverseParameter( _pNode, pParent, sColumnName, sTableRange, aColumnAlias ); const sal_uInt32 nCount = _pNode->count(); for (sal_uInt32 i = 0; i < nCount; ++i) { const OSQLParseNode* pChild = _pNode->getChild(i); traverseParameters( pChild ); } } //----------------------------------------------------------------------------- bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode* pSelectNode) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseSelectionCriteria" ); if ( pSelectNode == NULL ) return false; // Parse Tree analysieren (je nach Statement-Typ) // und Zeiger auf WHERE-Klausel setzen: OSQLParseNode * pWhereClause = NULL; if (m_eStatementType == SQL_STATEMENT_SELECT) { if(SQL_ISRULE(pSelectNode,union_statement)) { return traverseSelectionCriteria( pSelectNode->getChild( 0 ) ) && traverseSelectionCriteria( pSelectNode->getChild( 3 ) ); } OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!"); OSQLParseNode * pTableExp = pSelectNode->getChild(3); OSL_ENSURE(pTableExp != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); pWhereClause = pTableExp->getChild(1); } else if (SQL_ISRULE(pSelectNode,update_statement_searched)) { OSL_ENSURE(pSelectNode->count() == 5,"OSQLParseTreeIterator: error in parse tree!"); pWhereClause = pSelectNode->getChild(4); } else if (SQL_ISRULE(pSelectNode,delete_statement_searched)) { OSL_ENSURE(pSelectNode->count() == 4,"OSQLParseTreeIterator: error in parse tree!"); pWhereClause = pSelectNode->getChild(3); } else if (SQL_ISRULE(pSelectNode,delete_statement_positioned)) { // nyi OSL_ASSERT("OSQLParseTreeIterator::getSelectionCriteria: positioned nyi"); } else { // Anderes Statement. Keine Selektionskriterien. return false; } if (! SQL_ISRULE(pWhereClause,where_clause)) { // Die Where Clause ist meistens optional, d. h. es koennte sich auch // um "optional_where_clause" handeln. OSL_ENSURE(SQL_ISRULE(pWhereClause,opt_where_clause),"OSQLParseTreeIterator: error in parse tree!"); return false; } // Wenn es aber eine where_clause ist, dann darf sie nicht leer sein: OSL_ENSURE(pWhereClause->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1); OSL_ENSURE(pComparisonPredicate != NULL,"OSQLParseTreeIterator: error in parse tree!"); // // Und nun die Vergleichskriterien abarbeiten (rekursiv, alles ist erstmal ein OR-Kriterium): // traverseORCriteria(pComparisonPredicate); return !hasErrors(); } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseORCriteria(OSQLParseNode * pSearchCondition) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseORCriteria" ); if ( pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") && SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")") ) { // Runde Klammern um den Ausdruck traverseORCriteria(pSearchCondition->getChild(1)); } else if (SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 && SQL_ISTOKEN(pSearchCondition->getChild(1),OR)) { // OR-Verknuepfung: for (int i = 0; i < 3; i++) { if (i == 1) continue; // Schluesselwort OR ueberspringen // Ist das erste Element wieder eine OR-Verknuepfung? if (i == 0 && SQL_ISRULE(pSearchCondition->getChild(0),search_condition) && pSearchCondition->getChild(0)->count() == 3 && SQL_ISTOKEN(pSearchCondition->getChild(0)->getChild(1),OR)) { // Dann rekursiv absteigen ... traverseORCriteria(pSearchCondition->getChild(0)); } else { // AND-Kriterien ... traverseANDCriteria(pSearchCondition->getChild(i)); // if (! aIteratorStatus.IsSuccessful()) break; } // if (! aIteratorStatus.IsSuccessful()) break; } } else { // Nur *ein* Kriterium oder eine AND-Verknuepfung von Kriterien. // Direkt die AND-Kriterien behandeln. traverseANDCriteria(pSearchCondition); // if (! aIteratorStatus.IsSuccessful()) return; } // Fehler einfach weiterreichen. } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseANDCriteria(OSQLParseNode * pSearchCondition) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseANDCriteria" ); if ( SQL_ISRULE(pSearchCondition,boolean_primary) && pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") && SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")") ) { // Runde Klammern traverseANDCriteria(pSearchCondition->getChild(1)); } // Das erste Element ist eine OR-Verknuepfung else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 ) { // Dann rekursiv absteigen (dieselbe Row benutzen) ... traverseORCriteria(pSearchCondition->getChild(0)); // if (! aIteratorStatus.IsSuccessful()) // return; // Und mit dem rechten Child weitermachen: traverseANDCriteria(pSearchCondition->getChild(2)); } // Das erste Element ist (wieder) eine AND-Verknuepfung else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 ) { // Dann rekursiv absteigen (dieselbe Row benutzen) ... traverseANDCriteria(pSearchCondition->getChild(0)); // if (! aIteratorStatus.IsSuccessful()) // return; // Und mit dem rechten Child weitermachen: traverseANDCriteria(pSearchCondition->getChild(2)); } // Sonst einzelne Suchkriterien wie =, !=, ..., LIKE, IS NULL usw. behandeln: else if (SQL_ISRULE(pSearchCondition,comparison_predicate) ) { ::rtl::OUString aValue; pSearchCondition->getChild(2)->parseNodeToStr( aValue, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); traverseOnePredicate(pSearchCondition->getChild(0),aValue,pSearchCondition->getChild(2)); impl_fillJoinConditions(pSearchCondition); // if (! aIteratorStatus.IsSuccessful()) // return; } else if (SQL_ISRULE(pSearchCondition,like_predicate) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/) { OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); const OSQLParseNode* pPart2 = pSearchCondition->getChild(1); sal_Int32 nCurentPos = pPart2->count()-2; OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurentPos); OSQLParseNode * pOptEscape = pPart2->getChild(nCurentPos+1); OSL_ENSURE(pNum_value_exp != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(pOptEscape != NULL,"OSQLParseTreeIterator: error in parse tree!"); if (pOptEscape->count() != 0) { // aIteratorStatus.setStatementTooComplex(); return; } ::rtl::OUString aValue; OSQLParseNode * pParam = NULL; if (SQL_ISRULE(pNum_value_exp,parameter)) pParam = pNum_value_exp; else if(pNum_value_exp->isToken()) // Normaler Wert aValue = pNum_value_exp->getTokenValue(); else { pNum_value_exp->parseNodeToStr( aValue, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); pParam = pNum_value_exp; } traverseOnePredicate(pSearchCondition->getChild(0),aValue,pParam); // if (! aIteratorStatus.IsSuccessful()) // return; } else if (SQL_ISRULE(pSearchCondition,in_predicate)) { OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); const OSQLParseNode* pPart2 = pSearchCondition->getChild(1); traverseORCriteria(pSearchCondition->getChild(0)); // if (! aIteratorStatus.IsSuccessful()) return; OSQLParseNode* pChild = pPart2->getChild(2); if ( SQL_ISRULE(pChild->getChild(0),subquery) ) { traverseTableNames( *m_pImpl->m_pSubTables ); traverseSelectionCriteria(pChild->getChild(0)->getChild(1)); } else { // '(' value_exp_commalist ')' pChild = pChild->getChild(1); sal_Int32 nCount = pChild->count(); for (sal_Int32 i=0; i < nCount; ++i) { traverseANDCriteria(pChild->getChild(i)); } } } else if (SQL_ISRULE(pSearchCondition,test_for_null) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/) { OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); const OSQLParseNode* pPart2 = pSearchCondition->getChild(1); (void)pPart2; OSL_ENSURE(SQL_ISTOKEN(pPart2->getChild(0),IS),"OSQLParseTreeIterator: error in parse tree!"); ::rtl::OUString aString; traverseOnePredicate(pSearchCondition->getChild(0),aString,NULL); // if (! aIteratorStatus.IsSuccessful()) return; } else if (SQL_ISRULE(pSearchCondition,num_value_exp) || SQL_ISRULE(pSearchCondition,term)) { ::rtl::OUString aString; traverseOnePredicate(pSearchCondition->getChild(0),aString,pSearchCondition->getChild(0)); traverseOnePredicate(pSearchCondition->getChild(2),aString,pSearchCondition->getChild(2)); } // Fehler einfach weiterreichen. } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode* _pParseNode ,const OSQLParseNode* _pParentNode ,const ::rtl::OUString& _aColumnName ,const ::rtl::OUString& _aTableRange ,const ::rtl::OUString& _rColumnAlias) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseParameter" ); if ( !SQL_ISRULE( _pParseNode, parameter ) ) return; if ( ( m_pImpl->m_nIncludeMask & Parameters ) != Parameters ) // parameters not to be included in the traversal return; OSL_ENSURE(_pParseNode->count() > 0,"OSQLParseTreeIterator: error in parse tree!"); OSQLParseNode * pMark = _pParseNode->getChild(0); ::rtl::OUString sParameterName; if (SQL_ISPUNCTUATION(pMark,"?")) { sParameterName = _rColumnAlias.getLength() ? _rColumnAlias : _aColumnName.getLength() ? _aColumnName : ::rtl::OUString::createFromAscii("?"); } else if (SQL_ISPUNCTUATION(pMark,":")) { sParameterName = _pParseNode->getChild(1)->getTokenValue(); } else if (SQL_ISPUNCTUATION(pMark,"[")) { sParameterName = _pParseNode->getChild(1)->getTokenValue(); } else { OSL_ASSERT("OSQLParseTreeIterator: error in parse tree!"); } // found a parameter if ( _pParentNode && (SQL_ISRULE(_pParentNode,general_set_fct) || SQL_ISRULE(_pParentNode,set_fct_spec)) ) {// found a function as column_ref ::rtl::OUString sFunctionName; _pParentNode->getChild(0)->parseNodeToStr( sFunctionName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); const sal_uInt32 nCount = _pParentNode->count(); sal_uInt32 i = 0; for(; i < nCount;++i) { if ( _pParentNode->getChild(i) == _pParseNode ) break; } sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode->getChild(0)->getTokenID(), i-1); OParseColumn* pColumn = new OParseColumn( sParameterName, ::rtl::OUString(), ::rtl::OUString(), ::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN, 0, 0, nType, sal_False, sal_False, isCaseSensitive()); pColumn->setFunction(sal_True); pColumn->setAggregateFunction(sal_True); pColumn->setRealName(sFunctionName); m_aParameters->get().push_back(pColumn); } else { sal_Bool bNotFound = sal_True; OSQLColumns::Vector::const_iterator aIter = ::connectivity::find( m_aSelectColumns->get().begin(), m_aSelectColumns->get().end(), _aColumnName,::comphelper::UStringMixEqual( isCaseSensitive() ) ); if(aIter != m_aSelectColumns->get().end()) { OParseColumn* pNewColumn = new OParseColumn(*aIter,isCaseSensitive()); pNewColumn->setName(sParameterName); pNewColumn->setRealName(_aColumnName); m_aParameters->get().push_back(pNewColumn); bNotFound = sal_False; } else if(_aColumnName.getLength())// search in the tables for the right one { Reference xColumn = findColumn( _aColumnName, _aTableRange, true ); if ( xColumn.is() ) { OParseColumn* pNewColumn = new OParseColumn(xColumn,isCaseSensitive()); pNewColumn->setName(sParameterName); pNewColumn->setRealName(_aColumnName); m_aParameters->get().push_back(pNewColumn); bNotFound = sal_False; } } if ( bNotFound ) { sal_Int32 nType = DataType::VARCHAR; OSQLParseNode* pParent = _pParentNode ? _pParentNode->getParent() : NULL; if ( pParent && (SQL_ISRULE(pParent,general_set_fct) || SQL_ISRULE(pParent,set_fct_spec)) ) { const sal_uInt32 nCount = _pParentNode->count(); sal_uInt32 i = 0; for(; i < nCount;++i) { if ( _pParentNode->getChild(i) == _pParseNode ) break; } nType = ::connectivity::OSQLParser::getFunctionParameterType( pParent->getChild(0)->getTokenID(), i+1); } ::rtl::OUString aNewColName( getUniqueColumnName( sParameterName ) ); OParseColumn* pColumn = new OParseColumn(aNewColName, ::rtl::OUString(), ::rtl::OUString(), ::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN, 0, 0, nType, sal_False, sal_False, isCaseSensitive() ); pColumn->setName(aNewColName); pColumn->setRealName(sParameterName); m_aParameters->get().push_back(pColumn); } } } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseOnePredicate( OSQLParseNode * pColumnRef, ::rtl::OUString& rValue, OSQLParseNode * pParseNode) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseOnePredicate" ); if ( !pParseNode ) return; // Column-Name (und TableRange): ::rtl::OUString aColumnName, aTableRange, sColumnAlias; getColumnRange( pColumnRef, aColumnName, aTableRange, sColumnAlias); ::rtl::OUString aName; /*if (SQL_ISRULE(pParseNode,parameter)) traverseParameter( pParseNode, pColumnRef, aColumnName, aTableRange, sColumnAlias ); else */if (SQL_ISRULE(pParseNode,column_ref))// Column-Name (und TableRange): getColumnRange(pParseNode,aName,rValue); else { traverseORCriteria(pParseNode); // if (! aIteratorStatus.IsSuccessful()) return; } } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseSome( sal_uInt32 _nIncludeMask ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseSome" ); impl_traverse( _nIncludeMask ); } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::traverseAll() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::traverseAll" ); impl_traverse( All ); } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::impl_traverse( sal_uInt32 _nIncludeMask ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::impl_traverse" ); impl_resetErrors(); m_pImpl->m_nIncludeMask = _nIncludeMask; if ( !traverseTableNames( *m_pImpl->m_pTables ) ) return; switch ( m_eStatementType ) { case SQL_STATEMENT_SELECT: { const OSQLParseNode* pSelectNode = m_pParseTree; traverseParameters( pSelectNode ); if ( !traverseSelectColumnNames( pSelectNode ) || !traverseOrderByColumnNames( pSelectNode ) || !traverseGroupByColumnNames( pSelectNode ) || !traverseSelectionCriteria( pSelectNode ) ) return; } break; case SQL_STATEMENT_CREATE_TABLE: { //0 | 1 | 2 |3| 4 |5 //create table sc.foo ( a char(20), b char ) const OSQLParseNode* pCreateNode = m_pParseTree->getChild(4); traverseCreateColumns(pCreateNode); } break; case SQL_STATEMENT_INSERT: break; default: break; } } // Dummy-Implementationen: //----------------------------------------------------------------------------- OSQLTable OSQLParseTreeIterator::impl_createTableObject( const ::rtl::OUString& rTableName, const ::rtl::OUString& rCatalogName, const ::rtl::OUString& rSchemaName ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::impl_createTableObject" ); OSL_PRECOND( m_eStatementType == SQL_STATEMENT_CREATE_TABLE, "OSQLParseTreeIterator::impl_createTableObject: only to be called for CREATE TABLE statements!" ); // (in all other cases, m_pTables is to contain the table objects as obtained from the tables // container of the connection (m_xTablesContainer) OSQLTable aReturnTable = new OTable( NULL, sal_False, rTableName, ::rtl::OUString::createFromAscii("Table"), ::rtl::OUString::createFromAscii("New Created Table"), rSchemaName, rCatalogName ); return aReturnTable; } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::appendColumns(::vos::ORef& _rColumns,const ::rtl::OUString& _rTableAlias,const OSQLTable& _rTable) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::appendColumns" ); if (!_rTable.is()) return; Reference xColumns = _rTable->getColumns(); if ( !xColumns.is() ) return; Sequence< ::rtl::OUString > aColNames = xColumns->getElementNames(); const ::rtl::OUString* pBegin = aColNames.getConstArray(); const ::rtl::OUString* pEnd = pBegin + aColNames.getLength(); for(;pBegin != pEnd;++pBegin) { ::rtl::OUString aName(getUniqueColumnName(*pBegin)); Reference< XPropertySet > xColumn; if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is()) { OParseColumn* pColumn = new OParseColumn(aName , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))) , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))) , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))) , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))) , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))) , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))) , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))) , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))) , isCaseSensitive() ); pColumn->setTableName(_rTableAlias); pColumn->setRealName(*pBegin); Reference< XPropertySet> xCol = pColumn; _rColumns->get().push_back(xCol); } else impl_appendError( IParseContext::ERROR_INVALID_COLUMN, pBegin, &_rTableAlias ); } } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::setSelectColumnName(::vos::ORef& _rColumns,const ::rtl::OUString & rColumnName,const ::rtl::OUString & rColumnAlias, const ::rtl::OUString & rTableRange,sal_Bool bFkt,sal_Int32 _nType,sal_Bool bAggFkt) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::setSelectColumnName" ); if(rColumnName.toChar() == '*' && !rTableRange.getLength()) { // SELECT * ... OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!"); for(ConstOSQLTablesIterator aIter = m_pImpl->m_pTables->begin(); aIter != m_pImpl->m_pTables->end();++aIter) appendColumns(_rColumns,aIter->first,aIter->second); } else if( rColumnName.toChar() == '*' && rTableRange.getLength() ) { // SELECT .* OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!"); ConstOSQLTablesIterator aFind = m_pImpl->m_pTables->find(rTableRange); if(aFind != m_pImpl->m_pTables->end()) appendColumns(_rColumns,rTableRange,aFind->second); } else if ( !rTableRange.getLength() ) { // SELECT ... // without table specified if ( !bFkt ) { Reference< XPropertySet> xNewColumn; for ( OSQLTablesIterator aIter = m_pImpl->m_pTables->begin(); aIter != m_pImpl->m_pTables->end(); ++aIter ) { if ( !aIter->second.is() ) continue; Reference xColumns = aIter->second->getColumns(); Reference< XPropertySet > xColumn; if ( !xColumns->hasByName( rColumnName ) || !( xColumns->getByName( rColumnName ) >>= xColumn ) ) continue; ::rtl::OUString aNewColName(getUniqueColumnName(rColumnAlias)); OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive()); xNewColumn = pColumn; pColumn->setTableName(aIter->first); pColumn->setName(aNewColName); pColumn->setRealName(rColumnName); break; } if ( !xNewColumn.is() ) { // no function (due to the above !bFkt), no existing column // => assume an expression ::rtl::OUString aNewColName( getUniqueColumnName( rColumnAlias ) ); // did not find a column with this name in any of the tables OParseColumn* pColumn = new OParseColumn( aNewColName, ::rtl::OUString::createFromAscii( "VARCHAR" ), // TODO: does this match with _nType? // Or should be fill this from the getTypeInfo of the connection? ::rtl::OUString(), ::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN, 0, 0, _nType, sal_False, sal_False, isCaseSensitive() ); xNewColumn = pColumn; pColumn->setRealName( rColumnName ); } _rColumns->get().push_back( xNewColumn ); } else { ::rtl::OUString aNewColName(getUniqueColumnName(rColumnAlias)); OParseColumn* pColumn = new OParseColumn(aNewColName,::rtl::OUString(),::rtl::OUString(),::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,sal_False,sal_False,isCaseSensitive()); pColumn->setFunction(sal_True); pColumn->setAggregateFunction(bAggFkt); pColumn->setRealName(rColumnName); Reference< XPropertySet> xCol = pColumn; _rColumns->get().push_back(xCol); } } else // ColumnName und Tablename vorhanden { ConstOSQLTablesIterator aFind = m_pImpl->m_pTables->find(rTableRange); sal_Bool bError = sal_False; if (aFind != m_pImpl->m_pTables->end() && aFind->second.is()) { if (bFkt) { ::rtl::OUString aNewColName(getUniqueColumnName(rColumnAlias)); OParseColumn* pColumn = new OParseColumn(aNewColName,::rtl::OUString(),::rtl::OUString(),::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,sal_False,sal_False,isCaseSensitive()); pColumn->setFunction(sal_True); pColumn->setAggregateFunction(bAggFkt); pColumn->setRealName(rColumnName); pColumn->setTableName(aFind->first); Reference< XPropertySet> xCol = pColumn; _rColumns->get().push_back(xCol); } else { Reference< XPropertySet > xColumn; if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn)) { ::rtl::OUString aNewColName(getUniqueColumnName(rColumnAlias)); OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive()); pColumn->setName(aNewColName); pColumn->setRealName(rColumnName); pColumn->setTableName(aFind->first); Reference< XPropertySet> xCol = pColumn; _rColumns->get().push_back(xCol); } else bError = sal_True; } } else bError = sal_True; // Tabelle existiert nicht oder Feld nicht vorhanden if (bError) { ::rtl::OUString aNewColName(getUniqueColumnName(rColumnAlias)); OParseColumn* pColumn = new OParseColumn(aNewColName,::rtl::OUString(),::rtl::OUString(),::rtl::OUString(), ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,sal_False,sal_False,isCaseSensitive()); pColumn->setFunction(sal_True); pColumn->setAggregateFunction(bAggFkt); Reference< XPropertySet> xCol = pColumn; _rColumns->get().push_back(xCol); } } } //----------------------------------------------------------------------------- ::rtl::OUString OSQLParseTreeIterator::getUniqueColumnName(const ::rtl::OUString & rColumnName) const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getUniqueColumnName" ); ::rtl::OUString aAlias(rColumnName); OSQLColumns::Vector::const_iterator aIter = find( m_aSelectColumns->get().begin(), m_aSelectColumns->get().end(), aAlias, ::comphelper::UStringMixEqual( isCaseSensitive() ) ); sal_Int32 i=1; while(aIter != m_aSelectColumns->get().end()) { (aAlias = rColumnName) += ::rtl::OUString::valueOf(i++); aIter = find( m_aSelectColumns->get().begin(), m_aSelectColumns->get().end(), aAlias, ::comphelper::UStringMixEqual( isCaseSensitive() ) ); } return aAlias; } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::setOrderByColumnName(const ::rtl::OUString & rColumnName, const ::rtl::OUString & rTableRange,sal_Bool bAscending) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::setOrderByColumnName" ); Reference xColumn = findColumn( rColumnName, rTableRange, false ); if ( xColumn.is() ) m_aOrderColumns->get().push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) ); else { sal_Int32 nId = rColumnName.toInt32(); if ( nId > 0 && nId < static_cast(m_aSelectColumns->get().size()) ) m_aOrderColumns->get().push_back( new OOrderColumn( ( m_aSelectColumns->get() )[nId-1], isCaseSensitive(), bAscending ) ); } #ifdef SQL_TEST_PARSETREEITERATOR cout << "OSQLParseTreeIterator::setOrderByColumnName: " << (const char *) rColumnName << ", " << (const char *) rTableRange << ", " << (bAscending ? "sal_True" : "sal_False") << "\n"; #endif } //----------------------------------------------------------------------------- void OSQLParseTreeIterator::setGroupByColumnName(const ::rtl::OUString & rColumnName, const ::rtl::OUString & rTableRange) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::setGroupByColumnName" ); Reference xColumn = findColumn( rColumnName, rTableRange, false ); if ( xColumn.is() ) m_aGroupColumns->get().push_back(new OParseColumn(xColumn,isCaseSensitive())); else { sal_Int32 nId = rColumnName.toInt32(); if ( nId > 0 && nId < static_cast(m_aSelectColumns->get().size()) ) m_aGroupColumns->get().push_back(new OParseColumn((m_aSelectColumns->get())[nId-1],isCaseSensitive())); } #ifdef SQL_TEST_PARSETREEITERATOR cout << "OSQLParseTreeIterator::setOrderByColumnName: " << (const char *) rColumnName << ", " << (const char *) rTableRange << ", " << (bAscending ? "sal_True" : "sal_False") << "\n"; #endif } //----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getWhereTree() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getWhereTree" ); if (!m_pParseTree) return NULL; // Parse Tree analysieren (je nach Statement-Typ) // und Zeiger auf WHERE-Klausel setzen: OSQLParseNode * pWhereClause = NULL; if(getStatementType() == SQL_STATEMENT_SELECT) { OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); OSQLParseNode * pTableExp = m_pParseTree->getChild(3); OSL_ENSURE(pTableExp != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); pWhereClause = pTableExp->getChild(1); } else if (SQL_ISRULE(m_pParseTree,update_statement_searched) || SQL_ISRULE(m_pParseTree,delete_statement_searched)) { pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1); } if(pWhereClause->count() != 2) pWhereClause = NULL; return pWhereClause; } //----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getOrderTree() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getOrderTree" ); if (!m_pParseTree || getStatementType() != SQL_STATEMENT_SELECT) return NULL; // Parse Tree analysieren (je nach Statement-Typ) // und Zeiger auf ORDER-Klausel setzen: OSQLParseNode * pOrderClause = NULL; OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); OSQLParseNode * pTableExp = m_pParseTree->getChild(3); OSL_ENSURE(pTableExp != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS); // Wenn es aber eine order_by ist, dann darf sie nicht leer sein: if(pOrderClause->count() != 3) pOrderClause = NULL; return pOrderClause; } //----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getGroupByTree() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getGroupByTree" ); if (!m_pParseTree || getStatementType() != SQL_STATEMENT_SELECT) return NULL; // Parse Tree analysieren (je nach Statement-Typ) // und Zeiger auf ORDER-Klausel setzen: OSQLParseNode * pGroupClause = NULL; OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); OSQLParseNode * pTableExp = m_pParseTree->getChild(3); OSL_ENSURE(pTableExp != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); pGroupClause = pTableExp->getChild(2); // Wenn es aber eine order_by ist, dann darf sie nicht leer sein: if(pGroupClause->count() != 3) pGroupClause = NULL; return pGroupClause; } //----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const { if (!m_pParseTree || getStatementType() != SQL_STATEMENT_SELECT) return NULL; // Parse Tree analysieren (je nach Statement-Typ) // und Zeiger auf ORDER-Klausel setzen: OSQLParseNode * pHavingClause = NULL; OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); OSQLParseNode * pTableExp = m_pParseTree->getChild(3); OSL_ENSURE(pTableExp != NULL,"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); pHavingClause = pTableExp->getChild(3); // Wenn es aber eine order_by ist, dann darf sie nicht leer sein: if(pHavingClause->count() < 1) pHavingClause = NULL; return pHavingClause; } // ----------------------------------------------------------------------------- sal_Bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode* _pTableNode) const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::isTableNode" ); return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) || SQL_ISRULE(_pTableNode,schema_name) || SQL_ISRULE(_pTableNode,table_name)); } // ----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getSimpleWhereTree() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getSimpleWhereTree" ); const OSQLParseNode* pNode = getWhereTree(); return pNode ? pNode->getChild(1) : NULL; } // ----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getSimpleOrderTree() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getSimpleOrderTree" ); const OSQLParseNode* pNode = getOrderTree(); return pNode ? pNode->getChild(2) : NULL; } // ----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getSimpleGroupByTree() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getSimpleGroupByTree" ); const OSQLParseNode* pNode = getGroupByTree(); return pNode ? pNode->getChild(2) : NULL; } // ----------------------------------------------------------------------------- const OSQLParseNode* OSQLParseTreeIterator::getSimpleHavingTree() const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::getSimpleHavingTree" ); const OSQLParseNode* pNode = getHavingTree(); return pNode ? pNode->getChild(1) : NULL; } // ----------------------------------------------------------------------------- Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const ::rtl::OUString & rColumnName, const ::rtl::OUString & rTableRange, bool _bLookInSubTables ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::findColumn" ); Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange ); if ( !xColumn.is() && _bLookInSubTables ) xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange ); return xColumn; } // ----------------------------------------------------------------------------- Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables,const ::rtl::OUString & rColumnName, const ::rtl::OUString & rTableRange) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::findColumn" ); Reference< XPropertySet > xColumn; if ( rTableRange.getLength() ) { ConstOSQLTablesIterator aFind = _rTables.find(rTableRange); if ( aFind != _rTables.end() && aFind->second.is() && aFind->second->getColumns().is() && aFind->second->getColumns()->hasByName(rColumnName) ) aFind->second->getColumns()->getByName(rColumnName) >>= xColumn; } if ( !xColumn.is() ) { OSQLTables::const_iterator aEnd = _rTables.end(); for(OSQLTables::const_iterator aIter = _rTables.begin(); aIter != aEnd; ++aIter) { if ( aIter->second.is() ) { Reference xColumns = aIter->second->getColumns(); if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) ) { OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!"); break; // diese Column darf nur einmal vorkommen } } } } return xColumn; } // ----------------------------------------------------------------------------- void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const ::rtl::OUString* _pReplaceToken1, const ::rtl::OUString* _pReplaceToken2 ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::impl_appendError" ); ::rtl::OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError ); if ( _pReplaceToken1 ) { bool bTwoTokens = ( _pReplaceToken2 != NULL ); const sal_Char* pPlaceHolder1 = bTwoTokens ? "#1" : "#"; const ::rtl::OUString sPlaceHolder1 = ::rtl::OUString::createFromAscii( pPlaceHolder1 ); sErrorMessage = sErrorMessage.replaceAt( sErrorMessage.indexOf( sPlaceHolder1 ), sPlaceHolder1.getLength(), *_pReplaceToken1 ); if ( _pReplaceToken2 ) sErrorMessage = sErrorMessage.replaceAt( sErrorMessage.indexOf( ::rtl::OUString::createFromAscii( "#2" ) ), 2, *_pReplaceToken2 ); } impl_appendError( SQLException( sErrorMessage, NULL, getStandardSQLState( SQL_GENERAL_ERROR ), 1000, Any() ) ); } // ----------------------------------------------------------------------------- void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "parse", "Ocke.Janssen@sun.com", "OSQLParseTreeIterator::impl_appendError" ); if ( m_aErrors.Message.getLength() ) { SQLException* pErrorChain = &m_aErrors; while ( pErrorChain->NextException.hasValue() ) pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData ); pErrorChain->NextException <<= _rError; } else m_aErrors = _rError; } // ----------------------------------------------------------------------------- sal_Int32 OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode* _pNode ) { sal_Int32 nType = DataType::OTHER; ::rtl::OUString sFunctionName; if ( SQL_ISRULE(_pNode,length_exp) ) { _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() ); } else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) ) { nType = DataType::DOUBLE; } else { _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); // MIN and MAX have another return type, we have to check the expression itself. // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566 if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) )) { const OSQLParseNode* pValueExp = _pNode->getChild(3); if (SQL_ISRULE(pValueExp,column_ref)) { ::rtl::OUString sColumnName; ::rtl::OUString aTableRange; getColumnRange(pValueExp,sColumnName,aTableRange); OSL_ENSURE(sColumnName.getLength(),"Columnname darf nicht leer sein"); Reference xColumn = findColumn( sColumnName, aTableRange, true ); if ( xColumn.is() ) { xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType; } } else { if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) ) { nType = DataType::DOUBLE; } else if ( SQL_ISRULE(pValueExp,datetime_primary) ) { switch(pValueExp->getChild(0)->getTokenID() ) { case SQL_TOKEN_CURRENT_DATE: nType = DataType::DATE; break; case SQL_TOKEN_CURRENT_TIME: nType = DataType::TIME; break; case SQL_TOKEN_CURRENT_TIMESTAMP: nType = DataType::TIMESTAMP; break; } } else if ( SQL_ISRULE(pValueExp,value_exp_primary) ) { nType = getFunctionReturnType(pValueExp->getChild(1)); } else if ( SQL_ISRULE(pValueExp,concatenation) || SQL_ISRULE(pValueExp,char_factor) || SQL_ISRULE(pValueExp,bit_value_fct) || SQL_ISRULE(pValueExp,char_value_fct) || SQL_ISRULE(pValueExp,char_substring_fct) || SQL_ISRULE(pValueExp,fold) || SQL_ISTOKEN(pValueExp,STRING) ) { nType = DataType::VARCHAR; } } if ( nType == DataType::OTHER ) nType = DataType::DOUBLE; } else nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() ); } return nType; }