/**************************************************************
 * 
 * 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 <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->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<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 = _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<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, rTableRange, 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() == 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<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;
}