1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
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>
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
94 Reference
< XQueriesSupplier
> xSuppQueries( m_xConnection
, UNO_QUERY
);
95 if ( xSuppQueries
.is() )
96 m_xQueryContainer
= xSuppQueries
->getQueries();
101 inline bool isQueryAllowed( const OUString
& _rQueryName
)
103 if ( !m_pForbiddenQueryNames
.get() )
105 if ( m_pForbiddenQueryNames
->find( _rQueryName
) == m_pForbiddenQueryNames
->end() )
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
;
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
);
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()
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
;
200 m_eStatementType
= OSQLStatementType::Unknown
;
204 // If m_pParseTree, but no connection then return
205 if ( !m_pImpl
->m_xTableContainer
.is() )
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);
239 m_eStatementType
= OSQLStatementType::Unknown
;
240 //aIteratorStatus.setInvalidStatement();
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(
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
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
327 if ( !bEscapeProcessing
|| ( sSubQueryCommand
.isEmpty() ) )
331 std::unique_ptr
< OSQLParseNode
> pSubQueryNode( const_cast< OSQLParser
& >( m_rParser
).parseTree( sError
, sSubQueryCommand
) );
332 if ( !pSubQueryNode
.get() )
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();
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?" );
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
);
385 aReturn
= impl_createTableObject( sName
, sCatalog
, sSchema
);
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 ) );
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
;
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
);
414 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch
, &sName
);
420 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch
, &sComposedName
);
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
433 OSL_ENSURE(pTableName
!= nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
436 OUString aSchema
,aTableName
,aComposedName
;
437 OUString
aTableRange(rTableRange
);
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(),
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
);
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!" );
503 const OSQLParseNode
* pNode
= getTableNode(_rTables
,pTableRef
->getChild(0),aTableRange
);
504 if ( isTableNode( pNode
) )
505 traverseOneTableName( _rTables
, pNode
, aTableRange
);
508 if( SQL_ISRULE(pTableRef
,cross_union
) || pTableRef
->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL
)
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));
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
);
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
);
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
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);
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));
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
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
);
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 )
662 OSQLParseNode
* pTableName
= nullptr;
664 switch ( m_eStatementType
)
666 case OSQLStatementType::Select
:
667 getSelect_statement( _rTables
, m_pParseTree
);
670 case OSQLStatementType::CreateTable
:
671 case OSQLStatementType::Insert
:
672 case OSQLStatementType::Delete
:
673 pTableName
= m_pParseTree
->getChild(2);
676 case OSQLStatementType::Update
:
677 pTableName
= m_pParseTree
->getChild(1);
685 OUString sTableRange
;
686 traverseOneTableName( _rTables
, pTableName
, sTableRange
);
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();
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();
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();
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
;
744 catch( const Exception
& )
746 DBG_UNHANDLED_EXCEPTION();
751 else if(SQL_ISRULE(_pColumnRef
,general_set_fct
) || SQL_ISRULE(_pColumnRef
,set_fct_spec
))
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
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
)
783 lcl_getColumnRange( _pColumnRef
, _rxConnection
, _out_rColumnName
, _out_rTableRange
, nullptr, sDummy
);
787 bool OSQLParseTreeIterator::getColumnTableRange(const OSQLParseNode
* pNode
, OUString
&rTableRange
) const
790 if(impl_getColumnTableRange(pNode
, tmp
))
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
;
832 if (aTableRange
.isEmpty())
837 if (rTableRange
.isEmpty())
838 rTableRange
= aTableRange
;
839 else if (rTableRange
!= aTableRange
)
844 for (sal_uInt32 i
= 0, ncount
= pNode
->count(); i
< ncount
; i
++)
846 if (!getColumnTableRange(pNode
->getChild(i
), rTableRange
))
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
);
863 if (!SQL_ISRULE(pSelectNode
,base_table_element_commalist
))
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
;
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();
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
) )
919 if (!pSelectNode
|| m_eStatementType
!= OSQLStatementType::Select
|| m_pImpl
->m_pTables
->empty())
921 impl_appendError( IParseContext::ErrorCode::General
);
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),"*"))
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
);
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
;
966 pColumnRef
= pColumnRef
->getChild(0);
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"
996 nType
= getFunctionReturnType(pColumnRef
);
1002 aIteratorStatus.setStatementTooComplex();
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();
1033 if (m_eStatementType
!= OSQLStatementType::Select
)
1035 //aIteratorStatus.setInvalidStatement();
1039 if(SQL_ISRULE(pSelectNode
,union_statement
))
1041 traverseByColumnNames(pSelectNode
->getChild(0),_bOrder
);
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 )
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!");
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
);
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!");
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
);
1103 setGroupByColumnName(sColumnName
, aTableRange
);
1107 bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode
* pSelectNode
)
1109 traverseByColumnNames( pSelectNode
, false );
1110 return !hasErrors();
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 );
1133 void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode
* _pNode
)
1135 if ( _pNode
== nullptr )
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
)
1147 const OSQLParseNode
* pOther
= pParent
->getChild(nPos
);
1148 if ( SQL_ISRULE( pOther
, column_ref
) )
1149 getColumnRange( pOther
, sColumnName
, sTableRange
, aColumnAlias
);
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
);
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
);
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 )
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
)) {
1219 SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
1221 // Other statement, no selection criteria
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!");
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
)
1251 SQL_ISRULE(pSearchCondition
,boolean_primary
) &&
1252 pSearchCondition
->count() == 3 &&
1253 SQL_ISPUNCTUATION(pSearchCondition
->getChild(0),"(") &&
1254 SQL_ISPUNCTUATION(pSearchCondition
->getChild(2),")")
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())
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())
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
) )
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())
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();
1314 OSQLParseNode
* pParam
= nullptr;
1315 if (SQL_ISRULE(pNum_value_exp
,parameter
))
1316 pParam
= pNum_value_exp
;
1317 else if(pNum_value_exp
->isToken())
1319 aValue
= pNum_value_exp
->getTokenValue();
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())
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));
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);
1359 OSL_ENSURE(SQL_ISTOKEN(pPart2
->getChild(0),IS
),"OSQLParseTreeIterator: error in parse tree!");
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
))
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
) )
1383 if ( !( m_pImpl
->m_nIncludeMask
& TraversalParts::Parameters
) )
1384 // parameters not to be included in the traversal
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()
1395 : !_aColumnName
.isEmpty()
1399 else if (SQL_ISPUNCTUATION(pMark
,":"))
1401 sParameterName
= _pParseNode
->getChild(1)->getTokenValue();
1403 else if (SQL_ISPUNCTUATION(pMark
,"["))
1405 sParameterName
= _pParseNode
->getChild(1)->getTokenValue();
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();
1419 for(; i
< nCount
;++i
)
1421 if ( _pParentNode
->getChild(i
) == _pParseNode
)
1424 sal_Int32 nType
= ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode
->getChild(0)->getTokenID(), i
-1);
1426 OParseColumn
* pColumn
= new OParseColumn( sParameterName
,
1430 ColumnValue::NULLABLE_UNKNOWN
,
1440 pColumn
->setFunction(true);
1441 pColumn
->setAggregateFunction(true);
1442 pColumn
->setRealName(sFunctionName
);
1443 m_aParameters
->get().push_back(pColumn
);
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
);
1461 else if(!_aColumnName
.isEmpty())// search in the tables for the right one
1464 Reference
<XPropertySet
> xColumn
= findColumn( _aColumnName
, _aTableRange
, true );
1468 OParseColumn
* pNewColumn
= new OParseColumn(xColumn
,isCaseSensitive());
1469 pNewColumn
->setName(sParameterName
);
1470 pNewColumn
->setRealName(_aColumnName
);
1471 m_aParameters
->get().push_back(pNewColumn
);
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();
1483 for(; i
< nCount
;++i
)
1485 if ( _pParentNode
->getChild(i
) == _pParseNode
)
1488 nType
= ::connectivity::OSQLParser::getFunctionParameterType( pParent
->getChild(0)->getTokenID(), i
+1);
1491 OUString
aNewColName( getUniqueColumnName( sParameterName
) );
1493 OParseColumn
* pColumn
= new OParseColumn(aNewColName
,
1497 ColumnValue::NULLABLE_UNKNOWN
,
1507 pColumn
->setName(aNewColName
);
1508 pColumn
->setRealName(sParameterName
);
1509 m_aParameters
->get().push_back(pColumn
);
1514 void OSQLParseTreeIterator::traverseOnePredicate(
1515 OSQLParseNode
* pColumnRef
,
1517 OSQLParseNode
* pParseNode
)
1522 // Column name (and TableRange):
1523 OUString aColumnName
, aTableRange
, sColumnAlias
;
1524 getColumnRange( pColumnRef
, aColumnName
, aTableRange
, sColumnAlias
);
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
);
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
) )
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
)
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
);
1578 case OSQLStatementType::Insert
:
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(
1601 OUString("New Created Table"),
1605 return aReturnTable
;
1608 void OSQLParseTreeIterator::appendColumns(::rtl::Reference
<OSQLColumns
>& _rColumns
,const OUString
& _rTableAlias
,const OSQLTable
& _rTable
)
1613 Reference
<XNameAccess
> xColumns
= _rTable
->getColumns();
1614 if ( !xColumns
.is() )
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
)))
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
);
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())
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
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() )
1681 Reference
<XNameAccess
> xColumns
= aIter
->second
->getColumns();
1682 Reference
< XPropertySet
> xColumn
;
1683 if ( !xColumns
->hasByName( rColumnName
)
1684 || !( xColumns
->getByName( rColumnName
) >>= xColumn
)
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
);
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(
1707 OUString("VARCHAR"),
1708 // TODO: does this match with _nType?
1709 // Or should be fill this from the getTypeInfo of the connection?
1712 ColumnValue::NULLABLE_UNKNOWN
,
1724 xNewColumn
= pColumn
;
1725 pColumn
->setRealName( rColumnName
);
1728 _rColumns
->get().push_back( xNewColumn
);
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())
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.");
1764 pColumn
->setTableName(aFind
->first
);
1766 Reference
< XPropertySet
> xCol
= pColumn
;
1767 _rColumns
->get().push_back(xCol
);
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
);
1791 // Table does not exist or lacking field
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(),
1816 ::comphelper::UStringMixEqual( isCaseSensitive() )
1819 while(aIter
!= m_aSelectColumns
->get().end())
1821 (aAlias
= rColumnName
) += OUString::number(i
++);
1823 m_aSelectColumns
->get().begin(),
1824 m_aSelectColumns
->get().end(),
1826 ::comphelper::UStringMixEqual( isCaseSensitive() )
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 );
1838 m_aOrderColumns
->get().push_back(new OOrderColumn( xColumn
, rTableRange
, isCaseSensitive(), bAscending
) );
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")
1855 void OSQLParseTreeIterator::setGroupByColumnName(const OUString
& rColumnName
, OUString
& rTableRange
)
1857 Reference
<XPropertySet
> xColumn
= findColumn( rColumnName
, rTableRange
, false );
1859 m_aGroupColumns
->get().push_back(new OParseColumn(xColumn
,isCaseSensitive()));
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")
1877 const OSQLParseNode
* OSQLParseTreeIterator::getWhereTree() const
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
)
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
)
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
)
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();
2007 Reference
< XPropertySet
> xColumn( *lookupColumn
);
2011 xColumn
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME
) ) >>= sName
;
2012 if ( sName
== rColumnName
)
2015 catch( const Exception
& )
2017 DBG_UNHANDLED_EXCEPTION();
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
);
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
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
;
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
;
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 );
2133 xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE
)) >>= nType
;
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
;
2149 case SQL_TOKEN_CURRENT_TIME
:
2150 nType
= DataType::TIME
;
2152 case SQL_TOKEN_CURRENT_TIMESTAMP
:
2153 nType
= DataType::TIMESTAMP
;
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
;
2176 nType
= ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName
, &m_rParser
.getContext() );
2182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */