build fix
[LibreOffice.git] / connectivity / source / parse / sqliterator.cxx
blob8e880557793ca55a9da880033888d153b8f7bab1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <connectivity/sqliterator.hxx>
21 #include <connectivity/sdbcx/VTable.hxx>
22 #include <connectivity/sqlparse.hxx>
23 #include "sqlbison.hxx"
24 #include <connectivity/dbtools.hxx>
25 #include <connectivity/sqlerror.hxx>
26 #include <com/sun/star/sdbc/ColumnValue.hpp>
27 #include <com/sun/star/sdbc/DataType.hpp>
28 #include <com/sun/star/sdbc/XRow.hpp>
29 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
30 #include <com/sun/star/sdb/ErrorCondition.hpp>
31 #ifdef SQL_TEST_PARSETREEITERATOR
32 #include <iostream>
33 #endif
34 #include <connectivity/PColumn.hxx>
35 #include <tools/diagnose_ex.h>
36 #include "TConnection.hxx"
37 #include <comphelper/types.hxx>
38 #include <connectivity/dbmetadata.hxx>
39 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
41 #include <iterator>
42 #include <memory>
44 using namespace ::comphelper;
45 using namespace ::connectivity;
46 using namespace ::connectivity::sdbcx;
47 using namespace ::dbtools;
48 using namespace ::connectivity::parse;
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::uno;
51 using namespace ::com::sun::star::container;
52 using namespace ::com::sun::star::sdbcx;
53 using namespace ::com::sun::star::beans;
54 using namespace ::com::sun::star::sdbc;
55 using namespace ::com::sun::star::sdb;
57 namespace connectivity
59 struct OSQLParseTreeIteratorImpl
61 ::std::vector< TNodePair > m_aJoinConditions;
62 Reference< XConnection > m_xConnection;
63 Reference< XDatabaseMetaData > m_xDatabaseMetaData;
64 Reference< XNameAccess > m_xTableContainer;
65 Reference< XNameAccess > m_xQueryContainer;
67 std::shared_ptr< OSQLTables > m_pTables; // all tables which participate in the SQL statement
68 std::shared_ptr< OSQLTables > m_pSubTables; // all tables from sub queries not the tables from the select tables
69 std::shared_ptr< QueryNameSet > m_pForbiddenQueryNames;
71 TraversalParts m_nIncludeMask;
73 bool m_bIsCaseSensitive;
75 OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables )
76 :m_xConnection( _rxConnection )
77 ,m_nIncludeMask( TraversalParts::All )
78 ,m_bIsCaseSensitive( true )
80 OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" );
81 m_xDatabaseMetaData = m_xConnection->getMetaData();
83 m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers();
84 m_pTables.reset( new OSQLTables( m_bIsCaseSensitive ) );
85 m_pSubTables.reset( new OSQLTables( m_bIsCaseSensitive ) );
87 m_xTableContainer = _rxTables;
89 DatabaseMetaData aMetaData( m_xConnection );
90 if ( aMetaData.supportsSubqueriesInFrom() )
92 // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection
93 // service
94 Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY );
95 if ( xSuppQueries.is() )
96 m_xQueryContainer = xSuppQueries->getQueries();
100 public:
101 inline bool isQueryAllowed( const OUString& _rQueryName )
103 if ( !m_pForbiddenQueryNames.get() )
104 return true;
105 if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() )
106 return true;
107 return false;
112 /** helper class for temporarily adding a query name to a list of forbidden query names
114 class ForbidQueryName
116 std::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames;
117 OUString m_sForbiddenQueryName;
119 public:
120 ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, const OUString& _rForbiddenQueryName )
121 :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames )
122 ,m_sForbiddenQueryName( _rForbiddenQueryName )
124 if ( !m_rpAllForbiddenNames.get() )
125 m_rpAllForbiddenNames.reset( new QueryNameSet );
126 m_rpAllForbiddenNames->insert( m_sForbiddenQueryName );
129 ~ForbidQueryName()
131 m_rpAllForbiddenNames->erase( m_sForbiddenQueryName );
136 OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference< XConnection >& _rxConnection,
137 const Reference< XNameAccess >& _rxTables,
138 const OSQLParser& _rParser )
139 :m_rParser( _rParser )
140 ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection, _rxTables ) )
142 setParseTree(nullptr);
146 OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator& _rParentIterator, const OSQLParser& _rParser, const OSQLParseNode* pRoot )
147 :m_rParser( _rParser )
148 ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator.m_pImpl->m_xConnection, _rParentIterator.m_pImpl->m_xTableContainer ) )
150 m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames;
151 setParseTree( pRoot );
155 OSQLParseTreeIterator::~OSQLParseTreeIterator()
157 dispose();
161 const OSQLTables& OSQLParseTreeIterator::getTables() const
163 return *m_pImpl->m_pTables;
167 bool OSQLParseTreeIterator::isCaseSensitive() const
169 return m_pImpl->m_bIsCaseSensitive;
173 void OSQLParseTreeIterator::dispose()
175 m_aSelectColumns = nullptr;
176 m_aGroupColumns = nullptr;
177 m_aOrderColumns = nullptr;
178 m_aParameters = nullptr;
179 m_pImpl->m_xTableContainer = nullptr;
180 m_pImpl->m_xDatabaseMetaData = nullptr;
181 m_aCreateColumns = nullptr;
182 m_pImpl->m_pTables->clear();
183 m_pImpl->m_pSubTables->clear();
186 void OSQLParseTreeIterator::setParseTree(const OSQLParseNode * pNewParseTree)
188 m_pImpl->m_pTables->clear();
189 m_pImpl->m_pSubTables->clear();
191 m_aSelectColumns = new OSQLColumns();
192 m_aGroupColumns = new OSQLColumns();
193 m_aOrderColumns = new OSQLColumns();
194 m_aParameters = new OSQLColumns();
195 m_aCreateColumns = new OSQLColumns();
197 m_pParseTree = pNewParseTree;
198 if (!m_pParseTree)
200 m_eStatementType = OSQLStatementType::Unknown;
201 return;
204 // If m_pParseTree, but no connection then return
205 if ( !m_pImpl->m_xTableContainer.is() )
206 return;
208 m_aErrors = SQLException();
211 // Determine statement type ...
212 if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) )
214 m_eStatementType = OSQLStatementType::Select;
216 else if (SQL_ISRULE(m_pParseTree,insert_statement))
218 m_eStatementType = OSQLStatementType::Insert;
220 else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
222 m_eStatementType = OSQLStatementType::Update;
224 else if (SQL_ISRULE(m_pParseTree,delete_statement_searched))
226 m_eStatementType = OSQLStatementType::Delete;
228 else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec))
230 m_eStatementType = OSQLStatementType::OdbcCall;
232 else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def))
234 m_eStatementType = OSQLStatementType::CreateTable;
235 m_pParseTree = m_pParseTree->getChild(0);
237 else
239 m_eStatementType = OSQLStatementType::Unknown;
240 //aIteratorStatus.setInvalidStatement();
241 return;
246 namespace
249 void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, OUString& _out_rString )
251 _out_rString = _rxRow->getString( _nColumnIndex );
252 if ( _rxRow->wasNull() )
253 _out_rString.clear();
257 OUString lcl_findTableInMetaData(
258 const Reference< XDatabaseMetaData >& _rxDBMeta, const OUString& _rCatalog,
259 const OUString& _rSchema, const OUString& _rTableName )
261 OUString sComposedName;
263 static const char s_sWildcard[] = "%" ;
265 // we want all catalogues, all schemas, all tables
266 Sequence< OUString > sTableTypes(3);
267 sTableTypes[0] = "VIEW";
268 sTableTypes[1] = "TABLE";
269 sTableTypes[2] = s_sWildcard; // just to be sure to include anything else ....
271 if ( _rxDBMeta.is() )
273 sComposedName.clear();
275 Reference< XResultSet> xRes = _rxDBMeta->getTables(
276 !_rCatalog.isEmpty() ? makeAny( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _rSchema : s_sWildcard, _rTableName, sTableTypes );
278 Reference< XRow > xCurrentRow( xRes, UNO_QUERY );
279 if ( xCurrentRow.is() && xRes->next() )
281 OUString sCatalog, sSchema, sName;
283 impl_getRowString( xCurrentRow, 1, sCatalog );
284 impl_getRowString( xCurrentRow, 2, sSchema );
285 impl_getRowString( xCurrentRow, 3, sName );
287 sComposedName = ::dbtools::composeTableName(
288 _rxDBMeta,
289 sCatalog,
290 sSchema,
291 sName,
292 false,
293 ::dbtools::EComposeRule::InDataManipulation
297 return sComposedName;
302 void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable& _rQuery )
304 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
305 // parameters not to be included in the traversal
306 return;
308 ::rtl::Reference< OSQLColumns > pSubQueryParameterColumns( new OSQLColumns() );
310 // get the command and the EscapeProcessing properties from the sub query
311 OUString sSubQueryCommand;
312 bool bEscapeProcessing = false;
315 Reference< XPropertySet > xQueryProperties( _rQuery, UNO_QUERY_THROW );
316 OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sSubQueryCommand );
317 OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
319 catch( const Exception& )
321 DBG_UNHANDLED_EXCEPTION();
324 // parse the sub query
325 do {
327 if ( !bEscapeProcessing || ( sSubQueryCommand.isEmpty() ) )
328 break;
330 OUString sError;
331 std::unique_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand ) );
332 if ( !pSubQueryNode.get() )
333 break;
335 OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() );
336 aSubQueryIterator.impl_traverse( TraversalParts::Parameters | TraversalParts::SelectColumns );
337 // SelectColumns might also contain parameters
338 // #i77635# - 2007-07-23 / frank.schoenheit@sun.com
339 pSubQueryParameterColumns = aSubQueryIterator.getParameters();
340 aSubQueryIterator.dispose();
342 } while ( false );
344 // copy the parameters of the sub query to our own parameter array
345 ::std::copy( pSubQueryParameterColumns->get().begin(), pSubQueryParameterColumns->get().end(),
346 ::std::insert_iterator< OSQLColumns::Vector >( m_aParameters->get(), m_aParameters->get().end() ) );
350 OSQLTable OSQLParseTreeIterator::impl_locateRecordSource( const OUString& _rComposedName )
352 if ( _rComposedName.isEmpty() )
354 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" );
355 return OSQLTable();
358 OSQLTable aReturn;
359 OUString sComposedName( _rComposedName );
363 OUString sCatalog, sSchema, sName;
364 qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
366 // check whether there is a query with the given name
367 bool bQueryDoesExist = m_pImpl->m_xQueryContainer.is() && m_pImpl->m_xQueryContainer->hasByName( sComposedName );
369 // check whether the table container contains an object with the given name
370 if ( !bQueryDoesExist && !m_pImpl->m_xTableContainer->hasByName( sComposedName ) )
371 sComposedName = lcl_findTableInMetaData( m_pImpl->m_xDatabaseMetaData, sCatalog, sSchema, sName );
372 bool bTableDoesExist = m_pImpl->m_xTableContainer->hasByName( sComposedName );
374 // now obtain the object
376 // if we're creating a table, and there already is a table or query with the same name,
377 // this is worth an error
378 if ( OSQLStatementType::CreateTable == m_eStatementType )
380 if ( bQueryDoesExist )
381 impl_appendError( IParseContext::ErrorCode::InvalidQueryExist, &sName );
382 else if ( bTableDoesExist )
383 impl_appendError( IParseContext::ErrorCode::InvalidTableExist, &sName );
384 else
385 aReturn = impl_createTableObject( sName, sCatalog, sSchema );
387 else
389 // queries win over tables, so if there's a query with this name, take this, no matter if
390 // there's a table, too
391 if ( bQueryDoesExist )
393 if ( !m_pImpl->isQueryAllowed( sComposedName ) )
395 impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, nullptr ) );
396 return nullptr;
399 m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn;
401 // collect the parameters from the sub query
402 ForbidQueryName aForbidName( *m_pImpl, sComposedName );
403 impl_getQueryParameterColumns( aReturn );
405 else if ( bTableDoesExist )
406 m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn;
407 else
409 if ( m_pImpl->m_xQueryContainer.is() )
410 // the connection on which we're working supports sub queries in from (else
411 // m_xQueryContainer would not have been set), so emit a better error message
412 impl_appendError( IParseContext::ErrorCode::InvalidTableOrQuery, &sName );
413 else
414 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sName );
418 catch(Exception&)
420 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sComposedName );
423 return aReturn;
427 void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const OUString & rTableRange )
429 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::TableNames ) )
430 // tables should not be included in the traversal
431 return;
433 OSL_ENSURE(pTableName != nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
435 Any aCatalog;
436 OUString aSchema,aTableName,aComposedName;
437 OUString aTableRange(rTableRange);
439 // Get table name
440 OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData);
442 // create the composed name like DOMAIN.USER.TABLE1
443 aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData,
444 aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : OUString(),
445 aSchema,
446 aTableName,
447 false,
448 ::dbtools::EComposeRule::InDataManipulation);
450 // if there is no alias for the table name assign the orignal name to it
451 if ( aTableRange.isEmpty() )
452 aTableRange = aComposedName;
454 // get the object representing this table/query
455 OSQLTable aTable = impl_locateRecordSource( aComposedName );
456 if ( aTable.is() )
457 _rTables[ aTableRange ] = aTable;
460 void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode* i_pJoinCondition)
462 if (i_pJoinCondition->count() == 3 && // Expression with brackets
463 SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") &&
464 SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")"))
466 impl_fillJoinConditions(i_pJoinCondition->getChild(1));
468 else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR logic operation:
469 i_pJoinCondition->count() == 3)
471 // Only allow AND logic operation
472 if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) )
474 impl_fillJoinConditions(i_pJoinCondition->getChild(0));
475 impl_fillJoinConditions(i_pJoinCondition->getChild(1));
478 else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate))
480 // only the comparison of columns is allowed
481 OSL_ENSURE(i_pJoinCondition->count() == 3,"OQueryDesignView::InsertJoinConnection: error in the parse tree");
482 if (SQL_ISRULE(i_pJoinCondition->getChild(0),column_ref) &&
483 SQL_ISRULE(i_pJoinCondition->getChild(2),column_ref) &&
484 i_pJoinCondition->getChild(1)->getNodeType() == SQLNodeType::Equal)
486 m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) );
491 ::std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const
493 return m_pImpl->m_aJoinConditions;
496 void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, OUString& aTableRange )
498 OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) ,
499 "OSQLParseTreeIterator::getQualified_join: illegal node!" );
501 aTableRange.clear();
503 const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange);
504 if ( isTableNode( pNode ) )
505 traverseOneTableName( _rTables, pNode, aTableRange );
507 sal_uInt32 nPos = 4;
508 if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL)
510 nPos = 3;
511 // join_condition,named_columns_join
512 if ( SQL_ISRULE( pTableRef, qualified_join ) )
514 const OSQLParseNode* pJoin_spec = pTableRef->getChild(4);
515 if ( SQL_ISRULE( pJoin_spec, join_condition ) )
517 impl_fillJoinConditions(pJoin_spec->getChild(1));
519 else
521 const OSQLParseNode* pColumnCommalist = pJoin_spec->getChild(2);
522 // All columns in the column_commalist ...
523 for (size_t i = 0; i < pColumnCommalist->count(); i++)
525 const OSQLParseNode * pCol = pColumnCommalist->getChild(i);
526 // add twice because the column must exists in both tables
527 m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) );
533 pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange);
534 if ( isTableNode( pNode ) )
535 traverseOneTableName( _rTables, pNode, aTableRange );
538 const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,OUString& rTableRange )
540 OSL_PRECOND( SQL_ISRULE( pTableRef, table_ref ) || SQL_ISRULE( pTableRef, joined_table )
541 || SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ),
542 "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" );
544 const OSQLParseNode* pTableNameNode = nullptr;
546 if ( SQL_ISRULE( pTableRef, joined_table ) )
548 getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
550 if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) )
552 getQualified_join( _rTables, pTableRef, rTableRange );
554 else
556 rTableRange = OSQLParseNode::getTableRange(pTableRef);
557 if ( ( pTableRef->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
558 || ( pTableRef->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist
561 getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange );
563 else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')'
565 const OSQLParseNode* pSubQuery = pTableRef->getChild(0);
566 if ( pSubQuery->isToken() )
568 getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
570 else
572 OSL_ENSURE( pSubQuery->count() == 3, "sub queries should have 3 children!" );
573 const OSQLParseNode* pQueryExpression = pSubQuery->getChild(1);
574 if ( SQL_ISRULE( pQueryExpression, select_statement ) )
576 getSelect_statement( *m_pImpl->m_pSubTables, pQueryExpression );
577 // LEM TODO: now, we need to setup a OSQLTable from pQueryExpression in some way
578 // and stick it in _rTables[rTableRange]. Probably fake it by
579 // setting up a full OSQLParseTreeIterator on pQueryExpression
580 // and using its m_aSelectColumns
581 // This is necessary in stuff like "SELECT * FROM tbl1 INNER JOIN (SELECT foo, bar FROM tbl2) AS tbl3"
582 // so that setSelectColumnName() can expand the "*" correctly.
583 // See e.g. R_UserAndLastSubscription query of https://bugs.libreoffice.org/attachment.cgi?id=71871
585 else
587 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" );
591 else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column
593 pTableNameNode = pTableRef->getChild(0);
595 else
596 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" );
599 return pTableNameNode;
602 void OSQLParseTreeIterator::getSelect_statement(OSQLTables& _rTables,const OSQLParseNode* pSelect)
604 if(SQL_ISRULE(pSelect,union_statement))
606 getSelect_statement(_rTables,pSelect->getChild(0));
607 //getSelect_statement(pSelect->getChild(3));
608 return;
610 OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1);
612 OSL_ENSURE(pTableRefCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
613 OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!");
615 const OSQLParseNode* pTableName = nullptr;
616 OUString aTableRange;
617 for (size_t i = 0; i < pTableRefCommalist->count(); i++)
618 { // Process FROM clause
619 aTableRange.clear();
621 const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i);
622 if ( isTableNode( pTableListElement ) )
624 traverseOneTableName( _rTables, pTableListElement, aTableRange );
626 else if ( SQL_ISRULE( pTableListElement, table_ref ) )
628 // Table references can be made up of table names, table names (+),'('joined_table')'(+)
629 pTableName = pTableListElement->getChild(0);
630 if( isTableNode( pTableName ) )
631 { // Found table names
632 aTableRange = OSQLParseNode::getTableRange(pTableListElement);
633 traverseOneTableName( _rTables, pTableName, aTableRange );
635 else if(SQL_ISPUNCTUATION(pTableName,"{"))
636 { // '{' SQL_TOKEN_OJ joined_table '}'
637 getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange );
639 else
640 { // '(' joined_table ')' range_variable op_column_commalist
641 getTableNode( _rTables, pTableListElement, aTableRange );
644 else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) )
646 getQualified_join( _rTables, pTableListElement, aTableRange );
648 else if ( SQL_ISRULE( pTableListElement, joined_table ) )
650 getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange );
653 // if (! aIteratorStatus.IsSuccessful()) break;
657 bool OSQLParseTreeIterator::traverseTableNames(OSQLTables& _rTables)
659 if ( m_pParseTree == nullptr )
660 return false;
662 OSQLParseNode* pTableName = nullptr;
664 switch ( m_eStatementType )
666 case OSQLStatementType::Select:
667 getSelect_statement( _rTables, m_pParseTree );
668 break;
670 case OSQLStatementType::CreateTable:
671 case OSQLStatementType::Insert:
672 case OSQLStatementType::Delete:
673 pTableName = m_pParseTree->getChild(2);
674 break;
676 case OSQLStatementType::Update:
677 pTableName = m_pParseTree->getChild(1);
678 break;
679 default:
680 break;
683 if ( pTableName )
685 OUString sTableRange;
686 traverseOneTableName( _rTables, pTableName, sTableRange );
689 return !hasErrors();
692 OUString OSQLParseTreeIterator::getColumnAlias(const OSQLParseNode* _pDerivedColumn)
694 OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!");
695 OUString sColumnAlias;
696 if(_pDerivedColumn->getChild(1)->count() == 2)
697 sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue();
698 else if(!_pDerivedColumn->getChild(1)->isRule())
699 sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue();
700 return sColumnAlias;
704 namespace
706 void lcl_getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection,
707 OUString& _out_rColumnName, OUString& _out_rTableRange,
708 const OSQLColumns* _pSelectColumns, OUString& _out_rColumnAliasIfPresent )
710 _out_rColumnName.clear();
711 _out_rTableRange.clear();
712 _out_rColumnAliasIfPresent.clear();
713 if ( SQL_ISRULE( _pColumnRef, column_ref ) )
715 if( _pColumnRef->count() > 1 )
717 for ( sal_Int32 i=0; i<((sal_Int32)_pColumnRef->count())-2; ++i )
718 _pColumnRef->getChild(i)->parseNodeToStr( _out_rTableRange, _rxConnection, nullptr, false, false );
719 _out_rColumnName = _pColumnRef->getChild( _pColumnRef->count()-1 )->getChild(0)->getTokenValue();
721 else
722 _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue();
724 // look up the column in the select column, to find an possible alias
725 if ( _pSelectColumns )
727 for ( OSQLColumns::Vector::const_iterator lookupColumn = _pSelectColumns->get().begin();
728 lookupColumn != _pSelectColumns->get().end();
729 ++lookupColumn
732 Reference< XPropertySet > xColumn( *lookupColumn );
735 OUString sName, sTableName;
736 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) >>= sName;
737 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName;
738 if ( sName == _out_rColumnName && ( _out_rTableRange.isEmpty() || sTableName == _out_rTableRange ) )
740 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent;
741 break;
744 catch( const Exception& )
746 DBG_UNHANDLED_EXCEPTION();
751 else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec))
752 { // Function
753 _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection );
755 else if(_pColumnRef->getNodeType() == SQLNodeType::Name)
756 _out_rColumnName = _pColumnRef->getTokenValue();
761 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
762 OUString& _rColumnName,
763 OUString& _rTableRange) const
765 OUString sDummy;
766 lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, nullptr, sDummy );
770 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
771 OUString& _rColumnName,
772 OUString& _rTableRange,
773 OUString& _out_rColumnAliasIfPresent ) const
775 lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent );
779 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
780 const Reference< XConnection >& _rxConnection, OUString& _out_rColumnName, OUString& _out_rTableRange )
782 OUString sDummy;
783 lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, nullptr, sDummy );
787 bool OSQLParseTreeIterator::getColumnTableRange(const OSQLParseNode* pNode, OUString &rTableRange) const
789 OUString tmp;
790 if(impl_getColumnTableRange(pNode, tmp))
792 rTableRange = tmp;
793 return true;
795 else
796 return false;
799 bool OSQLParseTreeIterator::impl_getColumnTableRange(const OSQLParseNode* pNode, OUString &rTableRange) const
801 // See if all columns belong to one table
802 if (SQL_ISRULE(pNode,column_ref))
804 OUString aColName, aTableRange;
805 getColumnRange(pNode, aColName, aTableRange);
806 if (aTableRange.isEmpty()) // None found
808 // Look for the columns in the tables
809 for (OSQLTables::const_iterator aIter = m_pImpl->m_pTables->begin(); aIter != m_pImpl->m_pTables->end(); ++aIter)
811 if (aIter->second.is())
815 Reference< XNameAccess > xColumns = aIter->second->getColumns();
816 if(xColumns->hasByName(aColName))
818 Reference< XPropertySet > xColumn;
819 if (xColumns->getByName(aColName) >>= xColumn)
821 OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!");
822 aTableRange = aIter->first;
823 break;
827 catch(Exception&)
832 if (aTableRange.isEmpty())
833 return false;
837 if (rTableRange.isEmpty())
838 rTableRange = aTableRange;
839 else if (rTableRange != aTableRange)
840 return false;
842 else
844 for (sal_uInt32 i = 0, ncount = pNode->count(); i < ncount; i++)
846 if (!getColumnTableRange(pNode->getChild(i), rTableRange))
847 return false;
850 return true;
854 void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode* pSelectNode)
856 // aIteratorStatus.Clear();
858 if (!pSelectNode || m_eStatementType != OSQLStatementType::CreateTable || m_pImpl->m_pTables->empty())
860 impl_appendError( IParseContext::ErrorCode::General );
861 return;
863 if (!SQL_ISRULE(pSelectNode,base_table_element_commalist))
864 return ;
866 for (size_t i = 0; i < pSelectNode->count(); i++)
868 OSQLParseNode *pColumnRef = pSelectNode->getChild(i);
870 if (SQL_ISRULE(pColumnRef,column_def))
872 OUString aColumnName;
873 OUString aTypeName;
874 sal_Int32 nType = DataType::VARCHAR;
875 aColumnName = pColumnRef->getChild(0)->getTokenValue();
877 OSQLParseNode *pDatatype = pColumnRef->getChild(1);
878 if (pDatatype && SQL_ISRULE(pDatatype,character_string_type))
880 const OSQLParseNode *pType = pDatatype->getChild(0);
881 aTypeName = pType->getTokenValue();
882 if (pDatatype->count() == 2 && (pType->getTokenID() == SQL_TOKEN_CHAR || pType->getTokenID() == SQL_TOKEN_CHARACTER ))
883 nType = DataType::CHAR;
885 const OSQLParseNode *pParams = pDatatype->getChild(pDatatype->count()-1);
886 if ( pParams->count() )
888 sal_Int32 nLen = pParams->getChild(1)->getTokenValue().toInt32();
889 (void)nLen;
892 else if(pDatatype && pDatatype->getNodeType() == SQLNodeType::Keyword)
894 aTypeName = "VARCHAR";
897 if (!aTypeName.isEmpty())
899 //TODO:Create a new class for create statement to handle field length
900 OParseColumn* pColumn = new OParseColumn(aColumnName,aTypeName,OUString(),OUString(),
901 ColumnValue::NULLABLE_UNKNOWN,0,0,nType,false,false,isCaseSensitive(),
902 OUString(),OUString(),OUString());
903 pColumn->setFunction(false);
904 pColumn->setRealName(aColumnName);
906 Reference< XPropertySet> xCol = pColumn;
907 m_aCreateColumns->get().push_back(xCol);
914 bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode* pSelectNode)
916 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::SelectColumns ) )
917 return true;
919 if (!pSelectNode || m_eStatementType != OSQLStatementType::Select || m_pImpl->m_pTables->empty())
921 impl_appendError( IParseContext::ErrorCode::General );
922 return false;
925 if(SQL_ISRULE(pSelectNode,union_statement))
927 return traverseSelectColumnNames( pSelectNode->getChild( 0 ) )
928 /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/;
931 static OUString aEmptyString;
932 // nyi: more checks for correct structure!
933 if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*"))
935 // SELECT * ...
936 setSelectColumnName(m_aSelectColumns,"*", aEmptyString,aEmptyString);
938 else if (SQL_ISRULE(pSelectNode->getChild(2),scalar_exp_commalist))
940 // SELECT column[,column] oder SELECT COUNT(*) ...
941 OSQLParseNode * pSelection = pSelectNode->getChild(2);
943 for (size_t i = 0; i < pSelection->count(); i++)
945 OSQLParseNode *pColumnRef = pSelection->getChild(i);
947 //if (SQL_ISRULE(pColumnRef,select_sublist))
948 if (SQL_ISRULE(pColumnRef,derived_column) &&
949 SQL_ISRULE(pColumnRef->getChild(0),column_ref) &&
950 pColumnRef->getChild(0)->count() == 3 &&
951 SQL_ISPUNCTUATION(pColumnRef->getChild(0)->getChild(2),"*"))
953 // All the table's columns
954 OUString aTableRange;
955 pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, nullptr, false, false );
956 setSelectColumnName(m_aSelectColumns,"*", aEmptyString,aTableRange);
957 continue;
959 else if (SQL_ISRULE(pColumnRef,derived_column))
961 OUString aColumnAlias(getColumnAlias(pColumnRef)); // can be empty
962 OUString sColumnName;
963 OUString aTableRange;
964 sal_Int32 nType = DataType::VARCHAR;
965 bool bFkt(false);
966 pColumnRef = pColumnRef->getChild(0);
967 while (
968 pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
969 pColumnRef->count() == 3 &&
970 SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
971 SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
973 pColumnRef = pColumnRef->getChild(1);
975 if (SQL_ISRULE(pColumnRef,column_ref))
977 getColumnRange(pColumnRef,sColumnName,aTableRange);
978 OSL_ENSURE(!sColumnName.isEmpty(),"Column name must not be empty!");
980 else /*if (SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec) ||
981 SQL_ISRULE(pColumnRef,position_exp) || SQL_ISRULE(pColumnRef,extract_exp) ||
982 SQL_ISRULE(pColumnRef,length_exp) || SQL_ISRULE(pColumnRef,char_value_fct)||
983 SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term))*/
985 // Function call present
986 pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection );
987 // check if the column is also a parameter
988 traverseSearchCondition(pColumnRef); // num_value_exp
990 if ( pColumnRef->isRule() )
992 // LEM FIXME: the if condition is not quite right
993 // many expressions are rules, e.g. "5+3"
994 // or even: "colName + 1"
995 bFkt = true;
996 nType = getFunctionReturnType(pColumnRef);
1000 else
1002 aIteratorStatus.setStatementTooComplex();
1003 return;
1006 if(aColumnAlias.isEmpty())
1007 aColumnAlias = sColumnName;
1008 setSelectColumnName(m_aSelectColumns,sColumnName,aColumnAlias,aTableRange,bFkt,nType,SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec));
1013 return !hasErrors();
1017 bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode* pSelectNode)
1019 traverseByColumnNames( pSelectNode, true );
1020 return !hasErrors();
1023 void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode* pSelectNode, bool _bOrder)
1025 // aIteratorStatus.Clear();
1027 if (pSelectNode == nullptr)
1029 //aIteratorStatus.setInvalidStatement();
1030 return;
1033 if (m_eStatementType != OSQLStatementType::Select)
1035 //aIteratorStatus.setInvalidStatement();
1036 return;
1039 if(SQL_ISRULE(pSelectNode,union_statement))
1041 traverseByColumnNames(pSelectNode->getChild(0),_bOrder);
1042 return;
1045 OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
1047 OSQLParseNode * pTableExp = pSelectNode->getChild(3);
1048 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1049 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator:table_exp error in parse tree!");
1050 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1052 sal_uInt32 nPos = ( _bOrder ? ORDER_BY_CHILD_POS : 2 );
1054 OSQLParseNode * pOptByClause = pTableExp->getChild(nPos);
1055 OSL_ENSURE(pOptByClause != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1056 if ( pOptByClause->count() == 0 )
1057 return;
1059 OSL_ENSURE(pOptByClause->count() == 3,"OSQLParseTreeIterator: error in parse tree!");
1061 OSQLParseNode * pOrderingSpecCommalist = pOptByClause->getChild(2);
1062 OSL_ENSURE(pOrderingSpecCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1063 OSL_ENSURE(!_bOrder || SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OSQLParseTreeIterator:ordering_spec_commalist error in parse tree!");
1064 OSL_ENSURE(pOrderingSpecCommalist->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
1066 OUString sColumnName;
1067 OUString aTableRange;
1068 sal_uInt32 nCount = pOrderingSpecCommalist->count();
1069 for (sal_uInt32 i = 0; i < nCount; ++i)
1071 OSQLParseNode* pColumnRef = pOrderingSpecCommalist->getChild(i);
1072 OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1073 if ( _bOrder )
1075 OSL_ENSURE(SQL_ISRULE(pColumnRef,ordering_spec),"OSQLParseTreeIterator:ordering_spec error in parse tree!");
1076 OSL_ENSURE(pColumnRef->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1078 pColumnRef = pColumnRef->getChild(0);
1080 OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1081 aTableRange.clear();
1082 sColumnName.clear();
1083 if ( SQL_ISRULE(pColumnRef,column_ref) )
1085 // Column name (and TableRange):
1086 getColumnRange(pColumnRef,sColumnName,aTableRange);
1088 else
1089 { // here I found a predicate
1090 pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
1092 OSL_ENSURE(!sColumnName.isEmpty(),"sColumnName must not be empty!");
1093 if ( _bOrder )
1095 // Ascending/Descending
1096 OSQLParseNode * pOptAscDesc = pColumnRef->getParent()->getChild(1);
1097 OSL_ENSURE(pOptAscDesc != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1099 bool bAscending = ! (pOptAscDesc && SQL_ISTOKEN(pOptAscDesc,DESC));
1100 setOrderByColumnName(sColumnName, aTableRange,bAscending);
1102 else
1103 setGroupByColumnName(sColumnName, aTableRange);
1107 bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode* pSelectNode)
1109 traverseByColumnNames( pSelectNode, false );
1110 return !hasErrors();
1114 namespace
1116 OUString lcl_generateParameterName( const OSQLParseNode& _rParentNode, const OSQLParseNode& _rParamNode )
1118 OUString sColumnName( "param" );
1119 const sal_Int32 nCount = (sal_Int32)_rParentNode.count();
1120 for ( sal_Int32 i = 0; i < nCount; ++i )
1122 if ( _rParentNode.getChild(i) == &_rParamNode )
1124 sColumnName += OUString::number( i+1 );
1125 break;
1128 return sColumnName;
1133 void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode* _pNode)
1135 if ( _pNode == nullptr )
1136 return;
1138 OUString sColumnName, sTableRange, aColumnAlias;
1139 const OSQLParseNode* pParent = _pNode->getParent();
1140 if ( pParent != nullptr )
1142 if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
1144 sal_uInt32 nPos = 0;
1145 if ( pParent->getChild(nPos) == _pNode )
1146 nPos = 2;
1147 const OSQLParseNode* pOther = pParent->getChild(nPos);
1148 if ( SQL_ISRULE( pOther, column_ref ) )
1149 getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
1150 else
1151 pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
1152 } // if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
1153 else if ( SQL_ISRULE(pParent,other_like_predicate_part_2) )
1155 const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
1156 if ( SQL_ISRULE( pOther, column_ref ) )
1157 getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
1158 else
1159 pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
1161 else if ( SQL_ISRULE(pParent,between_predicate_part_2) )
1163 const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
1164 if ( SQL_ISRULE( pOther, column_ref ) )
1165 getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
1166 else
1168 pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
1169 lcl_generateParameterName( *pParent, *_pNode );
1172 else if ( pParent->getNodeType() == SQLNodeType::CommaListRule )
1174 lcl_generateParameterName( *pParent, *_pNode );
1177 traverseParameter( _pNode, pParent, sColumnName, sTableRange, aColumnAlias );
1178 const sal_uInt32 nCount = _pNode->count();
1179 for (sal_uInt32 i = 0; i < nCount; ++i)
1181 const OSQLParseNode* pChild = _pNode->getChild(i);
1182 traverseParameters( pChild );
1186 bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode* pSelectNode)
1188 if ( pSelectNode == nullptr )
1189 return false;
1192 // Analyse parse tree (depending on statement type)
1193 // and set pointer to WHERE clause:
1194 OSQLParseNode * pWhereClause = nullptr;
1196 if (m_eStatementType == OSQLStatementType::Select)
1198 if(SQL_ISRULE(pSelectNode,union_statement))
1200 return traverseSelectionCriteria( pSelectNode->getChild( 0 ) )
1201 && traverseSelectionCriteria( pSelectNode->getChild( 3 ) );
1203 OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
1205 OSQLParseNode * pTableExp = pSelectNode->getChild(3);
1206 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1207 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1208 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1210 pWhereClause = pTableExp->getChild(1);
1211 } else if (SQL_ISRULE(pSelectNode,update_statement_searched)) {
1212 OSL_ENSURE(pSelectNode->count() == 5,"OSQLParseTreeIterator: error in parse tree!");
1213 pWhereClause = pSelectNode->getChild(4);
1214 } else if (SQL_ISRULE(pSelectNode,delete_statement_searched)) {
1215 OSL_ENSURE(pSelectNode->count() == 4,"OSQLParseTreeIterator: error in parse tree!");
1216 pWhereClause = pSelectNode->getChild(3);
1217 } else if (SQL_ISRULE(pSelectNode,delete_statement_positioned)) {
1218 // nyi
1219 SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
1220 } else {
1221 // Other statement, no selection criteria
1222 return false;
1225 if (!pWhereClause || !SQL_ISRULE(pWhereClause,where_clause))
1227 // The WHERE clause is optional most of the time; which means it could be a "optional_where_clause".
1228 OSL_ENSURE(pWhereClause && SQL_ISRULE(pWhereClause,opt_where_clause),"OSQLParseTreeIterator: error in parse tree!");
1229 return false;
1232 // But if it's a where_clause, then it must not be empty
1233 OSL_ENSURE(pWhereClause->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1235 OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
1236 OSL_ENSURE(pComparisonPredicate != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1239 // Process the comparison criteria now
1242 traverseSearchCondition(pComparisonPredicate);
1244 return !hasErrors();
1248 void OSQLParseTreeIterator::traverseSearchCondition(OSQLParseNode * pSearchCondition)
1250 if (
1251 SQL_ISRULE(pSearchCondition,boolean_primary) &&
1252 pSearchCondition->count() == 3 &&
1253 SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
1254 SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")
1257 // Round brackets
1258 traverseSearchCondition(pSearchCondition->getChild(1));
1260 // The first element is an OR logical operation
1261 else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 )
1263 // if this assert fails, the SQL grammar has changed!
1264 assert(SQL_ISTOKEN(pSearchCondition->getChild(1),OR));
1265 // Then process recursively (use the same row) ...
1266 traverseSearchCondition(pSearchCondition->getChild(0));
1267 // if (! aIteratorStatus.IsSuccessful())
1268 // return;
1270 // Continue with the right child
1271 traverseSearchCondition(pSearchCondition->getChild(2));
1273 // The first element is an AND logical operation (again)
1274 else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 )
1276 // Then process recursively (use the same row)
1277 traverseSearchCondition(pSearchCondition->getChild(0));
1278 // if (! aIteratorStatus.IsSuccessful())
1279 // return;
1281 // Continue with the right child
1282 traverseSearchCondition(pSearchCondition->getChild(2));
1284 // Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.)
1285 else if (SQL_ISRULE(pSearchCondition,comparison_predicate) )
1287 OUString aValue;
1288 pSearchCondition->getChild(2)->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
1289 traverseOnePredicate(pSearchCondition->getChild(0),aValue,pSearchCondition->getChild(2));
1290 impl_fillJoinConditions(pSearchCondition);
1291 // if (! aIteratorStatus.IsSuccessful())
1292 // return;
1294 else if (SQL_ISRULE(pSearchCondition,like_predicate) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
1296 OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1297 const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
1299 sal_Int32 nCurentPos = pPart2->count()-2;
1301 OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurentPos);
1302 OSQLParseNode * pOptEscape = pPart2->getChild(nCurentPos+1);
1304 OSL_ENSURE(pNum_value_exp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1305 OSL_ENSURE(pOptEscape != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1307 if (pOptEscape->count() != 0)
1309 // aIteratorStatus.setStatementTooComplex();
1310 return;
1313 OUString aValue;
1314 OSQLParseNode * pParam = nullptr;
1315 if (SQL_ISRULE(pNum_value_exp,parameter))
1316 pParam = pNum_value_exp;
1317 else if(pNum_value_exp->isToken())
1318 // Normal value
1319 aValue = pNum_value_exp->getTokenValue();
1320 else
1322 pNum_value_exp->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
1323 pParam = pNum_value_exp;
1326 traverseOnePredicate(pSearchCondition->getChild(0),aValue,pParam);
1327 // if (! aIteratorStatus.IsSuccessful())
1328 // return;
1330 else if (SQL_ISRULE(pSearchCondition,in_predicate))
1332 OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1333 const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
1335 traverseSearchCondition(pSearchCondition->getChild(0));
1336 // if (! aIteratorStatus.IsSuccessful()) return;
1338 OSQLParseNode* pChild = pPart2->getChild(2);
1339 if ( SQL_ISRULE(pChild->getChild(0),subquery) )
1341 traverseTableNames( *m_pImpl->m_pSubTables );
1342 traverseSelectionCriteria(pChild->getChild(0)->getChild(1));
1344 else
1345 { // '(' value_exp_commalist ')'
1346 pChild = pChild->getChild(1);
1347 sal_Int32 nCount = pChild->count();
1348 for (sal_Int32 i=0; i < nCount; ++i)
1350 traverseSearchCondition(pChild->getChild(i));
1354 else if (SQL_ISRULE(pSearchCondition,test_for_null) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
1356 OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1357 const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
1358 (void)pPart2;
1359 OSL_ENSURE(SQL_ISTOKEN(pPart2->getChild(0),IS),"OSQLParseTreeIterator: error in parse tree!");
1361 OUString aString;
1362 traverseOnePredicate(pSearchCondition->getChild(0),aString,nullptr);
1363 // if (! aIteratorStatus.IsSuccessful()) return;
1365 else if (SQL_ISRULE(pSearchCondition,num_value_exp) || SQL_ISRULE(pSearchCondition,term))
1367 OUString aString;
1368 traverseOnePredicate(pSearchCondition->getChild(0),aString,pSearchCondition->getChild(0));
1369 traverseOnePredicate(pSearchCondition->getChild(2),aString,pSearchCondition->getChild(2));
1371 // Just pass on the error
1374 void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode* _pParseNode
1375 ,const OSQLParseNode* _pParentNode
1376 ,const OUString& _aColumnName
1377 ,OUString& _aTableRange
1378 ,const OUString& _rColumnAlias)
1380 if ( !SQL_ISRULE( _pParseNode, parameter ) )
1381 return;
1383 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
1384 // parameters not to be included in the traversal
1385 return;
1387 OSL_ENSURE(_pParseNode->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
1388 OSQLParseNode * pMark = _pParseNode->getChild(0);
1389 OUString sParameterName;
1391 if (SQL_ISPUNCTUATION(pMark,"?"))
1393 sParameterName = !_rColumnAlias.isEmpty()
1394 ? _rColumnAlias
1395 : !_aColumnName.isEmpty()
1396 ? _aColumnName
1397 : OUString("?");
1399 else if (SQL_ISPUNCTUATION(pMark,":"))
1401 sParameterName = _pParseNode->getChild(1)->getTokenValue();
1403 else if (SQL_ISPUNCTUATION(pMark,"["))
1405 sParameterName = _pParseNode->getChild(1)->getTokenValue();
1407 else
1409 SAL_WARN( "connectivity.parse","OSQLParseTreeIterator: error in parse tree!");
1412 // found a parameter
1413 if ( _pParentNode && (SQL_ISRULE(_pParentNode,general_set_fct) || SQL_ISRULE(_pParentNode,set_fct_spec)) )
1414 {// found a function as column_ref
1415 OUString sFunctionName;
1416 _pParentNode->getChild(0)->parseNodeToStr( sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
1417 const sal_uInt32 nCount = _pParentNode->count();
1418 sal_uInt32 i = 0;
1419 for(; i < nCount;++i)
1421 if ( _pParentNode->getChild(i) == _pParseNode )
1422 break;
1424 sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode->getChild(0)->getTokenID(), i-1);
1426 OParseColumn* pColumn = new OParseColumn( sParameterName,
1427 OUString(),
1428 OUString(),
1429 OUString(),
1430 ColumnValue::NULLABLE_UNKNOWN,
1433 nType,
1434 false,
1435 false,
1436 isCaseSensitive(),
1437 OUString(),
1438 OUString(),
1439 OUString());
1440 pColumn->setFunction(true);
1441 pColumn->setAggregateFunction(true);
1442 pColumn->setRealName(sFunctionName);
1443 m_aParameters->get().push_back(pColumn);
1445 else
1447 bool bNotFound = true;
1448 OSQLColumns::Vector::const_iterator aIter = ::connectivity::find(
1449 m_aSelectColumns->get().begin(),
1450 m_aSelectColumns->get().end(),
1451 _aColumnName,::comphelper::UStringMixEqual( isCaseSensitive() )
1453 if(aIter != m_aSelectColumns->get().end())
1455 OParseColumn* pNewColumn = new OParseColumn(*aIter,isCaseSensitive());
1456 pNewColumn->setName(sParameterName);
1457 pNewColumn->setRealName(_aColumnName);
1458 m_aParameters->get().push_back(pNewColumn);
1459 bNotFound = false;
1461 else if(!_aColumnName.isEmpty())// search in the tables for the right one
1464 Reference<XPropertySet> xColumn = findColumn( _aColumnName, _aTableRange, true );
1466 if ( xColumn.is() )
1468 OParseColumn* pNewColumn = new OParseColumn(xColumn,isCaseSensitive());
1469 pNewColumn->setName(sParameterName);
1470 pNewColumn->setRealName(_aColumnName);
1471 m_aParameters->get().push_back(pNewColumn);
1472 bNotFound = false;
1475 if ( bNotFound )
1477 sal_Int32 nType = DataType::VARCHAR;
1478 OSQLParseNode* pParent = _pParentNode ? _pParentNode->getParent() : nullptr;
1479 if ( pParent && (SQL_ISRULE(pParent,general_set_fct) || SQL_ISRULE(pParent,set_fct_spec)) )
1481 const sal_uInt32 nCount = _pParentNode->count();
1482 sal_uInt32 i = 0;
1483 for(; i < nCount;++i)
1485 if ( _pParentNode->getChild(i) == _pParseNode )
1486 break;
1488 nType = ::connectivity::OSQLParser::getFunctionParameterType( pParent->getChild(0)->getTokenID(), i+1);
1491 OUString aNewColName( getUniqueColumnName( sParameterName ) );
1493 OParseColumn* pColumn = new OParseColumn(aNewColName,
1494 OUString(),
1495 OUString(),
1496 OUString(),
1497 ColumnValue::NULLABLE_UNKNOWN,
1500 nType,
1501 false,
1502 false,
1503 isCaseSensitive(),
1504 OUString(),
1505 OUString(),
1506 OUString());
1507 pColumn->setName(aNewColName);
1508 pColumn->setRealName(sParameterName);
1509 m_aParameters->get().push_back(pColumn);
1514 void OSQLParseTreeIterator::traverseOnePredicate(
1515 OSQLParseNode * pColumnRef,
1516 OUString& rValue,
1517 OSQLParseNode * pParseNode)
1519 if ( !pParseNode )
1520 return;
1522 // Column name (and TableRange):
1523 OUString aColumnName, aTableRange, sColumnAlias;
1524 getColumnRange( pColumnRef, aColumnName, aTableRange, sColumnAlias);
1526 OUString aName;
1528 /*if (SQL_ISRULE(pParseNode,parameter))
1529 traverseParameter( pParseNode, pColumnRef, aColumnName, aTableRange, sColumnAlias );
1530 else */if (SQL_ISRULE(pParseNode,column_ref))// Column-Name (und TableRange):
1531 getColumnRange(pParseNode,aName,rValue);
1532 else
1534 traverseSearchCondition(pParseNode);
1535 // if (! aIteratorStatus.IsSuccessful()) return;
1540 void OSQLParseTreeIterator::traverseAll()
1542 impl_traverse( TraversalParts::All );
1546 void OSQLParseTreeIterator::impl_traverse( TraversalParts _nIncludeMask )
1548 // resets our errors
1549 m_aErrors = css::sdbc::SQLException();
1551 m_pImpl->m_nIncludeMask = _nIncludeMask;
1553 if ( !traverseTableNames( *m_pImpl->m_pTables ) )
1554 return;
1556 switch ( m_eStatementType )
1558 case OSQLStatementType::Select:
1560 const OSQLParseNode* pSelectNode = m_pParseTree;
1561 traverseParameters( pSelectNode );
1562 if ( !traverseSelectColumnNames( pSelectNode )
1563 || !traverseOrderByColumnNames( pSelectNode )
1564 || !traverseGroupByColumnNames( pSelectNode )
1565 || !traverseSelectionCriteria( pSelectNode )
1567 return;
1569 break;
1570 case OSQLStatementType::CreateTable:
1572 //0 | 1 | 2 |3| 4 |5
1573 //create table sc.foo ( a char(20), b char )
1574 const OSQLParseNode* pCreateNode = m_pParseTree->getChild(4);
1575 traverseCreateColumns(pCreateNode);
1577 break;
1578 case OSQLStatementType::Insert:
1579 break;
1580 default:
1581 break;
1585 // Dummy implementations
1588 OSQLTable OSQLParseTreeIterator::impl_createTableObject( const OUString& rTableName,
1589 const OUString& rCatalogName, const OUString& rSchemaName )
1591 OSL_PRECOND( m_eStatementType == OSQLStatementType::CreateTable,
1592 "OSQLParseTreeIterator::impl_createTableObject: only to be called for CREATE TABLE statements!" );
1593 // (in all other cases, m_pTables is to contain the table objects as obtained from the tables
1594 // container of the connection (m_xTablesContainer)
1596 OSQLTable aReturnTable = new OTable(
1597 nullptr,
1598 false,
1599 rTableName,
1600 OUString("Table"),
1601 OUString("New Created Table"),
1602 rSchemaName,
1603 rCatalogName
1605 return aReturnTable;
1608 void OSQLParseTreeIterator::appendColumns(::rtl::Reference<OSQLColumns>& _rColumns,const OUString& _rTableAlias,const OSQLTable& _rTable)
1610 if (!_rTable.is())
1611 return;
1613 Reference<XNameAccess> xColumns = _rTable->getColumns();
1614 if ( !xColumns.is() )
1615 return;
1617 Sequence< OUString > aColNames = xColumns->getElementNames();
1618 const OUString* pBegin = aColNames.getConstArray();
1619 const OUString* pEnd = pBegin + aColNames.getLength();
1621 for(;pBegin != pEnd;++pBegin)
1624 OUString aName(getUniqueColumnName(*pBegin));
1625 Reference< XPropertySet > xColumn;
1626 if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is())
1628 OParseColumn* pColumn = new OParseColumn(aName
1629 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
1630 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
1631 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
1632 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
1633 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
1634 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
1635 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
1636 , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
1637 , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
1638 , isCaseSensitive()
1639 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
1640 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
1641 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))));
1643 pColumn->setTableName(_rTableAlias);
1644 pColumn->setRealName(*pBegin);
1645 Reference< XPropertySet> xCol = pColumn;
1646 _rColumns->get().push_back(xCol);
1648 else
1649 impl_appendError( IParseContext::ErrorCode::InvalidColumn, pBegin, &_rTableAlias );
1653 void OSQLParseTreeIterator::setSelectColumnName(::rtl::Reference<OSQLColumns>& _rColumns,const OUString & rColumnName,const OUString & rColumnAlias, const OUString & rTableRange, bool bFkt, sal_Int32 _nType, bool bAggFkt)
1655 if(rColumnName.toChar() == '*' && rTableRange.isEmpty())
1656 { // SELECT * ...
1657 OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!");
1658 for(OSQLTables::const_iterator aIter = m_pImpl->m_pTables->begin(); aIter != m_pImpl->m_pTables->end();++aIter)
1659 appendColumns(_rColumns,aIter->first,aIter->second);
1661 else if( rColumnName.toChar() == '*' && !rTableRange.isEmpty() )
1662 { // SELECT <table>.*
1663 OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!");
1664 OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
1666 if(aFind != m_pImpl->m_pTables->end())
1667 appendColumns(_rColumns,rTableRange,aFind->second);
1669 else if ( rTableRange.isEmpty() )
1670 { // SELECT <something> ...
1671 // without table specified
1672 if ( !bFkt )
1674 Reference< XPropertySet> xNewColumn;
1676 for ( OSQLTables::const_iterator aIter = m_pImpl->m_pTables->begin(); aIter != m_pImpl->m_pTables->end(); ++aIter )
1678 if ( !aIter->second.is() )
1679 continue;
1681 Reference<XNameAccess> xColumns = aIter->second->getColumns();
1682 Reference< XPropertySet > xColumn;
1683 if ( !xColumns->hasByName( rColumnName )
1684 || !( xColumns->getByName( rColumnName ) >>= xColumn )
1686 continue;
1688 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1690 OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive());
1691 xNewColumn = pColumn;
1692 pColumn->setTableName(aIter->first);
1693 pColumn->setName(aNewColName);
1694 pColumn->setRealName(rColumnName);
1696 break;
1699 if ( !xNewColumn.is() )
1701 // no function (due to the above !bFkt), no existing column
1702 // => assume an expression
1703 OUString aNewColName( getUniqueColumnName( rColumnAlias ) );
1704 // did not find a column with this name in any of the tables
1705 OParseColumn* pColumn = new OParseColumn(
1706 aNewColName,
1707 OUString("VARCHAR"),
1708 // TODO: does this match with _nType?
1709 // Or should be fill this from the getTypeInfo of the connection?
1710 OUString(),
1711 OUString(),
1712 ColumnValue::NULLABLE_UNKNOWN,
1715 _nType,
1716 false,
1717 false,
1718 isCaseSensitive(),
1719 OUString(),
1720 OUString(),
1721 OUString()
1724 xNewColumn = pColumn;
1725 pColumn->setRealName( rColumnName );
1728 _rColumns->get().push_back( xNewColumn );
1730 else
1732 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1734 OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1735 ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
1736 OUString(),OUString(),OUString());
1737 pColumn->setFunction(true);
1738 pColumn->setAggregateFunction(bAggFkt);
1739 pColumn->setRealName(rColumnName);
1741 Reference< XPropertySet> xCol = pColumn;
1742 _rColumns->get().push_back(xCol);
1745 else // ColumnName and TableName exist
1747 OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
1749 bool bError = false;
1750 if (aFind != m_pImpl->m_pTables->end() && aFind->second.is())
1752 if (bFkt)
1754 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1756 OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1757 ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
1758 OUString(),OUString(),OUString());
1759 pColumn->setFunction(true);
1760 pColumn->setAggregateFunction(bAggFkt);
1761 pColumn->setRealName(rColumnName);
1762 SAL_WARN("connectivity.parse", "Trying to construct a column with Function==true and a TableName; this makes no sense.");
1763 assert(false);
1764 pColumn->setTableName(aFind->first);
1766 Reference< XPropertySet> xCol = pColumn;
1767 _rColumns->get().push_back(xCol);
1769 else
1771 Reference< XPropertySet > xColumn;
1772 if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn))
1774 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1776 OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive());
1777 pColumn->setName(aNewColName);
1778 pColumn->setRealName(rColumnName);
1779 pColumn->setTableName(aFind->first);
1781 Reference< XPropertySet> xCol = pColumn;
1782 _rColumns->get().push_back(xCol);
1784 else
1785 bError = true;
1788 else
1789 bError = true;
1791 // Table does not exist or lacking field
1792 if (bError)
1794 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1796 OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1797 ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,false,false,isCaseSensitive(),
1798 OUString(),OUString(),OUString());
1799 pColumn->setFunction(true);
1800 pColumn->setAggregateFunction(bAggFkt);
1802 Reference< XPropertySet> xCol = pColumn;
1803 _rColumns->get().push_back(xCol);
1808 OUString OSQLParseTreeIterator::getUniqueColumnName(const OUString & rColumnName) const
1810 OUString aAlias(rColumnName);
1812 OSQLColumns::Vector::const_iterator aIter = find(
1813 m_aSelectColumns->get().begin(),
1814 m_aSelectColumns->get().end(),
1815 aAlias,
1816 ::comphelper::UStringMixEqual( isCaseSensitive() )
1818 sal_Int32 i=1;
1819 while(aIter != m_aSelectColumns->get().end())
1821 (aAlias = rColumnName) += OUString::number(i++);
1822 aIter = find(
1823 m_aSelectColumns->get().begin(),
1824 m_aSelectColumns->get().end(),
1825 aAlias,
1826 ::comphelper::UStringMixEqual( isCaseSensitive() )
1829 return aAlias;
1832 void OSQLParseTreeIterator::setOrderByColumnName(const OUString & rColumnName, OUString & rTableRange, bool bAscending)
1834 Reference<XPropertySet> xColumn = findSelectColumn( rColumnName );
1835 if ( !xColumn.is() )
1836 xColumn = findColumn ( rColumnName, rTableRange, false );
1837 if ( xColumn.is() )
1838 m_aOrderColumns->get().push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) );
1839 else
1841 sal_Int32 nId = rColumnName.toInt32();
1842 if ( nId > 0 && nId < static_cast<sal_Int32>(m_aSelectColumns->get().size()) )
1843 m_aOrderColumns->get().push_back( new OOrderColumn( ( m_aSelectColumns->get() )[nId-1], isCaseSensitive(), bAscending ) );
1846 #ifdef SQL_TEST_PARSETREEITERATOR
1847 cout << "OSQLParseTreeIterator::setOrderByColumnName: "
1848 << (const char *) rColumnName << ", "
1849 << (const char *) rTableRange << ", "
1850 << (bAscending ? "true" : "false")
1851 << "\n";
1852 #endif
1855 void OSQLParseTreeIterator::setGroupByColumnName(const OUString & rColumnName, OUString & rTableRange)
1857 Reference<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false );
1858 if ( xColumn.is() )
1859 m_aGroupColumns->get().push_back(new OParseColumn(xColumn,isCaseSensitive()));
1860 else
1862 sal_Int32 nId = rColumnName.toInt32();
1863 if ( nId > 0 && nId < static_cast<sal_Int32>(m_aSelectColumns->get().size()) )
1864 m_aGroupColumns->get().push_back(new OParseColumn((m_aSelectColumns->get())[nId-1],isCaseSensitive()));
1867 #ifdef SQL_TEST_PARSETREEITERATOR
1868 cout << "OSQLParseTreeIterator::setGroupByColumnName: "
1869 << (const char *) rColumnName << ", "
1870 << (const char *) rTableRange << ", "
1871 << (bAscending ? "true" : "false")
1872 << "\n";
1873 #endif
1877 const OSQLParseNode* OSQLParseTreeIterator::getWhereTree() const
1879 if (!m_pParseTree)
1880 return nullptr;
1882 // Analyse parse tree (depending on statement type)
1883 // and set pointer to WHERE clause:
1884 OSQLParseNode * pWhereClause = nullptr;
1885 if(getStatementType() == OSQLStatementType::Select)
1887 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1888 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1889 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1890 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1891 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1893 pWhereClause = pTableExp->getChild(1);
1895 else if (SQL_ISRULE(m_pParseTree,update_statement_searched) ||
1896 SQL_ISRULE(m_pParseTree,delete_statement_searched))
1898 pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1);
1900 if(pWhereClause && pWhereClause->count() != 2)
1901 pWhereClause = nullptr;
1902 return pWhereClause;
1906 const OSQLParseNode* OSQLParseTreeIterator::getOrderTree() const
1908 if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
1909 return nullptr;
1911 // Analyse parse tree (depending on statement type)
1912 // and set pointer to ORDER clause:
1913 OSQLParseNode * pOrderClause = nullptr;
1914 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1915 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1916 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1917 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1918 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1920 pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
1921 // If it is a order_by, it must not be empty
1922 if(pOrderClause->count() != 3)
1923 pOrderClause = nullptr;
1924 return pOrderClause;
1927 const OSQLParseNode* OSQLParseTreeIterator::getGroupByTree() const
1929 if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
1930 return nullptr;
1932 // Analyse parse tree (depending on statement type)
1933 // and set pointer to ORDER clause:
1934 OSQLParseNode * pGroupClause = nullptr;
1935 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1936 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1937 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1938 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1939 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1941 pGroupClause = pTableExp->getChild(2);
1942 // If it is an order_by, it must not be empty
1943 if(pGroupClause->count() != 3)
1944 pGroupClause = nullptr;
1945 return pGroupClause;
1948 const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const
1950 if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
1951 return nullptr;
1953 // Analyse parse tree (depending on statement type)
1954 // and set pointer to ORDER clause:
1955 OSQLParseNode * pHavingClause = nullptr;
1956 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1957 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1958 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1959 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1960 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1962 pHavingClause = pTableExp->getChild(3);
1963 // If it is an order_by, then it must not be empty
1964 if(pHavingClause->count() < 1)
1965 pHavingClause = nullptr;
1966 return pHavingClause;
1969 bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode* _pTableNode)
1971 return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) ||
1972 SQL_ISRULE(_pTableNode,schema_name) ||
1973 SQL_ISRULE(_pTableNode,table_name));
1976 const OSQLParseNode* OSQLParseTreeIterator::getSimpleWhereTree() const
1978 const OSQLParseNode* pNode = getWhereTree();
1979 return pNode ? pNode->getChild(1) : nullptr;
1982 const OSQLParseNode* OSQLParseTreeIterator::getSimpleOrderTree() const
1984 const OSQLParseNode* pNode = getOrderTree();
1985 return pNode ? pNode->getChild(2) : nullptr;
1988 const OSQLParseNode* OSQLParseTreeIterator::getSimpleGroupByTree() const
1990 const OSQLParseNode* pNode = getGroupByTree();
1991 return pNode ? pNode->getChild(2) : nullptr;
1994 const OSQLParseNode* OSQLParseTreeIterator::getSimpleHavingTree() const
1996 const OSQLParseNode* pNode = getHavingTree();
1997 return pNode ? pNode->getChild(1) : nullptr;
2001 Reference< XPropertySet > OSQLParseTreeIterator::findSelectColumn( const OUString & rColumnName )
2003 for ( OSQLColumns::Vector::const_iterator lookupColumn = m_aSelectColumns->get().begin();
2004 lookupColumn != m_aSelectColumns->get().end();
2005 ++lookupColumn )
2007 Reference< XPropertySet > xColumn( *lookupColumn );
2010 OUString sName;
2011 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sName;
2012 if ( sName == rColumnName )
2013 return xColumn;
2015 catch( const Exception& )
2017 DBG_UNHANDLED_EXCEPTION();
2020 return nullptr;
2024 Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const OUString & rColumnName, OUString & rTableRange, bool _bLookInSubTables )
2026 Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange );
2027 if ( !xColumn.is() && _bLookInSubTables )
2028 xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange );
2029 return xColumn;
2033 Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables, const OUString & rColumnName, OUString & rTableRange)
2035 Reference< XPropertySet > xColumn;
2036 if ( !rTableRange.isEmpty() )
2038 OSQLTables::const_iterator aFind = _rTables.find(rTableRange);
2040 if ( aFind != _rTables.end()
2041 && aFind->second.is()
2042 && aFind->second->getColumns().is()
2043 && aFind->second->getColumns()->hasByName(rColumnName) )
2044 aFind->second->getColumns()->getByName(rColumnName) >>= xColumn;
2046 if ( !xColumn.is() )
2048 const OSQLTables::const_iterator aEnd = _rTables.end();
2049 for(OSQLTables::const_iterator aIter = _rTables.begin(); aIter != aEnd; ++aIter)
2051 if ( aIter->second.is() )
2053 Reference<XNameAccess> xColumns = aIter->second->getColumns();
2054 if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) )
2056 OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!");
2057 // Cannot take "rTableRange = aIter->first" because that is the fully composed name
2058 // that is, catalogName.schemaName.tableName
2059 rTableRange = getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)));
2060 break; // This column must only exits once
2065 return xColumn;
2069 void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const OUString* _pReplaceToken1, const OUString* _pReplaceToken2 )
2071 OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError );
2072 if ( _pReplaceToken1 )
2074 bool bTwoTokens = ( _pReplaceToken2 != nullptr );
2075 const sal_Char* pPlaceHolder1 = bTwoTokens ? "#1" : "#";
2076 const OUString sPlaceHolder1 = OUString::createFromAscii( pPlaceHolder1 );
2078 sErrorMessage = sErrorMessage.replaceFirst( sPlaceHolder1, *_pReplaceToken1 );
2079 if ( _pReplaceToken2 )
2080 sErrorMessage = sErrorMessage.replaceFirst( "#2" , *_pReplaceToken2 );
2083 impl_appendError( SQLException(
2084 sErrorMessage, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() ) );
2088 void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError )
2090 if ( !m_aErrors.Message.isEmpty() )
2092 SQLException* pErrorChain = &m_aErrors;
2093 while ( pErrorChain->NextException.hasValue() )
2094 pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData );
2095 pErrorChain->NextException <<= _rError;
2097 else
2098 m_aErrors = _rError;
2101 sal_Int32 OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode* _pNode )
2103 sal_Int32 nType = DataType::OTHER;
2104 OUString sFunctionName;
2105 if ( SQL_ISRULE(_pNode,length_exp) )
2107 _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
2108 nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
2110 else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) )
2112 nType = DataType::DOUBLE;
2114 else
2116 _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
2118 // MIN and MAX have another return type, we have to check the expression itself.
2119 // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566
2120 if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) ))
2122 const OSQLParseNode* pValueExp = _pNode->getChild(3);
2123 if (SQL_ISRULE(pValueExp,column_ref))
2125 OUString sColumnName;
2126 OUString aTableRange;
2127 getColumnRange(pValueExp,sColumnName,aTableRange);
2128 OSL_ENSURE(!sColumnName.isEmpty(),"Columnname must not be empty!");
2129 Reference<XPropertySet> xColumn = findColumn( sColumnName, aTableRange, true );
2131 if ( xColumn.is() )
2133 xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType;
2136 else
2138 if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) )
2140 nType = DataType::DOUBLE;
2142 else if ( SQL_ISRULE(pValueExp,datetime_primary) )
2144 switch(pValueExp->getChild(0)->getTokenID() )
2146 case SQL_TOKEN_CURRENT_DATE:
2147 nType = DataType::DATE;
2148 break;
2149 case SQL_TOKEN_CURRENT_TIME:
2150 nType = DataType::TIME;
2151 break;
2152 case SQL_TOKEN_CURRENT_TIMESTAMP:
2153 nType = DataType::TIMESTAMP;
2154 break;
2157 else if ( SQL_ISRULE(pValueExp,value_exp_primary) )
2159 nType = getFunctionReturnType(pValueExp->getChild(1));
2161 else if ( SQL_ISRULE(pValueExp,concatenation)
2162 || SQL_ISRULE(pValueExp,char_factor)
2163 || SQL_ISRULE(pValueExp,bit_value_fct)
2164 || SQL_ISRULE(pValueExp,char_value_fct)
2165 || SQL_ISRULE(pValueExp,char_substring_fct)
2166 || SQL_ISRULE(pValueExp,fold)
2167 || SQL_ISTOKEN(pValueExp,STRING) )
2169 nType = DataType::VARCHAR;
2172 if ( nType == DataType::OTHER )
2173 nType = DataType::DOUBLE;
2175 else
2176 nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
2179 return nType;
2182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */