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 <comphelper/diagnose_ex.hxx>
36 #include <TConnection.hxx>
37 #include <comphelper/types.hxx>
38 #include <connectivity/dbmetadata.hxx>
39 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
40 #include <o3tl/safeint.hxx>
41 #include <sal/log.hxx>
47 using namespace ::comphelper
;
48 using namespace ::connectivity
;
49 using namespace ::connectivity::sdbcx
;
50 using namespace ::dbtools
;
51 using namespace ::connectivity::parse
;
52 using namespace ::com::sun::star
;
53 using namespace ::com::sun::star::uno
;
54 using namespace ::com::sun::star::container
;
55 using namespace ::com::sun::star::sdbcx
;
56 using namespace ::com::sun::star::beans
;
57 using namespace ::com::sun::star::sdbc
;
58 using namespace ::com::sun::star::sdb
;
60 namespace connectivity
62 struct OSQLParseTreeIteratorImpl
64 std::vector
< TNodePair
> m_aJoinConditions
;
65 Reference
< XConnection
> m_xConnection
;
66 Reference
< XDatabaseMetaData
> m_xDatabaseMetaData
;
67 Reference
< XNameAccess
> m_xTableContainer
;
68 Reference
< XNameAccess
> m_xQueryContainer
;
70 std::shared_ptr
< OSQLTables
> m_pTables
; // all tables which participate in the SQL statement
71 std::shared_ptr
< OSQLTables
> m_pSubTables
; // all tables from sub queries not the tables from the select tables
72 std::shared_ptr
< QueryNameSet
> m_pForbiddenQueryNames
;
74 TraversalParts m_nIncludeMask
;
76 bool m_bIsCaseSensitive
;
78 OSQLParseTreeIteratorImpl( const Reference
< XConnection
>& _rxConnection
, const Reference
< XNameAccess
>& _rxTables
)
79 :m_xConnection( _rxConnection
)
80 ,m_nIncludeMask( TraversalParts::All
)
81 ,m_bIsCaseSensitive( true )
83 OSL_PRECOND( m_xConnection
.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" );
84 m_xDatabaseMetaData
= m_xConnection
->getMetaData();
86 m_bIsCaseSensitive
= m_xDatabaseMetaData
.is() && m_xDatabaseMetaData
->supportsMixedCaseQuotedIdentifiers();
87 m_pTables
= std::make_shared
<OSQLTables
>( UStringMixLess(m_bIsCaseSensitive
) );
88 m_pSubTables
= std::make_shared
<OSQLTables
>( UStringMixLess(m_bIsCaseSensitive
) );
90 m_xTableContainer
= _rxTables
;
92 DatabaseMetaData
aMetaData( m_xConnection
);
93 if ( aMetaData
.supportsSubqueriesInFrom() )
95 // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection
97 Reference
< XQueriesSupplier
> xSuppQueries( m_xConnection
, UNO_QUERY
);
98 if ( xSuppQueries
.is() )
99 m_xQueryContainer
= xSuppQueries
->getQueries();
104 bool isQueryAllowed( const OUString
& _rQueryName
)
106 if ( !m_pForbiddenQueryNames
)
108 if ( m_pForbiddenQueryNames
->find( _rQueryName
) == m_pForbiddenQueryNames
->end() )
116 /** helper class for temporarily adding a query name to a list of forbidden query names
118 class ForbidQueryName
120 std::shared_ptr
< QueryNameSet
>& m_rpAllForbiddenNames
;
121 OUString m_sForbiddenQueryName
;
124 ForbidQueryName( OSQLParseTreeIteratorImpl
& _rIteratorImpl
, OUString _aForbiddenQueryName
)
125 :m_rpAllForbiddenNames( _rIteratorImpl
.m_pForbiddenQueryNames
)
126 ,m_sForbiddenQueryName(std::move( _aForbiddenQueryName
))
128 if ( !m_rpAllForbiddenNames
)
129 m_rpAllForbiddenNames
= std::make_shared
<QueryNameSet
>();
130 m_rpAllForbiddenNames
->insert( m_sForbiddenQueryName
);
135 m_rpAllForbiddenNames
->erase( m_sForbiddenQueryName
);
142 OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference
< XConnection
>& _rxConnection
,
143 const Reference
< XNameAccess
>& _rxTables
,
144 const OSQLParser
& _rParser
)
145 :m_rParser( _rParser
)
146 ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection
, _rxTables
) )
148 setParseTree(nullptr);
152 OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator
& _rParentIterator
, const OSQLParser
& _rParser
, const OSQLParseNode
* pRoot
)
153 :m_rParser( _rParser
)
154 ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator
.m_pImpl
->m_xConnection
, _rParentIterator
.m_pImpl
->m_xTableContainer
) )
156 m_pImpl
->m_pForbiddenQueryNames
= _rParentIterator
.m_pImpl
->m_pForbiddenQueryNames
;
157 setParseTree( pRoot
);
161 OSQLParseTreeIterator::~OSQLParseTreeIterator()
167 const OSQLTables
& OSQLParseTreeIterator::getTables() const
169 return *m_pImpl
->m_pTables
;
173 bool OSQLParseTreeIterator::isCaseSensitive() const
175 return m_pImpl
->m_bIsCaseSensitive
;
179 void OSQLParseTreeIterator::dispose()
181 m_aSelectColumns
= nullptr;
182 m_aGroupColumns
= nullptr;
183 m_aOrderColumns
= nullptr;
184 m_aParameters
= nullptr;
185 m_pImpl
->m_xTableContainer
= nullptr;
186 m_pImpl
->m_xDatabaseMetaData
= nullptr;
187 m_aCreateColumns
= nullptr;
188 m_pImpl
->m_pTables
->clear();
189 m_pImpl
->m_pSubTables
->clear();
192 void OSQLParseTreeIterator::setParseTree(const OSQLParseNode
* pNewParseTree
)
194 m_pImpl
->m_pTables
->clear();
195 m_pImpl
->m_pSubTables
->clear();
197 m_aSelectColumns
= new OSQLColumns();
198 m_aGroupColumns
= new OSQLColumns();
199 m_aOrderColumns
= new OSQLColumns();
200 m_aParameters
= new OSQLColumns();
201 m_aCreateColumns
= new OSQLColumns();
203 m_pParseTree
= pNewParseTree
;
206 m_eStatementType
= OSQLStatementType::Unknown
;
210 // If m_pParseTree, but no connection then return
211 if ( !m_pImpl
->m_xTableContainer
.is() )
217 // Determine statement type ...
218 if (SQL_ISRULE(m_pParseTree
,select_statement
) || SQL_ISRULE(m_pParseTree
,union_statement
) )
220 m_eStatementType
= OSQLStatementType::Select
;
222 else if (SQL_ISRULE(m_pParseTree
,insert_statement
))
224 m_eStatementType
= OSQLStatementType::Insert
;
226 else if (SQL_ISRULE(m_pParseTree
,update_statement_searched
))
228 m_eStatementType
= OSQLStatementType::Update
;
230 else if (SQL_ISRULE(m_pParseTree
,delete_statement_searched
))
232 m_eStatementType
= OSQLStatementType::Delete
;
234 else if (m_pParseTree
->count() == 3 && SQL_ISRULE(m_pParseTree
->getChild(1),odbc_call_spec
))
236 m_eStatementType
= OSQLStatementType::OdbcCall
;
238 else if (SQL_ISRULE(m_pParseTree
->getChild(0),base_table_def
))
240 m_eStatementType
= OSQLStatementType::CreateTable
;
241 m_pParseTree
= m_pParseTree
->getChild(0);
245 m_eStatementType
= OSQLStatementType::Unknown
;
246 //aIteratorStatus.setInvalidStatement();
255 void impl_getRowString( const Reference
< XRow
>& _rxRow
, const sal_Int32 _nColumnIndex
, OUString
& _out_rString
)
257 _out_rString
= _rxRow
->getString( _nColumnIndex
);
258 if ( _rxRow
->wasNull() )
259 _out_rString
.clear();
263 OUString
lcl_findTableInMetaData(
264 const Reference
< XDatabaseMetaData
>& _rxDBMeta
, const OUString
& _rCatalog
,
265 const OUString
& _rSchema
, const OUString
& _rTableName
)
267 OUString sComposedName
;
269 static constexpr OUString s_sWildcard
= u
"%"_ustr
;
271 // we want all catalogues, all schemas, all tables
272 Sequence
< OUString
> sTableTypes
{ u
"VIEW"_ustr
, u
"TABLE"_ustr
, s_sWildcard
}; // this last one just to be sure to include anything else...
274 if ( _rxDBMeta
.is() )
276 sComposedName
.clear();
278 Reference
< XResultSet
> xRes
= _rxDBMeta
->getTables(
279 !_rCatalog
.isEmpty() ? Any( _rCatalog
) : Any(), !_rSchema
.isEmpty() ? _rSchema
: s_sWildcard
, _rTableName
, sTableTypes
);
281 Reference
< XRow
> xCurrentRow( xRes
, UNO_QUERY
);
282 if ( xCurrentRow
.is() && xRes
->next() )
284 OUString sCatalog
, sSchema
, sName
;
286 impl_getRowString( xCurrentRow
, 1, sCatalog
);
287 impl_getRowString( xCurrentRow
, 2, sSchema
);
288 impl_getRowString( xCurrentRow
, 3, sName
);
290 sComposedName
= ::dbtools::composeTableName(
296 ::dbtools::EComposeRule::InDataManipulation
300 return sComposedName
;
305 void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable
& _rQuery
)
307 if ( !( m_pImpl
->m_nIncludeMask
& TraversalParts::Parameters
) )
308 // parameters not to be included in the traversal
311 ::rtl::Reference
pSubQueryParameterColumns( new OSQLColumns() );
313 // get the command and the EscapeProcessing properties from the sub query
314 OUString sSubQueryCommand
;
315 bool bEscapeProcessing
= false;
318 Reference
< XPropertySet
> xQueryProperties( _rQuery
, UNO_QUERY_THROW
);
319 OSL_VERIFY( xQueryProperties
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND
) ) >>= sSubQueryCommand
);
320 OSL_VERIFY( xQueryProperties
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING
) ) >>= bEscapeProcessing
);
322 catch( const Exception
& )
324 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
327 // parse the sub query
330 if ( !bEscapeProcessing
|| ( sSubQueryCommand
.isEmpty() ) )
334 std::unique_ptr
< OSQLParseNode
> pSubQueryNode( const_cast< OSQLParser
& >( m_rParser
).parseTree( sError
, sSubQueryCommand
) );
338 OSQLParseTreeIterator
aSubQueryIterator( *this, m_rParser
, pSubQueryNode
.get() );
339 aSubQueryIterator
.impl_traverse( TraversalParts::Parameters
| TraversalParts::SelectColumns
);
340 // SelectColumns might also contain parameters #i77635#
341 pSubQueryParameterColumns
= aSubQueryIterator
.getParameters();
342 aSubQueryIterator
.dispose();
346 // copy the parameters of the sub query to our own parameter array
347 m_aParameters
->insert( m_aParameters
->end(), pSubQueryParameterColumns
->begin(), pSubQueryParameterColumns
->end() );
351 OSQLTable
OSQLParseTreeIterator::impl_locateRecordSource( const OUString
& _rComposedName
)
353 if ( _rComposedName
.isEmpty() )
355 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" );
360 OUString
sComposedName( _rComposedName
);
364 OUString sCatalog
, sSchema
, sName
;
365 qualifiedNameComponents( m_pImpl
->m_xDatabaseMetaData
, sComposedName
, sCatalog
, sSchema
, sName
, ::dbtools::EComposeRule::InDataManipulation
);
367 // check whether there is a query with the given name
368 bool bQueryDoesExist
= m_pImpl
->m_xQueryContainer
.is() && m_pImpl
->m_xQueryContainer
->hasByName( sComposedName
);
370 // check whether the table container contains an object with the given name
371 if ( !bQueryDoesExist
&& !m_pImpl
->m_xTableContainer
->hasByName( sComposedName
) )
372 sComposedName
= lcl_findTableInMetaData( m_pImpl
->m_xDatabaseMetaData
, sCatalog
, sSchema
, sName
);
373 bool bTableDoesExist
= m_pImpl
->m_xTableContainer
->hasByName( sComposedName
);
375 // now obtain the object
377 // if we're creating a table, and there already is a table or query with the same name,
378 // this is worth an error
379 if ( OSQLStatementType::CreateTable
== m_eStatementType
)
381 if ( bQueryDoesExist
)
382 impl_appendError( IParseContext::ErrorCode::InvalidQueryExist
, &sName
);
383 else if ( bTableDoesExist
)
384 impl_appendError( IParseContext::ErrorCode::InvalidTableExist
, &sName
);
386 aReturn
= impl_createTableObject( sName
, sCatalog
, sSchema
);
390 // queries win over tables, so if there's a query with this name, take this, no matter if
391 // there's a table, too
392 if ( bQueryDoesExist
)
394 if ( !m_pImpl
->isQueryAllowed( sComposedName
) )
396 impl_appendError( m_rParser
.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES
, nullptr ) );
400 m_pImpl
->m_xQueryContainer
->getByName( sComposedName
) >>= aReturn
;
402 // collect the parameters from the sub query
403 ForbidQueryName
aForbidName( *m_pImpl
, sComposedName
);
404 impl_getQueryParameterColumns( aReturn
);
406 else if ( bTableDoesExist
)
407 m_pImpl
->m_xTableContainer
->getByName( sComposedName
) >>= aReturn
;
410 if ( m_pImpl
->m_xQueryContainer
.is() )
411 // the connection on which we're working supports sub queries in from (else
412 // m_xQueryContainer would not have been set), so emit a better error message
413 impl_appendError( IParseContext::ErrorCode::InvalidTableOrQuery
, &sName
);
415 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch
, &sName
);
421 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch
, &sComposedName
);
428 void OSQLParseTreeIterator::traverseOneTableName( OSQLTables
& _rTables
,const OSQLParseNode
* pTableName
, const OUString
& rTableRange
)
430 if ( !( m_pImpl
->m_nIncludeMask
& TraversalParts::TableNames
) )
431 // tables should not be included in the traversal
434 OSL_ENSURE(pTableName
!= nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
437 OUString aSchema
,aTableName
,aComposedName
;
438 OUString
aTableRange(rTableRange
);
441 OSQLParseNode::getTableComponents(pTableName
,aCatalog
,aSchema
,aTableName
,m_pImpl
->m_xDatabaseMetaData
);
443 // create the composed name like DOMAIN.USER.TABLE1
444 aComposedName
= ::dbtools::composeTableName(m_pImpl
->m_xDatabaseMetaData
,
445 aCatalog
.hasValue() ? ::comphelper::getString(aCatalog
) : OUString(),
449 ::dbtools::EComposeRule::InDataManipulation
);
451 // if there is no alias for the table name assign the original name to it
452 if ( aTableRange
.isEmpty() )
453 aTableRange
= aComposedName
;
455 // get the object representing this table/query
456 OSQLTable aTable
= impl_locateRecordSource( aComposedName
);
458 _rTables
[ aTableRange
] = std::move(aTable
);
461 void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode
* i_pJoinCondition
)
463 if (i_pJoinCondition
->count() == 3 && // Expression with brackets
464 SQL_ISPUNCTUATION(i_pJoinCondition
->getChild(0),"(") &&
465 SQL_ISPUNCTUATION(i_pJoinCondition
->getChild(2),")"))
467 impl_fillJoinConditions(i_pJoinCondition
->getChild(1));
469 else if (SQL_ISRULEOR2(i_pJoinCondition
,search_condition
,boolean_term
) && // AND/OR logic operation:
470 i_pJoinCondition
->count() == 3)
472 // Only allow AND logic operation
473 if ( SQL_ISTOKEN(i_pJoinCondition
->getChild(1),AND
) )
475 impl_fillJoinConditions(i_pJoinCondition
->getChild(0));
476 impl_fillJoinConditions(i_pJoinCondition
->getChild(1));
479 else if (SQL_ISRULE(i_pJoinCondition
,comparison_predicate
))
481 // only the comparison of columns is allowed
482 OSL_ENSURE(i_pJoinCondition
->count() == 3,"OQueryDesignView::InsertJoinConnection: error in the parse tree");
483 if (SQL_ISRULE(i_pJoinCondition
->getChild(0),column_ref
) &&
484 SQL_ISRULE(i_pJoinCondition
->getChild(2),column_ref
) &&
485 i_pJoinCondition
->getChild(1)->getNodeType() == SQLNodeType::Equal
)
487 m_pImpl
->m_aJoinConditions
.push_back( TNodePair(i_pJoinCondition
->getChild(0),i_pJoinCondition
->getChild(2)) );
492 std::vector
< TNodePair
>& OSQLParseTreeIterator::getJoinConditions() const
494 return m_pImpl
->m_aJoinConditions
;
497 void OSQLParseTreeIterator::getQualified_join( OSQLTables
& _rTables
, const OSQLParseNode
*pTableRef
, OUString
& aTableRange
)
499 OSL_PRECOND( SQL_ISRULE( pTableRef
, cross_union
) || SQL_ISRULE( pTableRef
, qualified_join
) ,
500 "OSQLParseTreeIterator::getQualified_join: illegal node!" );
504 const OSQLParseNode
* pNode
= getTableNode(_rTables
,pTableRef
->getChild(0),aTableRange
);
505 if ( isTableNode( pNode
) )
506 traverseOneTableName( _rTables
, pNode
, aTableRange
);
509 if( SQL_ISRULE(pTableRef
,cross_union
) || pTableRef
->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL
)
512 // join_condition,named_columns_join
513 if ( SQL_ISRULE( pTableRef
, qualified_join
) )
515 const OSQLParseNode
* pJoin_spec
= pTableRef
->getChild(4);
516 if ( SQL_ISRULE( pJoin_spec
, join_condition
) )
518 impl_fillJoinConditions(pJoin_spec
->getChild(1));
522 const OSQLParseNode
* pColumnCommalist
= pJoin_spec
->getChild(2);
523 // All columns in the column_commalist ...
524 for (size_t i
= 0; i
< pColumnCommalist
->count(); i
++)
526 const OSQLParseNode
* pCol
= pColumnCommalist
->getChild(i
);
527 // add twice because the column must exists in both tables
528 m_pImpl
->m_aJoinConditions
.emplace_back(pCol
,pCol
);
534 pNode
= getTableNode(_rTables
,pTableRef
->getChild(nPos
),aTableRange
);
535 if ( isTableNode( pNode
) )
536 traverseOneTableName( _rTables
, pNode
, aTableRange
);
539 const OSQLParseNode
* OSQLParseTreeIterator::getTableNode( OSQLTables
& _rTables
, const OSQLParseNode
*pTableRef
,OUString
& rTableRange
)
541 OSL_PRECOND( SQL_ISRULE( pTableRef
, table_ref
) || SQL_ISRULE( pTableRef
, joined_table
)
542 || SQL_ISRULE( pTableRef
, qualified_join
) || SQL_ISRULE( pTableRef
, cross_union
),
543 "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" );
545 const OSQLParseNode
* pTableNameNode
= nullptr;
547 if ( SQL_ISRULE( pTableRef
, joined_table
) )
549 getQualified_join( _rTables
, pTableRef
->getChild(1), rTableRange
);
551 if ( SQL_ISRULE( pTableRef
, qualified_join
) || SQL_ISRULE( pTableRef
, cross_union
) )
553 getQualified_join( _rTables
, pTableRef
, rTableRange
);
557 rTableRange
= OSQLParseNode::getTableRange(pTableRef
);
558 if ( ( pTableRef
->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
559 || ( pTableRef
->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist
562 getQualified_join( _rTables
, pTableRef
->getChild(6 - pTableRef
->count()), rTableRange
);
564 else if ( pTableRef
->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')'
566 const OSQLParseNode
* pSubQuery
= pTableRef
->getChild(0);
567 if ( pSubQuery
->isToken() )
569 getQualified_join( _rTables
, pTableRef
->getChild(1), rTableRange
);
573 OSL_ENSURE( pSubQuery
->count() == 3, "sub queries should have 3 children!" );
574 const OSQLParseNode
* pQueryExpression
= pSubQuery
->getChild(1);
575 if ( SQL_ISRULE( pQueryExpression
, select_statement
) )
577 getSelect_statement( *m_pImpl
->m_pSubTables
, pQueryExpression
);
578 // TODO: now, we need to setup an OSQLTable from pQueryExpression in some way
579 // and stick it in _rTables[rTableRange]. Probably fake it by
580 // setting up a full OSQLParseTreeIterator on pQueryExpression
581 // and using its m_aSelectColumns
582 // This is necessary in stuff like "SELECT * FROM tbl1 INNER JOIN (SELECT foo, bar FROM tbl2) AS tbl3"
583 // so that setSelectColumnName() can expand the "*" correctly.
584 // See e.g. R_UserAndLastSubscription query of https://bugs.libreoffice.org/attachment.cgi?id=71871
588 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" );
592 else if ( pTableRef
->count() == 2 ) // table_node table_primary_as_range_column
594 pTableNameNode
= pTableRef
->getChild(0);
597 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" );
600 return pTableNameNode
;
603 void OSQLParseTreeIterator::getSelect_statement(OSQLTables
& _rTables
,const OSQLParseNode
* pSelect
)
605 if(SQL_ISRULE(pSelect
,union_statement
))
607 getSelect_statement(_rTables
,pSelect
->getChild(0));
608 //getSelect_statement(pSelect->getChild(3));
611 OSQLParseNode
* pTableRefCommalist
= pSelect
->getChild(3)->getChild(0)->getChild(1);
613 assert(pTableRefCommalist
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
614 OSL_ENSURE(SQL_ISRULE(pTableRefCommalist
,table_ref_commalist
),"OSQLParseTreeIterator: error in parse tree!");
616 const OSQLParseNode
* pTableName
= nullptr;
617 OUString aTableRange
;
618 for (size_t i
= 0; i
< pTableRefCommalist
->count(); i
++)
619 { // Process FROM clause
622 const OSQLParseNode
* pTableListElement
= pTableRefCommalist
->getChild(i
);
623 if ( isTableNode( pTableListElement
) )
625 traverseOneTableName( _rTables
, pTableListElement
, aTableRange
);
627 else if ( SQL_ISRULE( pTableListElement
, table_ref
) )
629 // Table references can be made up of table names, table names (+),'('joined_table')'(+)
630 pTableName
= pTableListElement
->getChild(0);
631 if( isTableNode( pTableName
) )
632 { // Found table names
633 aTableRange
= OSQLParseNode::getTableRange(pTableListElement
);
634 traverseOneTableName( _rTables
, pTableName
, aTableRange
);
636 else if(SQL_ISPUNCTUATION(pTableName
,"{"))
637 { // '{' SQL_TOKEN_OJ joined_table '}'
638 getQualified_join( _rTables
, pTableListElement
->getChild(2), aTableRange
);
641 { // '(' joined_table ')' range_variable op_column_commalist
642 getTableNode( _rTables
, pTableListElement
, aTableRange
);
645 else if (SQL_ISRULE( pTableListElement
, qualified_join
) || SQL_ISRULE( pTableListElement
, cross_union
) )
647 getQualified_join( _rTables
, pTableListElement
, aTableRange
);
649 else if ( SQL_ISRULE( pTableListElement
, joined_table
) )
651 getQualified_join( _rTables
, pTableListElement
->getChild(1), aTableRange
);
654 // if (! aIteratorStatus.IsSuccessful()) break;
658 bool OSQLParseTreeIterator::traverseTableNames(OSQLTables
& _rTables
)
660 if ( m_pParseTree
== nullptr )
663 OSQLParseNode
* pTableName
= nullptr;
665 switch ( m_eStatementType
)
667 case OSQLStatementType::Select
:
668 getSelect_statement( _rTables
, m_pParseTree
);
671 case OSQLStatementType::CreateTable
:
672 case OSQLStatementType::Insert
:
673 case OSQLStatementType::Delete
:
674 pTableName
= m_pParseTree
->getChild(2);
677 case OSQLStatementType::Update
:
678 pTableName
= m_pParseTree
->getChild(1);
686 traverseOneTableName( _rTables
, pTableName
, OUString() );
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
<static_cast<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 a possible alias
725 if ( _pSelectColumns
)
727 for (const Reference
< XPropertySet
>& xColumn
: *_pSelectColumns
)
731 OUString sName
, sTableName
;
732 xColumn
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME
) ) >>= sName
;
733 xColumn
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME
) ) >>= sTableName
;
734 if ( sName
== _out_rColumnName
&& ( _out_rTableRange
.isEmpty() || sTableName
== _out_rTableRange
) )
736 xColumn
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME
) ) >>= _out_rColumnAliasIfPresent
;
740 catch( const Exception
& )
742 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
747 else if(SQL_ISRULE(_pColumnRef
,general_set_fct
) || SQL_ISRULE(_pColumnRef
,set_fct_spec
))
749 _pColumnRef
->parseNodeToStr( _out_rColumnName
, _rxConnection
);
751 else if(_pColumnRef
->getNodeType() == SQLNodeType::Name
)
752 _out_rColumnName
= _pColumnRef
->getTokenValue();
757 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode
* _pColumnRef
,
758 OUString
& _rColumnName
,
759 OUString
& _rTableRange
) const
762 lcl_getColumnRange( _pColumnRef
, m_pImpl
->m_xConnection
, _rColumnName
, _rTableRange
, nullptr, sDummy
);
766 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode
* _pColumnRef
,
767 OUString
& _rColumnName
,
768 OUString
& _rTableRange
,
769 OUString
& _out_rColumnAliasIfPresent
) const
771 lcl_getColumnRange( _pColumnRef
, m_pImpl
->m_xConnection
, _rColumnName
, _rTableRange
, &*m_aSelectColumns
, _out_rColumnAliasIfPresent
);
775 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode
* _pColumnRef
,
776 const Reference
< XConnection
>& _rxConnection
, OUString
& _out_rColumnName
, OUString
& _out_rTableRange
)
779 lcl_getColumnRange( _pColumnRef
, _rxConnection
, _out_rColumnName
, _out_rTableRange
, nullptr, sDummy
);
783 void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode
* pSelectNode
)
785 // aIteratorStatus.Clear();
787 if (!pSelectNode
|| m_eStatementType
!= OSQLStatementType::CreateTable
|| m_pImpl
->m_pTables
->empty())
789 impl_appendError( IParseContext::ErrorCode::General
);
792 if (!SQL_ISRULE(pSelectNode
,base_table_element_commalist
))
795 for (size_t i
= 0; i
< pSelectNode
->count(); i
++)
797 OSQLParseNode
*pColumnRef
= pSelectNode
->getChild(i
);
799 if (SQL_ISRULE(pColumnRef
,column_def
))
801 OUString aColumnName
;
803 sal_Int32 nType
= DataType::VARCHAR
;
804 aColumnName
= pColumnRef
->getChild(0)->getTokenValue();
806 OSQLParseNode
*pDatatype
= pColumnRef
->getChild(1);
807 if (pDatatype
&& SQL_ISRULE(pDatatype
,character_string_type
))
809 const OSQLParseNode
*pType
= pDatatype
->getChild(0);
810 aTypeName
= pType
->getTokenValue();
811 if (pDatatype
->count() == 2 && (pType
->getTokenID() == SQL_TOKEN_CHAR
|| pType
->getTokenID() == SQL_TOKEN_CHARACTER
))
812 nType
= DataType::CHAR
;
814 else if(pDatatype
&& pDatatype
->getNodeType() == SQLNodeType::Keyword
)
816 aTypeName
= "VARCHAR";
819 if (!aTypeName
.isEmpty())
821 //TODO:Create a new class for create statement to handle field length
822 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(aColumnName
,aTypeName
,OUString(),OUString(),
823 ColumnValue::NULLABLE_UNKNOWN
,0,0,nType
,false,false,isCaseSensitive(),
824 OUString(),OUString(),OUString());
825 pColumn
->setFunction(false);
826 pColumn
->setRealName(aColumnName
);
828 m_aCreateColumns
->push_back(pColumn
);
835 bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode
* pSelectNode
)
837 if ( !( m_pImpl
->m_nIncludeMask
& TraversalParts::SelectColumns
) )
840 if (!pSelectNode
|| m_eStatementType
!= OSQLStatementType::Select
|| m_pImpl
->m_pTables
->empty())
842 impl_appendError( IParseContext::ErrorCode::General
);
846 if(SQL_ISRULE(pSelectNode
,union_statement
))
848 return traverseSelectColumnNames( pSelectNode
->getChild( 0 ) )
849 /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/;
852 // nyi: more checks for correct structure!
853 if (pSelectNode
->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode
->getChild(2)->getChild(0),"*"))
856 setSelectColumnName(u
"*"_ustr
, u
""_ustr
, u
""_ustr
);
858 else if (SQL_ISRULE(pSelectNode
->getChild(2),scalar_exp_commalist
))
860 // SELECT column[,column] or SELECT COUNT(*) ...
861 OSQLParseNode
* pSelection
= pSelectNode
->getChild(2);
863 for (size_t i
= 0; i
< pSelection
->count(); i
++)
865 OSQLParseNode
*pColumnRef
= pSelection
->getChild(i
);
867 //if (SQL_ISRULE(pColumnRef,select_sublist))
868 if (SQL_ISRULE(pColumnRef
,derived_column
) &&
869 SQL_ISRULE(pColumnRef
->getChild(0),column_ref
) &&
870 pColumnRef
->getChild(0)->count() == 3 &&
871 SQL_ISPUNCTUATION(pColumnRef
->getChild(0)->getChild(2),"*"))
873 // All the table's columns
874 OUString aTableRange
;
875 pColumnRef
->getChild(0)->parseNodeToStr( aTableRange
, m_pImpl
->m_xConnection
, nullptr, false, false );
876 setSelectColumnName(u
"*"_ustr
, u
""_ustr
, aTableRange
);
879 else if (SQL_ISRULE(pColumnRef
,derived_column
))
881 OUString
aColumnAlias(getColumnAlias(pColumnRef
)); // can be empty
882 OUString sColumnName
;
883 OUString aTableRange
;
884 sal_Int32 nType
= DataType::VARCHAR
;
886 pColumnRef
= pColumnRef
->getChild(0);
888 pColumnRef
->getKnownRuleID() != OSQLParseNode::subquery
&&
889 pColumnRef
->count() == 3 &&
890 SQL_ISPUNCTUATION(pColumnRef
->getChild(0),"(") &&
891 SQL_ISPUNCTUATION(pColumnRef
->getChild(2),")")
893 pColumnRef
= pColumnRef
->getChild(1);
895 if (SQL_ISRULE(pColumnRef
,column_ref
))
897 getColumnRange(pColumnRef
,sColumnName
,aTableRange
);
898 OSL_ENSURE(!sColumnName
.isEmpty(),"Column name must not be empty!");
900 else /*if (SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec) ||
901 SQL_ISRULE(pColumnRef,position_exp) || SQL_ISRULE(pColumnRef,extract_exp) ||
902 SQL_ISRULE(pColumnRef,length_exp) || SQL_ISRULE(pColumnRef,char_value_fct)||
903 SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term))*/
905 // Function call present
906 pColumnRef
->parseNodeToStr( sColumnName
, m_pImpl
->m_xConnection
);
907 // check if the column is also a parameter
908 traverseSearchCondition(pColumnRef
); // num_value_exp
910 if ( pColumnRef
->isRule() )
912 // FIXME: the if condition is not quite right
913 // many expressions are rules, e.g. "5+3"
914 // or even: "colName + 1"
916 nType
= getFunctionReturnType(pColumnRef
);
922 aIteratorStatus.setStatementTooComplex();
926 if(aColumnAlias
.isEmpty())
927 aColumnAlias
= sColumnName
;
928 setSelectColumnName(sColumnName
,aColumnAlias
,aTableRange
,bFkt
,nType
,SQL_ISRULE(pColumnRef
,general_set_fct
) || SQL_ISRULE(pColumnRef
,set_fct_spec
));
937 bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode
* pSelectNode
)
939 traverseByColumnNames( pSelectNode
, true );
943 void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode
* pSelectNode
, bool _bOrder
)
945 // aIteratorStatus.Clear();
947 if (pSelectNode
== nullptr)
949 //aIteratorStatus.setInvalidStatement();
953 if (m_eStatementType
!= OSQLStatementType::Select
)
955 //aIteratorStatus.setInvalidStatement();
959 if(SQL_ISRULE(pSelectNode
,union_statement
))
961 traverseByColumnNames(pSelectNode
->getChild(0),_bOrder
);
965 OSL_ENSURE(pSelectNode
->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
967 OSQLParseNode
* pTableExp
= pSelectNode
->getChild(3);
968 assert(pTableExp
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
969 OSL_ENSURE(SQL_ISRULE(pTableExp
,table_exp
),"OSQLParseTreeIterator:table_exp error in parse tree!");
970 OSL_ENSURE(pTableExp
->count() == TABLE_EXPRESSION_CHILD_COUNT
,"OSQLParseTreeIterator: error in parse tree!");
972 sal_uInt32 nPos
= ( _bOrder
? ORDER_BY_CHILD_POS
: 2 );
974 OSQLParseNode
* pOptByClause
= pTableExp
->getChild(nPos
);
975 assert(pOptByClause
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
976 if ( pOptByClause
->count() == 0 )
979 OSL_ENSURE(pOptByClause
->count() == 3,"OSQLParseTreeIterator: error in parse tree!");
981 OSQLParseNode
* pOrderingSpecCommalist
= pOptByClause
->getChild(2);
982 assert(pOrderingSpecCommalist
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
983 OSL_ENSURE(!_bOrder
|| SQL_ISRULE(pOrderingSpecCommalist
,ordering_spec_commalist
),"OSQLParseTreeIterator:ordering_spec_commalist error in parse tree!");
984 OSL_ENSURE(pOrderingSpecCommalist
->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
986 OUString sColumnName
;
987 OUString aTableRange
;
988 sal_uInt32 nCount
= pOrderingSpecCommalist
->count();
989 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
991 OSQLParseNode
* pColumnRef
= pOrderingSpecCommalist
->getChild(i
);
992 assert(pColumnRef
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
995 OSL_ENSURE(SQL_ISRULE(pColumnRef
,ordering_spec
),"OSQLParseTreeIterator:ordering_spec error in parse tree!");
996 OSL_ENSURE(pColumnRef
->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
998 pColumnRef
= pColumnRef
->getChild(0);
1000 assert(pColumnRef
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
1001 aTableRange
.clear();
1002 sColumnName
.clear();
1003 if ( SQL_ISRULE(pColumnRef
,column_ref
) )
1005 // Column name (and TableRange):
1006 getColumnRange(pColumnRef
,sColumnName
,aTableRange
);
1009 { // here I found a predicate
1010 pColumnRef
->parseNodeToStr( sColumnName
, m_pImpl
->m_xConnection
, nullptr, false, false );
1012 OSL_ENSURE(!sColumnName
.isEmpty(),"sColumnName must not be empty!");
1015 // Ascending/Descending
1016 OSQLParseNode
* pOptAscDesc
= pColumnRef
->getParent()->getChild(1);
1017 OSL_ENSURE(pOptAscDesc
!= nullptr,"OSQLParseTreeIterator: error in parse tree!");
1019 bool bAscending
= ! (pOptAscDesc
&& SQL_ISTOKEN(pOptAscDesc
,DESC
));
1020 setOrderByColumnName(sColumnName
, aTableRange
,bAscending
);
1023 setGroupByColumnName(sColumnName
, aTableRange
);
1027 bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode
* pSelectNode
)
1029 traverseByColumnNames( pSelectNode
, false );
1030 return !hasErrors();
1036 OUString
lcl_generateParameterName( const OSQLParseNode
& _rParentNode
, const OSQLParseNode
& _rParamNode
)
1038 OUString
sColumnName( u
"param"_ustr
);
1039 const sal_Int32 nCount
= static_cast<sal_Int32
>(_rParentNode
.count());
1040 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
1042 if ( _rParentNode
.getChild(i
) == &_rParamNode
)
1044 sColumnName
+= OUString::number( i
+1 );
1053 void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode
* _pNode
)
1055 if ( _pNode
== nullptr )
1058 OUString sColumnName
, sTableRange
, aColumnAlias
;
1059 const OSQLParseNode
* pParent
= _pNode
->getParent();
1060 if ( pParent
!= nullptr )
1062 if ( SQL_ISRULE(pParent
,comparison_predicate
) ) // x = X
1064 sal_uInt32 nPos
= 0;
1065 if ( pParent
->getChild(nPos
) == _pNode
)
1067 const OSQLParseNode
* pOther
= pParent
->getChild(nPos
);
1068 if ( SQL_ISRULE( pOther
, column_ref
) )
1069 getColumnRange( pOther
, sColumnName
, sTableRange
, aColumnAlias
);
1071 pOther
->parseNodeToStr( sColumnName
, m_pImpl
->m_xConnection
, nullptr, false, false );
1072 } // if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
1073 else if ( SQL_ISRULE(pParent
,other_like_predicate_part_2
) )
1075 const OSQLParseNode
* pOther
= pParent
->getParent()->getChild(0);
1076 if ( SQL_ISRULE( pOther
, column_ref
) )
1077 getColumnRange( pOther
, sColumnName
, sTableRange
, aColumnAlias
);
1079 pOther
->parseNodeToStr( sColumnName
, m_pImpl
->m_xConnection
, nullptr, false, false );
1081 else if ( SQL_ISRULE(pParent
,between_predicate_part_2
) )
1083 const OSQLParseNode
* pOther
= pParent
->getParent()->getChild(0);
1084 if ( SQL_ISRULE( pOther
, column_ref
) )
1085 getColumnRange( pOther
, sColumnName
, sTableRange
, aColumnAlias
);
1088 pOther
->parseNodeToStr( sColumnName
, m_pImpl
->m_xConnection
, nullptr, false, false );
1089 lcl_generateParameterName( *pParent
, *_pNode
);
1092 else if ( pParent
->getNodeType() == SQLNodeType::CommaListRule
)
1094 lcl_generateParameterName( *pParent
, *_pNode
);
1097 traverseParameter( _pNode
, pParent
, sColumnName
, sTableRange
, aColumnAlias
);
1098 const sal_uInt32 nCount
= _pNode
->count();
1099 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
1101 const OSQLParseNode
* pChild
= _pNode
->getChild(i
);
1102 traverseParameters( pChild
);
1106 bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode
* pSelectNode
)
1108 if ( pSelectNode
== nullptr )
1112 // Analyse parse tree (depending on statement type)
1113 // and set pointer to WHERE clause:
1114 OSQLParseNode
* pWhereClause
= nullptr;
1116 if (m_eStatementType
== OSQLStatementType::Select
)
1118 if(SQL_ISRULE(pSelectNode
,union_statement
))
1120 return traverseSelectionCriteria( pSelectNode
->getChild( 0 ) )
1121 && traverseSelectionCriteria( pSelectNode
->getChild( 3 ) );
1123 OSL_ENSURE(pSelectNode
->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
1125 OSQLParseNode
* pTableExp
= pSelectNode
->getChild(3);
1126 assert(pTableExp
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
1127 OSL_ENSURE(SQL_ISRULE(pTableExp
,table_exp
),"OSQLParseTreeIterator: error in parse tree!");
1128 OSL_ENSURE(pTableExp
->count() == TABLE_EXPRESSION_CHILD_COUNT
,"OSQLParseTreeIterator: error in parse tree!");
1130 pWhereClause
= pTableExp
->getChild(1);
1131 } else if (SQL_ISRULE(pSelectNode
,update_statement_searched
)) {
1132 OSL_ENSURE(pSelectNode
->count() == 5,"OSQLParseTreeIterator: error in parse tree!");
1133 pWhereClause
= pSelectNode
->getChild(4);
1134 } else if (SQL_ISRULE(pSelectNode
,delete_statement_searched
)) {
1135 OSL_ENSURE(pSelectNode
->count() == 4,"OSQLParseTreeIterator: error in parse tree!");
1136 pWhereClause
= pSelectNode
->getChild(3);
1137 } else if (SQL_ISRULE(pSelectNode
,delete_statement_positioned
)) {
1139 SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
1141 // Other statement, no selection criteria
1145 if (!pWhereClause
|| !SQL_ISRULE(pWhereClause
,where_clause
))
1147 // The WHERE clause is optional most of the time; which means it could be a "optional_where_clause".
1148 OSL_ENSURE(pWhereClause
&& SQL_ISRULE(pWhereClause
,opt_where_clause
),"OSQLParseTreeIterator: error in parse tree!");
1152 // But if it's a where_clause, then it must not be empty
1153 OSL_ENSURE(pWhereClause
->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1155 OSQLParseNode
* pComparisonPredicate
= pWhereClause
->getChild(1);
1156 OSL_ENSURE(pComparisonPredicate
!= nullptr,"OSQLParseTreeIterator: error in parse tree!");
1159 // Process the comparison criteria now
1162 traverseSearchCondition(pComparisonPredicate
);
1164 return !hasErrors();
1168 void OSQLParseTreeIterator::traverseSearchCondition(OSQLParseNode
const * pSearchCondition
)
1171 SQL_ISRULE(pSearchCondition
,boolean_primary
) &&
1172 pSearchCondition
->count() == 3 &&
1173 SQL_ISPUNCTUATION(pSearchCondition
->getChild(0),"(") &&
1174 SQL_ISPUNCTUATION(pSearchCondition
->getChild(2),")")
1178 traverseSearchCondition(pSearchCondition
->getChild(1));
1180 // The first element is an OR logical operation
1181 else if ( SQL_ISRULE(pSearchCondition
,search_condition
) && pSearchCondition
->count() == 3 )
1183 // if this assert fails, the SQL grammar has changed!
1184 assert(SQL_ISTOKEN(pSearchCondition
->getChild(1),OR
));
1185 // Then process recursively (use the same row) ...
1186 traverseSearchCondition(pSearchCondition
->getChild(0));
1187 // if (! aIteratorStatus.IsSuccessful())
1190 // Continue with the right child
1191 traverseSearchCondition(pSearchCondition
->getChild(2));
1193 // The first element is an AND logical operation (again)
1194 else if ( SQL_ISRULE(pSearchCondition
,boolean_term
) && pSearchCondition
->count() == 3 )
1196 // Then process recursively (use the same row)
1197 traverseSearchCondition(pSearchCondition
->getChild(0));
1198 // if (! aIteratorStatus.IsSuccessful())
1201 // Continue with the right child
1202 traverseSearchCondition(pSearchCondition
->getChild(2));
1204 // Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.)
1205 else if (SQL_ISRULE(pSearchCondition
,comparison_predicate
) )
1208 pSearchCondition
->getChild(2)->parseNodeToStr( aValue
, m_pImpl
->m_xConnection
, nullptr, false, false );
1209 traverseOnePredicate(pSearchCondition
->getChild(0),aValue
,pSearchCondition
->getChild(2));
1210 impl_fillJoinConditions(pSearchCondition
);
1211 // if (! aIteratorStatus.IsSuccessful())
1214 else if (SQL_ISRULE(pSearchCondition
,like_predicate
) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
1216 OSL_ENSURE(pSearchCondition
->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1217 const OSQLParseNode
* pPart2
= pSearchCondition
->getChild(1);
1219 sal_Int32 nCurrentPos
= pPart2
->count()-2;
1221 OSQLParseNode
* pNum_value_exp
= pPart2
->getChild(nCurrentPos
);
1222 OSQLParseNode
* pOptEscape
= pPart2
->getChild(nCurrentPos
+1);
1224 assert(pNum_value_exp
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
1225 assert(pOptEscape
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
1227 if (pOptEscape
->count() != 0)
1229 // aIteratorStatus.setStatementTooComplex();
1234 OSQLParseNode
* pParam
= nullptr;
1235 if (SQL_ISRULE(pNum_value_exp
,parameter
))
1236 pParam
= pNum_value_exp
;
1237 else if(pNum_value_exp
->isToken())
1239 aValue
= pNum_value_exp
->getTokenValue();
1242 pNum_value_exp
->parseNodeToStr( aValue
, m_pImpl
->m_xConnection
, nullptr, false, false );
1243 pParam
= pNum_value_exp
;
1246 traverseOnePredicate(pSearchCondition
->getChild(0),aValue
,pParam
);
1247 // if (! aIteratorStatus.IsSuccessful())
1250 else if (SQL_ISRULE(pSearchCondition
,in_predicate
))
1252 OSL_ENSURE(pSearchCondition
->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1253 const OSQLParseNode
* pPart2
= pSearchCondition
->getChild(1);
1255 traverseSearchCondition(pSearchCondition
->getChild(0));
1256 // if (! aIteratorStatus.IsSuccessful()) return;
1258 OSQLParseNode
* pChild
= pPart2
->getChild(2);
1259 if ( SQL_ISRULE(pChild
->getChild(0),subquery
) )
1261 traverseTableNames( *m_pImpl
->m_pSubTables
);
1262 traverseSelectionCriteria(pChild
->getChild(0)->getChild(1));
1265 { // '(' value_exp_commalist ')'
1266 pChild
= pChild
->getChild(1);
1267 sal_Int32 nCount
= pChild
->count();
1268 for (sal_Int32 i
=0; i
< nCount
; ++i
)
1270 traverseSearchCondition(pChild
->getChild(i
));
1274 else if (SQL_ISRULE(pSearchCondition
,test_for_null
) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
1276 OSL_ENSURE(pSearchCondition
->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1277 const OSQLParseNode
* pPart2
= pSearchCondition
->getChild(1);
1278 OSL_ENSURE(SQL_ISTOKEN(pPart2
->getChild(0),IS
),"OSQLParseTreeIterator: error in parse tree!");
1281 traverseOnePredicate(pSearchCondition
->getChild(0),aString
,nullptr);
1282 // if (! aIteratorStatus.IsSuccessful()) return;
1284 else if (SQL_ISRULE(pSearchCondition
,num_value_exp
) || SQL_ISRULE(pSearchCondition
,term
))
1287 traverseOnePredicate(pSearchCondition
->getChild(0),aString
,pSearchCondition
->getChild(0));
1288 traverseOnePredicate(pSearchCondition
->getChild(2),aString
,pSearchCondition
->getChild(2));
1290 // Just pass on the error
1293 void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode
* _pParseNode
1294 ,const OSQLParseNode
* _pParentNode
1295 ,const OUString
& _aColumnName
1296 ,OUString
& _aTableRange
1297 ,const OUString
& _rColumnAlias
)
1299 if ( !SQL_ISRULE( _pParseNode
, parameter
) )
1302 if ( !( m_pImpl
->m_nIncludeMask
& TraversalParts::Parameters
) )
1303 // parameters not to be included in the traversal
1306 OSL_ENSURE(_pParseNode
->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
1307 OSQLParseNode
* pMark
= _pParseNode
->getChild(0);
1308 OUString sParameterName
;
1310 if (SQL_ISPUNCTUATION(pMark
,"?"))
1312 sParameterName
= !_rColumnAlias
.isEmpty()
1314 : !_aColumnName
.isEmpty()
1318 else if (SQL_ISPUNCTUATION(pMark
,":"))
1320 sParameterName
= _pParseNode
->getChild(1)->getTokenValue();
1322 else if (SQL_ISPUNCTUATION(pMark
,"["))
1324 sParameterName
= _pParseNode
->getChild(1)->getTokenValue();
1328 SAL_WARN( "connectivity.parse","OSQLParseTreeIterator: error in parse tree!");
1331 // found a parameter
1332 if ( _pParentNode
&& (SQL_ISRULE(_pParentNode
,general_set_fct
) || SQL_ISRULE(_pParentNode
,set_fct_spec
)) )
1333 {// found a function as column_ref
1334 OUString sFunctionName
;
1335 _pParentNode
->getChild(0)->parseNodeToStr( sFunctionName
, m_pImpl
->m_xConnection
, nullptr, false, false );
1336 const sal_uInt32 nCount
= _pParentNode
->count();
1338 for(; i
< nCount
;++i
)
1340 if ( _pParentNode
->getChild(i
) == _pParseNode
)
1343 sal_Int32 nType
= ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode
->getChild(0)->getTokenID(), i
-1);
1345 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn( sParameterName
,
1349 ColumnValue::NULLABLE_UNKNOWN
,
1359 pColumn
->setFunction(true);
1360 pColumn
->setAggregateFunction(true);
1361 pColumn
->setRealName(sFunctionName
);
1362 m_aParameters
->push_back(pColumn
);
1366 bool bNotFound
= true;
1367 OSQLColumns::const_iterator aIter
= ::connectivity::find(
1368 m_aSelectColumns
->begin(),
1369 m_aSelectColumns
->end(),
1370 _aColumnName
,::comphelper::UStringMixEqual( isCaseSensitive() )
1372 if(aIter
!= m_aSelectColumns
->end())
1374 rtl::Reference
<OParseColumn
> pNewColumn
= new OParseColumn(*aIter
,isCaseSensitive());
1375 pNewColumn
->setName(sParameterName
);
1376 pNewColumn
->setRealName(_aColumnName
);
1377 m_aParameters
->push_back(pNewColumn
);
1380 else if(!_aColumnName
.isEmpty())// search in the tables for the right one
1383 Reference
<XPropertySet
> xColumn
= findColumn( _aColumnName
, _aTableRange
, true );
1387 rtl::Reference
<OParseColumn
> pNewColumn
= new OParseColumn(xColumn
,isCaseSensitive());
1388 pNewColumn
->setName(sParameterName
);
1389 pNewColumn
->setRealName(_aColumnName
);
1390 m_aParameters
->push_back(pNewColumn
);
1396 sal_Int32 nType
= DataType::VARCHAR
;
1397 OSQLParseNode
* pParent
= _pParentNode
? _pParentNode
->getParent() : nullptr;
1398 if ( pParent
&& (SQL_ISRULE(pParent
,general_set_fct
) || SQL_ISRULE(pParent
,set_fct_spec
)) )
1400 const sal_uInt32 nCount
= _pParentNode
->count();
1402 for(; i
< nCount
;++i
)
1404 if ( _pParentNode
->getChild(i
) == _pParseNode
)
1407 nType
= ::connectivity::OSQLParser::getFunctionParameterType( pParent
->getChild(0)->getTokenID(), i
+1);
1410 OUString
aNewColName(getUniqueColumnName(getSelectColumnNames(), sParameterName
));
1412 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(aNewColName
,
1416 ColumnValue::NULLABLE_UNKNOWN
,
1426 pColumn
->setName(aNewColName
);
1427 pColumn
->setRealName(sParameterName
);
1428 m_aParameters
->push_back(pColumn
);
1433 void OSQLParseTreeIterator::traverseOnePredicate(
1434 OSQLParseNode
const * pColumnRef
,
1436 OSQLParseNode
const * pParseNode
)
1441 // Column name (and TableRange):
1442 OUString aColumnName
, aTableRange
, sColumnAlias
;
1443 getColumnRange( pColumnRef
, aColumnName
, aTableRange
, sColumnAlias
);
1447 /*if (SQL_ISRULE(pParseNode,parameter))
1448 traverseParameter( pParseNode, pColumnRef, aColumnName, aTableRange, sColumnAlias );
1449 else */if (SQL_ISRULE(pParseNode
,column_ref
))// Column-Name (and TableRange):
1450 getColumnRange(pParseNode
,aName
,rValue
);
1453 traverseSearchCondition(pParseNode
);
1454 // if (! aIteratorStatus.IsSuccessful()) return;
1459 void OSQLParseTreeIterator::traverseAll()
1461 impl_traverse( TraversalParts::All
);
1465 void OSQLParseTreeIterator::impl_traverse( TraversalParts _nIncludeMask
)
1467 // resets our errors
1470 m_pImpl
->m_nIncludeMask
= _nIncludeMask
;
1472 if ( !traverseTableNames( *m_pImpl
->m_pTables
) )
1475 switch ( m_eStatementType
)
1477 case OSQLStatementType::Select
:
1479 const OSQLParseNode
* pSelectNode
= m_pParseTree
;
1480 traverseParameters( pSelectNode
);
1481 if ( !traverseSelectColumnNames( pSelectNode
)
1482 || !traverseOrderByColumnNames( pSelectNode
)
1483 || !traverseGroupByColumnNames( pSelectNode
)
1484 || !traverseSelectionCriteria( pSelectNode
)
1489 case OSQLStatementType::CreateTable
:
1491 //0 | 1 | 2 |3| 4 |5
1492 //create table sc.foo ( a char(20), b char )
1493 const OSQLParseNode
* pCreateNode
= m_pParseTree
->getChild(4);
1494 traverseCreateColumns(pCreateNode
);
1497 case OSQLStatementType::Insert
:
1504 // Dummy implementations
1507 OSQLTable
OSQLParseTreeIterator::impl_createTableObject( const OUString
& rTableName
,
1508 const OUString
& rCatalogName
, const OUString
& rSchemaName
)
1510 OSL_PRECOND( m_eStatementType
== OSQLStatementType::CreateTable
,
1511 "OSQLParseTreeIterator::impl_createTableObject: only to be called for CREATE TABLE statements!" );
1512 // (in all other cases, m_pTables is to contain the table objects as obtained from the tables
1513 // container of the connection (m_xTablesContainer)
1515 OSQLTable aReturnTable
= new OTable(
1520 u
"New Created Table"_ustr
,
1524 return aReturnTable
;
1527 void OSQLParseTreeIterator::appendColumns(const OUString
& _rTableAlias
, const OSQLTable
& _rTable
)
1532 Reference
<XNameAccess
> xColumns
= _rTable
->getColumns();
1533 if ( !xColumns
.is() )
1536 ::comphelper::UStringMixLess
aCompare(isCaseSensitive());
1537 std::vector
<OUString
> aSelectColumnNames
= getSelectColumnNames();
1539 for (auto& colName
: xColumns
->getElementNames())
1541 OUString
aName(getUniqueColumnName(aSelectColumnNames
, colName
));
1542 Reference
< XPropertySet
> xColumn
;
1543 if(xColumns
->hasByName(colName
) && (xColumns
->getByName(colName
) >>= xColumn
) && xColumn
.is())
1545 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(aName
1546 , getString(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME
)))
1547 , getString(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE
)))
1548 , getString(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION
)))
1549 , getINT32(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE
)))
1550 , getINT32(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION
)))
1551 , getINT32(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
)))
1552 , getINT32(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
)))
1553 , getBOOL(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT
)))
1554 , getBOOL(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))
1556 , getString(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME
)))
1557 , getString(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME
)))
1558 , getString(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME
))));
1560 pColumn
->setTableName(_rTableAlias
);
1561 pColumn
->setRealName(colName
);
1562 m_aSelectColumns
->push_back(pColumn
);
1563 // update aSelectColumnNames with newly insert aName
1564 aSelectColumnNames
.insert(std::upper_bound(aSelectColumnNames
.begin(), aSelectColumnNames
.end(), aName
, aCompare
), aName
);
1567 impl_appendError(IParseContext::ErrorCode::InvalidColumn
, &colName
, &_rTableAlias
);
1571 void OSQLParseTreeIterator::setSelectColumnName(const OUString
& rColumnName
,const OUString
& rColumnAlias
, const OUString
& rTableRange
, bool bFkt
, sal_Int32 _nType
, bool bAggFkt
)
1573 if(rColumnName
.toChar() == '*' && rTableRange
.isEmpty())
1575 for (auto const& table
: *m_pImpl
->m_pTables
)
1576 appendColumns(table
.first
, table
.second
);
1578 else if( rColumnName
.toChar() == '*' && !rTableRange
.isEmpty() )
1579 { // SELECT <table>.*
1580 OSQLTables::const_iterator aFind
= m_pImpl
->m_pTables
->find(rTableRange
);
1582 if(aFind
!= m_pImpl
->m_pTables
->end())
1583 appendColumns(rTableRange
, aFind
->second
);
1585 else if ( rTableRange
.isEmpty() )
1586 { // SELECT <something> ...
1587 // without table specified
1590 Reference
< XPropertySet
> xNewColumn
;
1592 for (auto const& table
: *m_pImpl
->m_pTables
)
1594 if ( !table
.second
.is() )
1597 Reference
<XNameAccess
> xColumns
= table
.second
->getColumns();
1598 Reference
< XPropertySet
> xColumn
;
1599 if ( !xColumns
->hasByName( rColumnName
)
1600 || !( xColumns
->getByName( rColumnName
) >>= xColumn
)
1604 OUString
aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias
));
1606 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(xColumn
,isCaseSensitive());
1607 xNewColumn
= pColumn
;
1608 pColumn
->setTableName(table
.first
);
1609 pColumn
->setName(aNewColName
);
1610 pColumn
->setRealName(rColumnName
);
1615 if ( !xNewColumn
.is() )
1617 // no function (due to the above !bFkt), no existing column
1618 // => assume an expression
1619 OUString
aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias
));
1620 // did not find a column with this name in any of the tables
1621 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(
1624 // TODO: does this match with _nType?
1625 // Or should be fill this from the getTypeInfo of the connection?
1628 ColumnValue::NULLABLE_UNKNOWN
,
1640 xNewColumn
= pColumn
;
1641 pColumn
->setRealName( rColumnName
);
1644 m_aSelectColumns
->push_back( xNewColumn
);
1648 OUString
aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias
));
1650 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(aNewColName
,OUString(),OUString(),OUString(),
1651 ColumnValue::NULLABLE_UNKNOWN
,0,0,_nType
,false,false,isCaseSensitive(),
1652 OUString(),OUString(),OUString());
1653 pColumn
->setFunction(true);
1654 pColumn
->setAggregateFunction(bAggFkt
);
1655 pColumn
->setRealName(rColumnName
);
1657 m_aSelectColumns
->push_back(pColumn
);
1660 else // ColumnName and TableName exist
1662 OSQLTables::const_iterator aFind
= m_pImpl
->m_pTables
->find(rTableRange
);
1664 bool bError
= false;
1665 if (aFind
!= m_pImpl
->m_pTables
->end() && aFind
->second
.is())
1669 OUString
aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias
));
1671 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(aNewColName
,OUString(),OUString(),OUString(),
1672 ColumnValue::NULLABLE_UNKNOWN
,0,0,_nType
,false,false,isCaseSensitive(),
1673 OUString(),OUString(),OUString());
1674 pColumn
->setFunction(true);
1675 pColumn
->setAggregateFunction(bAggFkt
);
1676 pColumn
->setRealName(rColumnName
);
1677 SAL_WARN("connectivity.parse", "Trying to construct a column with Function==true and a TableName; this makes no sense.");
1679 pColumn
->setTableName(aFind
->first
);
1681 m_aSelectColumns
->push_back(pColumn
);
1685 Reference
< XPropertySet
> xColumn
;
1686 if (aFind
->second
->getColumns()->hasByName(rColumnName
) && (aFind
->second
->getColumns()->getByName(rColumnName
) >>= xColumn
))
1688 OUString
aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias
));
1690 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(xColumn
,isCaseSensitive());
1691 pColumn
->setName(aNewColName
);
1692 pColumn
->setRealName(rColumnName
);
1693 pColumn
->setTableName(aFind
->first
);
1695 m_aSelectColumns
->push_back(pColumn
);
1704 // Table does not exist or lacking field
1707 OUString
aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias
));
1709 rtl::Reference
<OParseColumn
> pColumn
= new OParseColumn(aNewColName
,OUString(),OUString(),OUString(),
1710 ColumnValue::NULLABLE_UNKNOWN
,0,0,DataType::VARCHAR
,false,false,isCaseSensitive(),
1711 OUString(),OUString(),OUString());
1712 pColumn
->setFunction(true);
1713 pColumn
->setAggregateFunction(bAggFkt
);
1715 m_aSelectColumns
->push_back(pColumn
);
1720 std::vector
<OUString
> OSQLParseTreeIterator::getSelectColumnNames() const
1722 ::comphelper::UStringMixLess
aCompare(isCaseSensitive());
1724 std::vector
<OUString
> aColumnNames
;
1725 OUString sPropertyName
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
);
1726 for (const auto& col
: *m_aSelectColumns
)
1727 aColumnNames
.push_back(getString(col
->getPropertyValue(sPropertyName
)));
1728 std::sort(aColumnNames
.begin(), aColumnNames
.end(), aCompare
);
1730 return aColumnNames
;
1733 OUString
OSQLParseTreeIterator::getUniqueColumnName(const std::vector
<OUString
>& rColumnNames
, const OUString
& rColumnName
) const
1735 ::comphelper::UStringMixLess
aCompare(isCaseSensitive());
1736 if (!std::binary_search(rColumnNames
.begin(), rColumnNames
.end(), rColumnName
, aCompare
))
1743 aAlias
= rColumnName
+ OUString::number(i
++);
1745 while (std::binary_search(rColumnNames
.begin(), rColumnNames
.end(), aAlias
, aCompare
));
1749 void OSQLParseTreeIterator::setOrderByColumnName(const OUString
& rColumnName
, OUString
& rTableRange
, bool bAscending
)
1751 Reference
<XPropertySet
> xColumn
= findSelectColumn( rColumnName
);
1752 if ( !xColumn
.is() )
1753 xColumn
= findColumn ( rColumnName
, rTableRange
, false );
1755 m_aOrderColumns
->push_back(new OOrderColumn( xColumn
, rTableRange
, isCaseSensitive(), bAscending
) );
1758 sal_Int32 nId
= rColumnName
.toInt32();
1759 if ( nId
> 0 && o3tl::make_unsigned(nId
) < m_aSelectColumns
->size() )
1760 m_aOrderColumns
->push_back( new OOrderColumn( (*m_aSelectColumns
)[nId
-1], isCaseSensitive(), bAscending
) );
1763 #ifdef SQL_TEST_PARSETREEITERATOR
1764 cout
<< "OSQLParseTreeIterator::setOrderByColumnName: "
1765 << (const char *) rColumnName
<< ", "
1766 << (const char *) rTableRange
<< ", "
1767 << (bAscending
? "true" : "false")
1772 void OSQLParseTreeIterator::setGroupByColumnName(const OUString
& rColumnName
, OUString
& rTableRange
)
1774 Reference
<XPropertySet
> xColumn
= findColumn( rColumnName
, rTableRange
, false );
1776 m_aGroupColumns
->push_back(new OParseColumn(xColumn
,isCaseSensitive()));
1779 sal_Int32 nId
= rColumnName
.toInt32();
1780 if ( nId
> 0 && o3tl::make_unsigned(nId
) < m_aSelectColumns
->size() )
1781 m_aGroupColumns
->push_back(new OParseColumn((*m_aSelectColumns
)[nId
-1],isCaseSensitive()));
1784 #ifdef SQL_TEST_PARSETREEITERATOR
1785 cout
<< "OSQLParseTreeIterator::setGroupByColumnName: "
1786 << (const char *) rColumnName
<< ", "
1787 << (const char *) rTableRange
<< ", "
1788 << (bAscending
? "true" : "false")
1794 const OSQLParseNode
* OSQLParseTreeIterator::getWhereTree() const
1799 // Analyse parse tree (depending on statement type)
1800 // and set pointer to WHERE clause:
1801 OSQLParseNode
* pWhereClause
= nullptr;
1802 if(getStatementType() == OSQLStatementType::Select
)
1804 OSL_ENSURE(m_pParseTree
->count() >= 4,"ParseTreeIterator: error in parse tree!");
1805 OSQLParseNode
* pTableExp
= m_pParseTree
->getChild(3);
1806 assert(pTableExp
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
1807 OSL_ENSURE(SQL_ISRULE(pTableExp
,table_exp
),"OSQLParseTreeIterator: error in parse tree!");
1808 OSL_ENSURE(pTableExp
->count() == TABLE_EXPRESSION_CHILD_COUNT
,"OSQLParseTreeIterator: error in parse tree!");
1810 pWhereClause
= pTableExp
->getChild(1);
1812 else if (SQL_ISRULE(m_pParseTree
,update_statement_searched
) ||
1813 SQL_ISRULE(m_pParseTree
,delete_statement_searched
))
1815 pWhereClause
= m_pParseTree
->getChild(m_pParseTree
->count()-1);
1817 if(pWhereClause
&& pWhereClause
->count() != 2)
1818 pWhereClause
= nullptr;
1819 return pWhereClause
;
1823 const OSQLParseNode
* OSQLParseTreeIterator::getOrderTree() const
1825 if (!m_pParseTree
|| getStatementType() != OSQLStatementType::Select
)
1828 // Analyse parse tree (depending on statement type)
1829 // and set pointer to ORDER clause:
1831 assert(SQL_ISRULE(m_pParseTree
, select_statement
) || SQL_ISRULE(m_pParseTree
, union_statement
));
1833 auto pParseTree
= m_pParseTree
;
1834 if(SQL_ISRULE(m_pParseTree
, union_statement
))
1836 assert(m_pParseTree
->count() == 4);
1837 pParseTree
= pParseTree
->getChild(3);
1838 // since UNION is left-associative (at least in our grammar),
1839 // possibly the left-hand (m_pParseTree->getChild(0)) is a union_statement,
1840 // but the right hand cannot.
1841 assert(SQL_ISRULE(pParseTree
, select_statement
));
1844 OSQLParseNode
* pOrderClause
= nullptr;
1845 OSL_ENSURE(pParseTree
->count() == 4, "OSQLParseTreeIterator::getOrderTree: expected a SELECT, and a SELECT must have exactly four children");
1846 OSQLParseNode
* pTableExp
= pParseTree
->getChild(3);
1847 assert(pTableExp
!= nullptr && "OSQLParseTreeIterator::getOrderTree: got NULL table_exp");
1848 OSL_ENSURE(SQL_ISRULE(pTableExp
, table_exp
), "OSQLParseTreeIterator::getOrderTree: expected table_exp but got something else");
1849 OSL_ENSURE(pTableExp
->count() == TABLE_EXPRESSION_CHILD_COUNT
,"OSQLParseTreeIterator::getOrderTree: table_exp doesn't have the expected number of children");
1850 // tdf#141115 upgrade the above to an assert;
1851 // this cannot go well if there are too few children
1852 assert(pTableExp
->count() == TABLE_EXPRESSION_CHILD_COUNT
);
1854 pOrderClause
= pTableExp
->getChild(ORDER_BY_CHILD_POS
);
1855 // If it is an order_by, it must not be empty
1856 if(pOrderClause
->count() != 3)
1857 pOrderClause
= nullptr;
1858 return pOrderClause
;
1861 const OSQLParseNode
* OSQLParseTreeIterator::getGroupByTree() const
1863 if (!m_pParseTree
|| getStatementType() != OSQLStatementType::Select
)
1866 // Analyse parse tree (depending on statement type)
1867 // and set pointer to ORDER clause:
1868 OSQLParseNode
* pGroupClause
= nullptr;
1869 OSL_ENSURE(m_pParseTree
->count() >= 4,"ParseTreeIterator: error in parse tree!");
1870 OSQLParseNode
* pTableExp
= m_pParseTree
->getChild(3);
1871 assert(pTableExp
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
1872 OSL_ENSURE(SQL_ISRULE(pTableExp
,table_exp
),"OSQLParseTreeIterator: error in parse tree!");
1873 OSL_ENSURE(pTableExp
->count() == TABLE_EXPRESSION_CHILD_COUNT
,"OSQLParseTreeIterator: error in parse tree!");
1875 pGroupClause
= pTableExp
->getChild(2);
1876 // If it is an order_by, it must not be empty
1877 if(pGroupClause
->count() != 3)
1878 pGroupClause
= nullptr;
1879 return pGroupClause
;
1882 const OSQLParseNode
* OSQLParseTreeIterator::getHavingTree() const
1884 if (!m_pParseTree
|| getStatementType() != OSQLStatementType::Select
)
1887 // Analyse parse tree (depending on statement type)
1888 // and set pointer to ORDER clause:
1889 OSQLParseNode
* pHavingClause
= nullptr;
1890 OSL_ENSURE(m_pParseTree
->count() >= 4,"ParseTreeIterator: error in parse tree!");
1891 OSQLParseNode
* pTableExp
= m_pParseTree
->getChild(3);
1892 assert(pTableExp
!= nullptr && "OSQLParseTreeIterator: error in parse tree!");
1893 OSL_ENSURE(SQL_ISRULE(pTableExp
,table_exp
),"OSQLParseTreeIterator: error in parse tree!");
1894 OSL_ENSURE(pTableExp
->count() == TABLE_EXPRESSION_CHILD_COUNT
,"OSQLParseTreeIterator: error in parse tree!");
1896 pHavingClause
= pTableExp
->getChild(3);
1897 // If it is an order_by, then it must not be empty
1898 if(pHavingClause
->count() < 1)
1899 pHavingClause
= nullptr;
1900 return pHavingClause
;
1903 bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode
* _pTableNode
)
1905 return _pTableNode
&& (SQL_ISRULE(_pTableNode
,catalog_name
) ||
1906 SQL_ISRULE(_pTableNode
,schema_name
) ||
1907 SQL_ISRULE(_pTableNode
,table_name
));
1910 const OSQLParseNode
* OSQLParseTreeIterator::getSimpleWhereTree() const
1912 const OSQLParseNode
* pNode
= getWhereTree();
1913 return pNode
? pNode
->getChild(1) : nullptr;
1916 const OSQLParseNode
* OSQLParseTreeIterator::getSimpleOrderTree() const
1918 const OSQLParseNode
* pNode
= getOrderTree();
1919 return pNode
? pNode
->getChild(2) : nullptr;
1922 const OSQLParseNode
* OSQLParseTreeIterator::getSimpleGroupByTree() const
1924 const OSQLParseNode
* pNode
= getGroupByTree();
1925 return pNode
? pNode
->getChild(2) : nullptr;
1928 const OSQLParseNode
* OSQLParseTreeIterator::getSimpleHavingTree() const
1930 const OSQLParseNode
* pNode
= getHavingTree();
1931 return pNode
? pNode
->getChild(1) : nullptr;
1935 Reference
< XPropertySet
> OSQLParseTreeIterator::findSelectColumn( std::u16string_view rColumnName
)
1937 for (auto const& lookupColumn
: *m_aSelectColumns
)
1939 Reference
< XPropertySet
> xColumn( lookupColumn
);
1943 xColumn
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME
) ) >>= sName
;
1944 if ( sName
== rColumnName
)
1947 catch( const Exception
& )
1949 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
1956 Reference
< XPropertySet
> OSQLParseTreeIterator::findColumn( const OUString
& rColumnName
, OUString
& rTableRange
, bool _bLookInSubTables
)
1958 Reference
< XPropertySet
> xColumn
= findColumn( *m_pImpl
->m_pTables
, rColumnName
, rTableRange
);
1959 if ( !xColumn
.is() && _bLookInSubTables
)
1960 xColumn
= findColumn( *m_pImpl
->m_pSubTables
, rColumnName
, rTableRange
);
1965 Reference
< XPropertySet
> OSQLParseTreeIterator::findColumn(const OSQLTables
& _rTables
, const OUString
& rColumnName
, OUString
& rTableRange
)
1967 Reference
< XPropertySet
> xColumn
;
1968 if ( !rTableRange
.isEmpty() )
1970 OSQLTables::const_iterator aFind
= _rTables
.find(rTableRange
);
1972 if ( aFind
!= _rTables
.end()
1973 && aFind
->second
.is()
1974 && aFind
->second
->getColumns().is()
1975 && aFind
->second
->getColumns()->hasByName(rColumnName
) )
1976 aFind
->second
->getColumns()->getByName(rColumnName
) >>= xColumn
;
1978 if ( !xColumn
.is() )
1980 for (auto const& table
: _rTables
)
1982 if ( table
.second
.is() )
1984 Reference
<XNameAccess
> xColumns
= table
.second
->getColumns();
1985 if( xColumns
.is() && xColumns
->hasByName(rColumnName
) && (xColumns
->getByName(rColumnName
) >>= xColumn
) )
1987 OSL_ENSURE(xColumn
.is(),"Column isn't a propertyset!");
1988 // Cannot take "rTableRange = table.first" because that is the fully composed name
1989 // that is, catalogName.schemaName.tableName
1990 rTableRange
= getString(xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME
)));
1991 break; // This column must only exits once
2000 void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError
, const OUString
* _pReplaceToken1
, const OUString
* _pReplaceToken2
)
2002 OUString sErrorMessage
= m_rParser
.getContext().getErrorMessage( _eError
);
2003 if ( _pReplaceToken1
)
2005 bool bTwoTokens
= ( _pReplaceToken2
!= nullptr );
2006 const char* pPlaceHolder1
= bTwoTokens
? "#1" : "#";
2007 const OUString sPlaceHolder1
= OUString::createFromAscii( pPlaceHolder1
);
2009 sErrorMessage
= sErrorMessage
.replaceFirst( sPlaceHolder1
, *_pReplaceToken1
);
2010 if ( _pReplaceToken2
)
2011 sErrorMessage
= sErrorMessage
.replaceFirst( "#2" , *_pReplaceToken2
);
2014 impl_appendError( SQLException(
2015 sErrorMessage
, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR
), 1000, Any() ) );
2019 void OSQLParseTreeIterator::impl_appendError( const SQLException
& _rError
)
2021 SAL_WARN("connectivity.parse", "Adding error " << exceptionToString(Any(_rError
)));
2024 SQLException
* pErrorChain
= &*m_xErrors
;
2025 while ( pErrorChain
->NextException
.hasValue() )
2026 pErrorChain
= static_cast< SQLException
* >( pErrorChain
->NextException
.pData
);
2027 pErrorChain
->NextException
<<= _rError
;
2030 m_xErrors
= _rError
;
2033 sal_Int32
OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode
* _pNode
)
2035 sal_Int32 nType
= DataType::OTHER
;
2036 OUString sFunctionName
;
2037 if ( SQL_ISRULE(_pNode
,length_exp
) )
2039 _pNode
->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName
, m_pImpl
->m_xConnection
, nullptr, false, false );
2040 nType
= ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName
, &m_rParser
.getContext() );
2042 else if ( SQL_ISRULE(_pNode
,num_value_exp
) || SQL_ISRULE(_pNode
,term
) || SQL_ISRULE(_pNode
,factor
) )
2044 nType
= DataType::DOUBLE
;
2048 _pNode
->getChild(0)->parseNodeToStr(sFunctionName
, m_pImpl
->m_xConnection
, nullptr, false, false );
2050 // MIN and MAX have another return type, we have to check the expression itself.
2051 // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566
2052 if ( SQL_ISRULE(_pNode
,general_set_fct
) && (SQL_ISTOKEN(_pNode
->getChild(0),MIN
) || SQL_ISTOKEN(_pNode
->getChild(0),MAX
) ))
2054 const OSQLParseNode
* pValueExp
= _pNode
->getChild(3);
2055 if (SQL_ISRULE(pValueExp
,column_ref
))
2057 OUString sColumnName
;
2058 OUString aTableRange
;
2059 getColumnRange(pValueExp
,sColumnName
,aTableRange
);
2060 OSL_ENSURE(!sColumnName
.isEmpty(),"Columnname must not be empty!");
2061 Reference
<XPropertySet
> xColumn
= findColumn( sColumnName
, aTableRange
, true );
2065 xColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE
)) >>= nType
;
2070 if ( SQL_ISRULE(pValueExp
,num_value_exp
) || SQL_ISRULE(pValueExp
,term
) || SQL_ISRULE(pValueExp
,factor
) )
2072 nType
= DataType::DOUBLE
;
2074 else if ( SQL_ISRULE(pValueExp
,datetime_primary
) )
2076 switch(pValueExp
->getChild(0)->getTokenID() )
2078 case SQL_TOKEN_CURRENT_DATE
:
2079 nType
= DataType::DATE
;
2081 case SQL_TOKEN_CURRENT_TIME
:
2082 nType
= DataType::TIME
;
2084 case SQL_TOKEN_CURRENT_TIMESTAMP
:
2085 nType
= DataType::TIMESTAMP
;
2089 else if ( SQL_ISRULE(pValueExp
,value_exp_primary
) )
2091 nType
= getFunctionReturnType(pValueExp
->getChild(1));
2093 else if ( SQL_ISRULE(pValueExp
,concatenation
)
2094 || SQL_ISRULE(pValueExp
,char_factor
)
2095 || SQL_ISRULE(pValueExp
,bit_value_fct
)
2096 || SQL_ISRULE(pValueExp
,char_value_fct
)
2097 || SQL_ISRULE(pValueExp
,char_substring_fct
)
2098 || SQL_ISRULE(pValueExp
,fold
)
2099 || SQL_ISTOKEN(pValueExp
,STRING
) )
2101 nType
= DataType::VARCHAR
;
2104 if ( nType
== DataType::OTHER
)
2105 nType
= DataType::DOUBLE
;
2109 nType
= ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName
, &m_rParser
.getContext() );
2110 if (nType
== DataType::SQLNULL
)
2111 nType
= ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName
, m_rParser
.getNeutral() );
2118 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */