diff options
Diffstat (limited to 'connectivity/source/parse/sqliterator.cxx')
-rw-r--r-- | connectivity/source/parse/sqliterator.cxx | 2247 |
1 files changed, 2247 insertions, 0 deletions
diff --git a/connectivity/source/parse/sqliterator.cxx b/connectivity/source/parse/sqliterator.cxx new file mode 100644 index 000000000000..e1d805e9a1e5 --- /dev/null +++ b/connectivity/source/parse/sqliterator.cxx @@ -0,0 +1,2247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 <connectivity/sqlparse.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sqlerror.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#ifdef SQL_TEST_PARSETREEITERATOR +#include <iostream> +#endif +#include "connectivity/PColumn.hxx" +#include "connectivity/dbtools.hxx" +#include <tools/diagnose_ex.h> +#include "TConnection.hxx" +#include <comphelper/types.hxx> +#include <connectivity/dbmetadata.hxx> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> +#include "diagnose_ex.h" +#include <rtl/logfile.hxx> + +#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->storesMixedCaseQuotedIdentifiers(); + 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() == 5,"OSQLParseTreeIterator: error in parse tree!"); + + sal_uInt32 nPos = ( _bOrder ? 4 : 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() == 5,"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* _pColumnRef + ,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 ( _pColumnRef && (SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec)) ) + {// found a function as column_ref + ::rtl::OUString sFunctionName; + _pColumnRef->getChild(0)->parseNodeToStr( sFunctionName, m_pImpl->m_xConnection, NULL, sal_False, sal_False ); + const sal_uInt32 nCount = _pColumnRef->count(); + sal_uInt32 i = 0; + for(; i < nCount;++i) + { + if ( _pColumnRef->getChild(i) == _pParseNode ) + break; + } + sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pColumnRef->getParent()->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<XPropertySet> 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 = _pColumnRef ? _pColumnRef->getParent() : NULL; + if ( pParent && (SQL_ISRULE(pParent,general_set_fct) || SQL_ISRULE(pParent,set_fct_spec)) ) + { + const sal_uInt32 nCount = _pColumnRef->count(); + sal_uInt32 i = 0; + for(; i < nCount;++i) + { + if ( _pColumnRef->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<OSQLColumns>& _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<XNameAccess> 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<OSQLColumns>& _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 <table>.* + 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 <something> ... + // 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<XNameAccess> 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<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false ); + if ( xColumn.is() ) + m_aOrderColumns->get().push_back(new OOrderColumn(xColumn,isCaseSensitive(),bAscending)); + else + { + sal_Int32 nId = rColumnName.toInt32(); + if ( nId > 0 && nId < static_cast<sal_Int32>(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<XPropertySet> 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<sal_Int32>(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() == 5,"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() == 5,"OSQLParseTreeIterator: error in parse tree!"); + + pOrderClause = pTableExp->getChild(4); + // 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() == 5,"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() == 5,"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<XNameAccess> 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<XPropertySet> 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; +} + |