For example dbaccess::OSingleSelectQueryComposer::appendOrderByColumn expects it (via impl_getColumnName_throw via getTableAlias) There is some vagueness: Should the TableName property contain just the table name, or the *composed* table name (that is with catalog and/or schema if used by this DB)? In the case of a query, should it contain the table name (alias) *in* *the* *query* or of the original table? In the former case, what meaning do SchemaName and CatalogName have? They should be empty? For now, commit as such and deal with the fallout, if any, when it hits the fan. If we really need to store these *different* values, (that is, some code validly needs them) it would be easier / cleaner / ... to define *different* properties for these *different* notions. Change-Id: I032e619a60e7563cd51478db16cb5e0e5452bfde
2252 lines
97 KiB
C++
2252 lines
97 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* 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 .
|
|
*/
|
|
|
|
#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>
|
|
|
|
|
|
#include <iterator>
|
|
|
|
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;
|
|
}
|
|
|
|
// If m_pParseTree, but no connection then return
|
|
if ( !m_pImpl->m_xTableContainer.is() )
|
|
return;
|
|
|
|
m_aErrors = SQLException();
|
|
|
|
|
|
// Determine statement type ...
|
|
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("VIEW");
|
|
static const ::rtl::OUString s_sTableTypeTable("TABLE");
|
|
static const ::rtl::OUString s_sWildcard( "%" );
|
|
|
|
// 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.isEmpty() ? makeAny( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _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;
|
|
|
|
::rtl::Reference< 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.isEmpty() ) )
|
|
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.isEmpty() )
|
|
{
|
|
OSL_FAIL( "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);
|
|
|
|
// Get table name
|
|
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.isEmpty() )
|
|
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 && // Expression with brackets
|
|
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 logic operation:
|
|
i_pJoinCondition->count() == 3)
|
|
{
|
|
// Only allow AND logic operation
|
|
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: error in the 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);
|
|
// All columns in the 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_FAIL( "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_FAIL( "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++)
|
|
{ // Process FROM clause
|
|
aTableRange = ::rtl::OUString();
|
|
|
|
const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i);
|
|
if ( isTableNode( pTableListElement ) )
|
|
{
|
|
traverseOneTableName( _rTables, pTableListElement, aTableRange );
|
|
}
|
|
else if ( SQL_ISRULE( pTableListElement, table_ref ) )
|
|
{
|
|
// Table refereneces can be made up of table names, table names (+),'('joined_table')'(+)
|
|
pTableName = pTableListElement->getChild(0);
|
|
if( isTableNode( pTableName ) )
|
|
{ // Found table names
|
|
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))
|
|
{ // Function
|
|
_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" );
|
|
// See if all columns belong to one table
|
|
if (SQL_ISRULE(pNode,column_ref))
|
|
{
|
|
::rtl::OUString aColName, aTableRange;
|
|
getColumnRange(pNode, aColName, aTableRange);
|
|
if (aTableRange.isEmpty()) // None found
|
|
{
|
|
// Look for the columns in the tables
|
|
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.isEmpty())
|
|
return sal_False;
|
|
}
|
|
|
|
|
|
if (rTableRange.isEmpty())
|
|
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;
|
|
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() )
|
|
{
|
|
sal_Int32 nLen = pParams->getChild(1)->getTokenValue().toInt32();
|
|
(void)nLen;
|
|
}
|
|
}
|
|
else if(pDatatype && pDatatype->getNodeType() == SQL_NODE_KEYWORD)
|
|
{
|
|
aTypeName = ::rtl::OUString("VARCHAR");
|
|
}
|
|
|
|
if (!aTypeName.isEmpty())
|
|
{
|
|
//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(),
|
|
::rtl::OUString(),::rtl::OUString(),::rtl::OUString());
|
|
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: more checks for correct structure!
|
|
if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*"))
|
|
{
|
|
// SELECT * ...
|
|
setSelectColumnName(m_aSelectColumns,::rtl::OUString("*"), 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),"*"))
|
|
{
|
|
// All the table's columns
|
|
::rtl::OUString aTableRange;
|
|
pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, NULL, sal_False, sal_False );
|
|
setSelectColumnName(m_aSelectColumns,::rtl::OUString("*"), aEmptyString,aTableRange);
|
|
continue;
|
|
}
|
|
else if (SQL_ISRULE(pColumnRef,derived_column))
|
|
{
|
|
::rtl::OUString aColumnAlias(getColumnAlias(pColumnRef)); // can be empty
|
|
::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.isEmpty(),"Column name must not be empty!");
|
|
}
|
|
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))*/
|
|
{
|
|
// Function call present
|
|
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
|
|
|
|
// Do all involved columns of the function belong to one table?
|
|
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.isEmpty())
|
|
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 (and TableRange):
|
|
if(SQL_ISRULE(pColumnRef,column_ref))
|
|
getColumnRange(pColumnRef,sColumnName,aTableRange);
|
|
else // an expression
|
|
pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, NULL, sal_False, sal_False );
|
|
|
|
OSL_ENSURE(!sColumnName.isEmpty(),"sColumnName must not be empty!");
|
|
}
|
|
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( "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;
|
|
|
|
|
|
// Analyse parse tree (depending on statement type)
|
|
// and set pointer to WHERE clause:
|
|
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_FAIL("OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
|
|
} else {
|
|
// Other statement, no selection criteria
|
|
return false;
|
|
}
|
|
|
|
if (! SQL_ISRULE(pWhereClause,where_clause)) {
|
|
// The WHERE clause is optional most of the time; which means it could be a "optional_where_clause".
|
|
OSL_ENSURE(SQL_ISRULE(pWhereClause,opt_where_clause),"OSQLParseTreeIterator: error in parse tree!");
|
|
return false;
|
|
}
|
|
|
|
// But if it's a where_clause, then it must not be empty
|
|
OSL_ENSURE(pWhereClause->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
|
|
|
|
OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
|
|
OSL_ENSURE(pComparisonPredicate != NULL,"OSQLParseTreeIterator: error in parse tree!");
|
|
|
|
//
|
|
// Process the comparison criteria now (recursively, for a start everything is an OR criterion)
|
|
//
|
|
|
|
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),")")
|
|
)
|
|
{
|
|
// Round brackets around the expression
|
|
traverseORCriteria(pSearchCondition->getChild(1));
|
|
} else if (SQL_ISRULE(pSearchCondition,search_condition) &&
|
|
pSearchCondition->count() == 3 &&
|
|
SQL_ISTOKEN(pSearchCondition->getChild(1),OR))
|
|
{
|
|
// OR logic operation
|
|
for (int i = 0; i < 3; i++) {
|
|
if (i == 1) continue; // Skip OR keyword
|
|
|
|
// Is the first element an OR again?
|
|
if (i == 0 &&
|
|
SQL_ISRULE(pSearchCondition->getChild(0),search_condition) &&
|
|
pSearchCondition->getChild(0)->count() == 3 &&
|
|
SQL_ISTOKEN(pSearchCondition->getChild(0)->getChild(1),OR))
|
|
{
|
|
// Then process recursively
|
|
traverseORCriteria(pSearchCondition->getChild(0));
|
|
|
|
} else {
|
|
// AND criteria
|
|
traverseANDCriteria(pSearchCondition->getChild(i));
|
|
// if (! aIteratorStatus.IsSuccessful()) break;
|
|
}
|
|
|
|
// if (! aIteratorStatus.IsSuccessful()) break;
|
|
}
|
|
} else {
|
|
// Only *one* criterion or one AND logical operation of criteria
|
|
// Process the AND criteria directly
|
|
traverseANDCriteria(pSearchCondition);
|
|
// if (! aIteratorStatus.IsSuccessful()) return;
|
|
}
|
|
|
|
// Just pass on the error
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
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),")")
|
|
)
|
|
{
|
|
// Round brackets
|
|
traverseANDCriteria(pSearchCondition->getChild(1));
|
|
}
|
|
// The first element is an OR logical operation
|
|
else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 )
|
|
{
|
|
// Then process recursively (use the same row) ...
|
|
traverseORCriteria(pSearchCondition->getChild(0));
|
|
// if (! aIteratorStatus.IsSuccessful())
|
|
// return;
|
|
|
|
// Continue with the right child
|
|
traverseANDCriteria(pSearchCondition->getChild(2));
|
|
}
|
|
// The first element is an AND logical operation (again)
|
|
else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 )
|
|
{
|
|
// Then process recursively (use the same row)
|
|
traverseANDCriteria(pSearchCondition->getChild(0));
|
|
// if (! aIteratorStatus.IsSuccessful())
|
|
// return;
|
|
|
|
// Continue with the right child
|
|
traverseANDCriteria(pSearchCondition->getChild(2));
|
|
}
|
|
// Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.)
|
|
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())
|
|
// Normal value
|
|
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));
|
|
}
|
|
// Just pass on the error
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
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.isEmpty()
|
|
? _rColumnAlias
|
|
: !_aColumnName.isEmpty()
|
|
? _aColumnName
|
|
: ::rtl::OUString("?");
|
|
}
|
|
else if (SQL_ISPUNCTUATION(pMark,":"))
|
|
{
|
|
sParameterName = _pParseNode->getChild(1)->getTokenValue();
|
|
}
|
|
else if (SQL_ISPUNCTUATION(pMark,"["))
|
|
{
|
|
sParameterName = _pParseNode->getChild(1)->getTokenValue();
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL("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(),
|
|
::rtl::OUString(),
|
|
::rtl::OUString(),
|
|
::rtl::OUString());
|
|
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.isEmpty())// 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(),
|
|
::rtl::OUString(),
|
|
::rtl::OUString(),
|
|
::rtl::OUString());
|
|
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 (and 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 implementations
|
|
|
|
//-----------------------------------------------------------------------------
|
|
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("Table"),
|
|
::rtl::OUString("New Created Table"),
|
|
rSchemaName,
|
|
rCatalogName
|
|
);
|
|
return aReturnTable;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void OSQLParseTreeIterator::appendColumns(::rtl::Reference<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()
|
|
, getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
|
|
, getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
|
|
, getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))));
|
|
|
|
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(::rtl::Reference<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.isEmpty())
|
|
{ // 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.isEmpty() )
|
|
{ // 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.isEmpty() )
|
|
{ // 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("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(),
|
|
::rtl::OUString(),
|
|
::rtl::OUString(),
|
|
::rtl::OUString()
|
|
);
|
|
|
|
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(),
|
|
::rtl::OUString(),::rtl::OUString(),::rtl::OUString());
|
|
pColumn->setFunction(sal_True);
|
|
pColumn->setAggregateFunction(bAggFkt);
|
|
pColumn->setRealName(rColumnName);
|
|
|
|
Reference< XPropertySet> xCol = pColumn;
|
|
_rColumns->get().push_back(xCol);
|
|
}
|
|
}
|
|
else // ColumnName and TableName exist
|
|
{
|
|
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(),
|
|
::rtl::OUString(),::rtl::OUString(),::rtl::OUString());
|
|
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;
|
|
|
|
// Table does not exist or lacking field
|
|
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(),
|
|
::rtl::OUString(),::rtl::OUString(),::rtl::OUString());
|
|
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 ? "true" : "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 ? "true" : "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;
|
|
|
|
// Analyse parse tree (depending on statement type)
|
|
// and set pointer to WHERE clause:
|
|
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;
|
|
|
|
// Analyse parse tree (depending on statement type)
|
|
// and set pointer to ORDER clause:
|
|
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);
|
|
// If it is a order_by, it must not be empty
|
|
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;
|
|
|
|
// Analyse parse tree (depending on statement type)
|
|
// and set pointer to ORDER clause:
|
|
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);
|
|
// If it is an order_by, it must not be empty
|
|
if(pGroupClause->count() != 3)
|
|
pGroupClause = NULL;
|
|
return pGroupClause;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const
|
|
{
|
|
if (!m_pParseTree || getStatementType() != SQL_STATEMENT_SELECT)
|
|
return NULL;
|
|
|
|
// Analyse parse tree (depending on statement type)
|
|
// and set pointer to ORDER clause:
|
|
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);
|
|
// If it is an order_by, then it must not be empty
|
|
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.isEmpty() )
|
|
{
|
|
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; // This column must only exits once
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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( "#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.isEmpty() )
|
|
{
|
|
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.isEmpty(),"Columnname must not be empty!");
|
|
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;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|