LibreOffice Module connectivity (master) 1
sqliterator.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
23#include <sqlbison.hxx>
26#include <com/sun/star/sdbc/ColumnValue.hpp>
27#include <com/sun/star/sdbc/DataType.hpp>
28#include <com/sun/star/sdbc/XRow.hpp>
29#include <com/sun/star/sdb/XQueriesSupplier.hpp>
30#include <com/sun/star/sdb/ErrorCondition.hpp>
31#ifdef SQL_TEST_PARSETREEITERATOR
32#include <iostream>
33#endif
36#include <TConnection.hxx>
37#include <comphelper/types.hxx>
39#include <com/sun/star/sdb/SQLFilterOperator.hpp>
40#include <o3tl/safeint.hxx>
41#include <sal/log.hxx>
42
43#include <iterator>
44#include <memory>
45#include <utility>
46
47using namespace ::comphelper;
48using namespace ::connectivity;
49using namespace ::connectivity::sdbcx;
50using namespace ::dbtools;
51using namespace ::connectivity::parse;
52using namespace ::com::sun::star;
53using namespace ::com::sun::star::uno;
54using namespace ::com::sun::star::container;
55using namespace ::com::sun::star::sdbcx;
56using namespace ::com::sun::star::beans;
57using namespace ::com::sun::star::sdbc;
58using namespace ::com::sun::star::sdb;
59
60namespace connectivity
61{
63 {
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;
69
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;
73
75
77
78 OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables )
79 :m_xConnection( _rxConnection )
81 ,m_bIsCaseSensitive( true )
82 {
83 OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" );
84 m_xDatabaseMetaData = m_xConnection->getMetaData();
85
86 m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers();
87 m_pTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
88 m_pSubTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
89
90 m_xTableContainer = _rxTables;
91
93 if ( aMetaData.supportsSubqueriesInFrom() )
94 {
95 // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection
96 // service
97 Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY );
98 if ( xSuppQueries.is() )
99 m_xQueryContainer = xSuppQueries->getQueries();
100 }
101 }
102
103 public:
104 bool isQueryAllowed( const OUString& _rQueryName )
105 {
107 return true;
108 if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() )
109 return true;
110 return false;
111 }
112 };
113
114 namespace {
115
118 class ForbidQueryName
119 {
120 std::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames;
122
123 public:
124 ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, OUString _aForbiddenQueryName )
125 :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames )
126 ,m_sForbiddenQueryName(std::move( _aForbiddenQueryName ))
127 {
129 m_rpAllForbiddenNames = std::make_shared<QueryNameSet>();
131 }
132
133 ~ForbidQueryName()
134 {
136 }
137 };
138
139 }
140}
141
142OSQLParseTreeIterator::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 ) )
147{
148 setParseTree(nullptr);
149}
150
151
152OSQLParseTreeIterator::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 ) )
155{
156 m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames;
157 setParseTree( pRoot );
158}
159
160
162{
163 dispose();
164}
165
166
168{
169 return *m_pImpl->m_pTables;
170}
171
172
174{
175 return m_pImpl->m_bIsCaseSensitive;
176}
177
178
180{
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();
190}
191
193{
194 m_pImpl->m_pTables->clear();
195 m_pImpl->m_pSubTables->clear();
196
202
203 m_pParseTree = pNewParseTree;
204 if (!m_pParseTree)
205 {
207 return;
208 }
209
210 // If m_pParseTree, but no connection then return
211 if ( !m_pImpl->m_xTableContainer.is() )
212 return;
213
214 m_xErrors.reset();
215
216
217 // Determine statement type ...
218 if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) )
219 {
221 }
222 else if (SQL_ISRULE(m_pParseTree,insert_statement))
223 {
225 }
226 else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
227 {
229 }
230 else if (SQL_ISRULE(m_pParseTree,delete_statement_searched))
231 {
233 }
234 else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec))
235 {
237 }
238 else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def))
239 {
242 }
243 else
244 {
246 //aIteratorStatus.setInvalidStatement();
247 return;
248 }
249}
250
251
252namespace
253{
254
255 void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, OUString& _out_rString )
256 {
257 _out_rString = _rxRow->getString( _nColumnIndex );
258 if ( _rxRow->wasNull() )
259 _out_rString.clear();
260 }
261
262
263 OUString lcl_findTableInMetaData(
264 const Reference< XDatabaseMetaData >& _rxDBMeta, const OUString& _rCatalog,
265 const OUString& _rSchema, const OUString& _rTableName )
266 {
267 OUString sComposedName;
268
269 static constexpr OUStringLiteral s_sWildcard = u"%" ;
270
271 // we want all catalogues, all schemas, all tables
272 Sequence< OUString > sTableTypes { "VIEW", "TABLE", s_sWildcard }; // this last one just to be sure to include anything else...
273
274 if ( _rxDBMeta.is() )
275 {
276 sComposedName.clear();
277
278 Reference< XResultSet> xRes = _rxDBMeta->getTables(
279 !_rCatalog.isEmpty() ? Any( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _rSchema : s_sWildcard, _rTableName, sTableTypes );
280
281 Reference< XRow > xCurrentRow( xRes, UNO_QUERY );
282 if ( xCurrentRow.is() && xRes->next() )
283 {
284 OUString sCatalog, sSchema, sName;
285
286 impl_getRowString( xCurrentRow, 1, sCatalog );
287 impl_getRowString( xCurrentRow, 2, sSchema );
288 impl_getRowString( xCurrentRow, 3, sName );
289
291 _rxDBMeta,
292 sCatalog,
293 sSchema,
294 sName,
295 false,
296 ::dbtools::EComposeRule::InDataManipulation
297 );
298 }
299 }
300 return sComposedName;
301 }
302}
303
304
306{
307 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
308 // parameters not to be included in the traversal
309 return;
310
311 ::rtl::Reference pSubQueryParameterColumns( new OSQLColumns() );
312
313 // get the command and the EscapeProcessing properties from the sub query
314 OUString sSubQueryCommand;
315 bool bEscapeProcessing = false;
316 try
317 {
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 );
321 }
322 catch( const Exception& )
323 {
324 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
325 }
326
327 // parse the sub query
328 do {
329
330 if ( !bEscapeProcessing || ( sSubQueryCommand.isEmpty() ) )
331 break;
332
333 OUString sError;
334 std::unique_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand ) );
335 if (!pSubQueryNode)
336 break;
337
338 OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() );
340 // SelectColumns might also contain parameters #i77635#
341 pSubQueryParameterColumns = aSubQueryIterator.getParameters();
342 aSubQueryIterator.dispose();
343
344 } while ( false );
345
346 // copy the parameters of the sub query to our own parameter array
347 m_aParameters->insert( m_aParameters->end(), pSubQueryParameterColumns->begin(), pSubQueryParameterColumns->end() );
348}
349
350
352{
353 if ( _rComposedName.isEmpty() )
354 {
355 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" );
356 return OSQLTable();
357 }
358
359 OSQLTable aReturn;
360 OUString sComposedName( _rComposedName );
361
362 try
363 {
364 OUString sCatalog, sSchema, sName;
365 qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
366
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 );
369
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 );
374
375 // now obtain the object
376
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
380 {
381 if ( bQueryDoesExist )
383 else if ( bTableDoesExist )
385 else
387 }
388 else
389 {
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 )
393 {
394 if ( !m_pImpl->isQueryAllowed( sComposedName ) )
395 {
396 impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, nullptr ) );
397 return nullptr;
398 }
399
400 m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn;
401
402 // collect the parameters from the sub query
403 ForbidQueryName aForbidName( *m_pImpl, sComposedName );
405 }
406 else if ( bTableDoesExist )
407 m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn;
408 else
409 {
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
414 else
416 }
417 }
418 }
419 catch(Exception&)
420 {
422 }
423
424 return aReturn;
425}
426
427
428void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const OUString & rTableRange )
429{
430 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::TableNames ) )
431 // tables should not be included in the traversal
432 return;
433
434 OSL_ENSURE(pTableName != nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
435
436 Any aCatalog;
437 OUString aSchema,aTableName,aComposedName;
438 OUString aTableRange(rTableRange);
439
440 // Get table name
441 OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData);
442
443 // create the composed name like DOMAIN.USER.TABLE1
444 aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData,
445 aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : OUString(),
446 aSchema,
447 aTableName,
448 false,
449 ::dbtools::EComposeRule::InDataManipulation);
450
451 // if there is no alias for the table name assign the original name to it
452 if ( aTableRange.isEmpty() )
453 aTableRange = aComposedName;
454
455 // get the object representing this table/query
456 OSQLTable aTable = impl_locateRecordSource( aComposedName );
457 if ( aTable.is() )
458 _rTables[ aTableRange ] = aTable;
459}
460
462{
463 if (i_pJoinCondition->count() == 3 && // Expression with brackets
464 SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") &&
465 SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")"))
466 {
467 impl_fillJoinConditions(i_pJoinCondition->getChild(1));
468 }
469 else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR logic operation:
470 i_pJoinCondition->count() == 3)
471 {
472 // Only allow AND logic operation
473 if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) )
474 {
475 impl_fillJoinConditions(i_pJoinCondition->getChild(0));
476 impl_fillJoinConditions(i_pJoinCondition->getChild(1));
477 }
478 }
479 else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate))
480 {
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)
486 {
487 m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) );
488 }
489 }
490}
491
492std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const
493{
494 return m_pImpl->m_aJoinConditions;
495}
496
497void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, OUString& aTableRange )
498{
499 OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) ,
500 "OSQLParseTreeIterator::getQualified_join: illegal node!" );
501
502 aTableRange.clear();
503
504 const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange);
505 if ( isTableNode( pNode ) )
506 traverseOneTableName( _rTables, pNode, aTableRange );
507
508 sal_uInt32 nPos = 4;
509 if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL)
510 {
511 nPos = 3;
512 // join_condition,named_columns_join
513 if ( SQL_ISRULE( pTableRef, qualified_join ) )
514 {
515 const OSQLParseNode* pJoin_spec = pTableRef->getChild(4);
516 if ( SQL_ISRULE( pJoin_spec, join_condition ) )
517 {
518 impl_fillJoinConditions(pJoin_spec->getChild(1));
519 }
520 else
521 {
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++)
525 {
526 const OSQLParseNode * pCol = pColumnCommalist->getChild(i);
527 // add twice because the column must exists in both tables
528 m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) );
529 }
530 }
531 }
532 }
533
534 pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange);
535 if ( isTableNode( pNode ) )
536 traverseOneTableName( _rTables, pNode, aTableRange );
537}
538
539const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,OUString& rTableRange )
540{
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!" );
544
545 const OSQLParseNode* pTableNameNode = nullptr;
546
547 if ( SQL_ISRULE( pTableRef, joined_table ) )
548 {
549 getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
550 }
551 if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) )
552 {
553 getQualified_join( _rTables, pTableRef, rTableRange );
554 }
555 else
556 {
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
560 )
561 {
562 getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange );
563 }
564 else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')'
565 {
566 const OSQLParseNode* pSubQuery = pTableRef->getChild(0);
567 if ( pSubQuery->isToken() )
568 {
569 getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
570 }
571 else
572 {
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 ) )
576 {
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
585 }
586 else
587 {
588 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" );
589 }
590 }
591 }
592 else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column
593 {
594 pTableNameNode = pTableRef->getChild(0);
595 }
596 else
597 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" );
598 }
599
600 return pTableNameNode;
601}
602
604{
605 if(SQL_ISRULE(pSelect,union_statement))
606 {
607 getSelect_statement(_rTables,pSelect->getChild(0));
608 //getSelect_statement(pSelect->getChild(3));
609 return;
610 }
611 OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1);
612
613 OSL_ENSURE(pTableRefCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
614 OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!");
615
616 const OSQLParseNode* pTableName = nullptr;
617 OUString aTableRange;
618 for (size_t i = 0; i < pTableRefCommalist->count(); i++)
619 { // Process FROM clause
620 aTableRange.clear();
621
622 const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i);
623 if ( isTableNode( pTableListElement ) )
624 {
625 traverseOneTableName( _rTables, pTableListElement, aTableRange );
626 }
627 else if ( SQL_ISRULE( pTableListElement, table_ref ) )
628 {
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 );
635 }
636 else if(SQL_ISPUNCTUATION(pTableName,"{"))
637 { // '{' SQL_TOKEN_OJ joined_table '}'
638 getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange );
639 }
640 else
641 { // '(' joined_table ')' range_variable op_column_commalist
642 getTableNode( _rTables, pTableListElement, aTableRange );
643 }
644 }
645 else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) )
646 {
647 getQualified_join( _rTables, pTableListElement, aTableRange );
648 }
649 else if ( SQL_ISRULE( pTableListElement, joined_table ) )
650 {
651 getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange );
652 }
653
654 // if (! aIteratorStatus.IsSuccessful()) break;
655 }
656}
657
659{
660 if ( m_pParseTree == nullptr )
661 return false;
662
663 OSQLParseNode* pTableName = nullptr;
664
665 switch ( m_eStatementType )
666 {
669 break;
670
674 pTableName = m_pParseTree->getChild(2);
675 break;
676
678 pTableName = m_pParseTree->getChild(1);
679 break;
680 default:
681 break;
682 }
683
684 if ( pTableName )
685 {
686 traverseOneTableName( _rTables, pTableName, OUString() );
687 }
688
689 return !hasErrors();
690}
691
693{
694 OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!");
695 OUString sColumnAlias;
696 if(_pDerivedColumn->getChild(1)->count() == 2)
697 sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue();
698 else if(!_pDerivedColumn->getChild(1)->isRule())
699 sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue();
700 return sColumnAlias;
701}
702
703
704namespace
705{
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 )
709 {
710 _out_rColumnName.clear();
711 _out_rTableRange.clear();
712 _out_rColumnAliasIfPresent.clear();
713 if ( SQL_ISRULE( _pColumnRef, column_ref ) )
714 {
715 if( _pColumnRef->count() > 1 )
716 {
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();
720 }
721 else
722 _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue();
723
724 // look up the column in the select column, to find a possible alias
725 if ( _pSelectColumns )
726 {
727 for (const Reference< XPropertySet >& xColumn : *_pSelectColumns)
728 {
729 try
730 {
731 OUString sName, sTableName;
733 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName;
734 if ( sName == _out_rColumnName && ( _out_rTableRange.isEmpty() || sTableName == _out_rTableRange ) )
735 {
736 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent;
737 break;
738 }
739 }
740 catch( const Exception& )
741 {
742 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
743 }
744 }
745 }
746 }
747 else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec))
748 { // Function
749 _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection );
750 }
751 else if(_pColumnRef->getNodeType() == SQLNodeType::Name)
752 _out_rColumnName = _pColumnRef->getTokenValue();
753 }
754}
755
756
758 OUString& _rColumnName,
759 OUString& _rTableRange) const
760{
761 OUString sDummy;
762 lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, nullptr, sDummy );
763}
764
765
767 OUString& _rColumnName,
768 OUString& _rTableRange,
769 OUString& _out_rColumnAliasIfPresent ) const
770{
771 lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent );
772}
773
774
775void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
776 const Reference< XConnection >& _rxConnection, OUString& _out_rColumnName, OUString& _out_rTableRange )
777{
778 OUString sDummy;
779 lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, nullptr, sDummy );
780}
781
782
784{
785 // aIteratorStatus.Clear();
786
787 if (!pSelectNode || m_eStatementType != OSQLStatementType::CreateTable || m_pImpl->m_pTables->empty())
788 {
790 return;
791 }
792 if (!SQL_ISRULE(pSelectNode,base_table_element_commalist))
793 return ;
794
795 for (size_t i = 0; i < pSelectNode->count(); i++)
796 {
797 OSQLParseNode *pColumnRef = pSelectNode->getChild(i);
798
799 if (SQL_ISRULE(pColumnRef,column_def))
800 {
801 OUString aColumnName;
802 OUString aTypeName;
803 sal_Int32 nType = DataType::VARCHAR;
804 aColumnName = pColumnRef->getChild(0)->getTokenValue();
805
806 OSQLParseNode *pDatatype = pColumnRef->getChild(1);
807 if (pDatatype && SQL_ISRULE(pDatatype,character_string_type))
808 {
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;
813 }
814 else if(pDatatype && pDatatype->getNodeType() == SQLNodeType::Keyword)
815 {
816 aTypeName = "VARCHAR";
817 }
818
819 if (!aTypeName.isEmpty())
820 {
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);
827
828 m_aCreateColumns->push_back(pColumn);
829 }
830 }
831
832 }
833}
834
836{
837 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::SelectColumns ) )
838 return true;
839
840 if (!pSelectNode || m_eStatementType != OSQLStatementType::Select || m_pImpl->m_pTables->empty())
841 {
843 return false;
844 }
845
846 if(SQL_ISRULE(pSelectNode,union_statement))
847 {
848 return traverseSelectColumnNames( pSelectNode->getChild( 0 ) )
849 /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/;
850 }
851
852 // nyi: more checks for correct structure!
853 if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*"))
854 {
855 // SELECT * ...
856 setSelectColumnName("*", "", "");
857 }
858 else if (SQL_ISRULE(pSelectNode->getChild(2),scalar_exp_commalist))
859 {
860 // SELECT column[,column] or SELECT COUNT(*) ...
861 OSQLParseNode * pSelection = pSelectNode->getChild(2);
862
863 for (size_t i = 0; i < pSelection->count(); i++)
864 {
865 OSQLParseNode *pColumnRef = pSelection->getChild(i);
866
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),"*"))
872 {
873 // All the table's columns
874 OUString aTableRange;
875 pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, nullptr, false, false );
876 setSelectColumnName("*", "", aTableRange);
877 continue;
878 }
879 else if (SQL_ISRULE(pColumnRef,derived_column))
880 {
881 OUString aColumnAlias(getColumnAlias(pColumnRef)); // can be empty
882 OUString sColumnName;
883 OUString aTableRange;
884 sal_Int32 nType = DataType::VARCHAR;
885 bool bFkt(false);
886 pColumnRef = pColumnRef->getChild(0);
887 while (
888 pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
889 pColumnRef->count() == 3 &&
890 SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
891 SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
892 )
893 pColumnRef = pColumnRef->getChild(1);
894
895 if (SQL_ISRULE(pColumnRef,column_ref))
896 {
897 getColumnRange(pColumnRef,sColumnName,aTableRange);
898 OSL_ENSURE(!sColumnName.isEmpty(),"Column name must not be empty!");
899 }
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))*/
904 {
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
909
910 if ( pColumnRef->isRule() )
911 {
912 // FIXME: the if condition is not quite right
913 // many expressions are rules, e.g. "5+3"
914 // or even: "colName + 1"
915 bFkt = true;
916 nType = getFunctionReturnType(pColumnRef);
917 }
918 }
919 /*
920 else
921 {
922 aIteratorStatus.setStatementTooComplex();
923 return;
924 }
925 */
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));
929 }
930 }
931 }
932
933 return !hasErrors();
934}
935
936
938{
939 traverseByColumnNames( pSelectNode, true );
940 return !hasErrors();
941}
942
944{
945 // aIteratorStatus.Clear();
946
947 if (pSelectNode == nullptr)
948 {
949 //aIteratorStatus.setInvalidStatement();
950 return;
951 }
952
954 {
955 //aIteratorStatus.setInvalidStatement();
956 return;
957 }
958
959 if(SQL_ISRULE(pSelectNode,union_statement))
960 {
961 traverseByColumnNames(pSelectNode->getChild(0),_bOrder);
962 return;
963 }
964
965 OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
966
967 OSQLParseNode * pTableExp = pSelectNode->getChild(3);
968 OSL_ENSURE(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!");
971
972 sal_uInt32 nPos = ( _bOrder ? ORDER_BY_CHILD_POS : 2 );
973
974 OSQLParseNode * pOptByClause = pTableExp->getChild(nPos);
975 OSL_ENSURE(pOptByClause != nullptr,"OSQLParseTreeIterator: error in parse tree!");
976 if ( pOptByClause->count() == 0 )
977 return;
978
979 OSL_ENSURE(pOptByClause->count() == 3,"OSQLParseTreeIterator: error in parse tree!");
980
981 OSQLParseNode * pOrderingSpecCommalist = pOptByClause->getChild(2);
982 OSL_ENSURE(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!");
985
986 OUString sColumnName;
987 OUString aTableRange;
988 sal_uInt32 nCount = pOrderingSpecCommalist->count();
989 for (sal_uInt32 i = 0; i < nCount; ++i)
990 {
991 OSQLParseNode* pColumnRef = pOrderingSpecCommalist->getChild(i);
992 OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
993 if ( _bOrder )
994 {
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!");
997
998 pColumnRef = pColumnRef->getChild(0);
999 }
1000 OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1001 aTableRange.clear();
1002 sColumnName.clear();
1003 if ( SQL_ISRULE(pColumnRef,column_ref) )
1004 {
1005 // Column name (and TableRange):
1006 getColumnRange(pColumnRef,sColumnName,aTableRange);
1007 }
1008 else
1009 { // here I found a predicate
1010 pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
1011 }
1012 OSL_ENSURE(!sColumnName.isEmpty(),"sColumnName must not be empty!");
1013 if ( _bOrder )
1014 {
1015 // Ascending/Descending
1016 OSQLParseNode * pOptAscDesc = pColumnRef->getParent()->getChild(1);
1017 OSL_ENSURE(pOptAscDesc != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1018
1019 bool bAscending = ! (pOptAscDesc && SQL_ISTOKEN(pOptAscDesc,DESC));
1020 setOrderByColumnName(sColumnName, aTableRange,bAscending);
1021 }
1022 else
1023 setGroupByColumnName(sColumnName, aTableRange);
1024 }
1025}
1026
1028{
1029 traverseByColumnNames( pSelectNode, false );
1030 return !hasErrors();
1031}
1032
1033
1034namespace
1035{
1036 OUString lcl_generateParameterName( const OSQLParseNode& _rParentNode, const OSQLParseNode& _rParamNode )
1037 {
1038 OUString sColumnName( "param" );
1039 const sal_Int32 nCount = static_cast<sal_Int32>(_rParentNode.count());
1040 for ( sal_Int32 i = 0; i < nCount; ++i )
1041 {
1042 if ( _rParentNode.getChild(i) == &_rParamNode )
1043 {
1044 sColumnName += OUString::number( i+1 );
1045 break;
1046 }
1047 }
1048 return sColumnName;
1049 }
1050}
1051
1052
1054{
1055 if ( _pNode == nullptr )
1056 return;
1057
1058 OUString sColumnName, sTableRange, aColumnAlias;
1059 const OSQLParseNode* pParent = _pNode->getParent();
1060 if ( pParent != nullptr )
1061 {
1062 if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
1063 {
1064 sal_uInt32 nPos = 0;
1065 if ( pParent->getChild(nPos) == _pNode )
1066 nPos = 2;
1067 const OSQLParseNode* pOther = pParent->getChild(nPos);
1068 if ( SQL_ISRULE( pOther, column_ref ) )
1069 getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
1070 else
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) )
1074 {
1075 const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
1076 if ( SQL_ISRULE( pOther, column_ref ) )
1077 getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
1078 else
1079 pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
1080 }
1081 else if ( SQL_ISRULE(pParent,between_predicate_part_2) )
1082 {
1083 const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
1084 if ( SQL_ISRULE( pOther, column_ref ) )
1085 getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
1086 else
1087 {
1088 pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
1089 lcl_generateParameterName( *pParent, *_pNode );
1090 }
1091 }
1092 else if ( pParent->getNodeType() == SQLNodeType::CommaListRule )
1093 {
1094 lcl_generateParameterName( *pParent, *_pNode );
1095 }
1096 }
1097 traverseParameter( _pNode, pParent, sColumnName, sTableRange, aColumnAlias );
1098 const sal_uInt32 nCount = _pNode->count();
1099 for (sal_uInt32 i = 0; i < nCount; ++i)
1100 {
1101 const OSQLParseNode* pChild = _pNode->getChild(i);
1102 traverseParameters( pChild );
1103 }
1104}
1105
1107{
1108 if ( pSelectNode == nullptr )
1109 return false;
1110
1111
1112 // Analyse parse tree (depending on statement type)
1113 // and set pointer to WHERE clause:
1114 OSQLParseNode * pWhereClause = nullptr;
1115
1117 {
1118 if(SQL_ISRULE(pSelectNode,union_statement))
1119 {
1120 return traverseSelectionCriteria( pSelectNode->getChild( 0 ) )
1121 && traverseSelectionCriteria( pSelectNode->getChild( 3 ) );
1122 }
1123 OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
1124
1125 OSQLParseNode * pTableExp = pSelectNode->getChild(3);
1126 OSL_ENSURE(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!");
1129
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)) {
1138 // nyi
1139 SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
1140 } else {
1141 // Other statement, no selection criteria
1142 return false;
1143 }
1144
1145 if (!pWhereClause || !SQL_ISRULE(pWhereClause,where_clause))
1146 {
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!");
1149 return false;
1150 }
1151
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!");
1154
1155 OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
1156 OSL_ENSURE(pComparisonPredicate != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1157
1158
1159 // Process the comparison criteria now
1160
1161
1162 traverseSearchCondition(pComparisonPredicate);
1163
1164 return !hasErrors();
1165}
1166
1167
1169{
1170 if (
1171 SQL_ISRULE(pSearchCondition,boolean_primary) &&
1172 pSearchCondition->count() == 3 &&
1173 SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
1174 SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")
1175 )
1176 {
1177 // Round brackets
1178 traverseSearchCondition(pSearchCondition->getChild(1));
1179 }
1180 // The first element is an OR logical operation
1181 else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 )
1182 {
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())
1188// return;
1189
1190 // Continue with the right child
1191 traverseSearchCondition(pSearchCondition->getChild(2));
1192 }
1193 // The first element is an AND logical operation (again)
1194 else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 )
1195 {
1196 // Then process recursively (use the same row)
1197 traverseSearchCondition(pSearchCondition->getChild(0));
1198// if (! aIteratorStatus.IsSuccessful())
1199// return;
1200
1201 // Continue with the right child
1202 traverseSearchCondition(pSearchCondition->getChild(2));
1203 }
1204 // Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.)
1205 else if (SQL_ISRULE(pSearchCondition,comparison_predicate) )
1206 {
1207 OUString aValue;
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())
1212// return;
1213 }
1214 else if (SQL_ISRULE(pSearchCondition,like_predicate) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
1215 {
1216 OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1217 const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
1218
1219 sal_Int32 nCurrentPos = pPart2->count()-2;
1220
1221 OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurrentPos);
1222 OSQLParseNode * pOptEscape = pPart2->getChild(nCurrentPos+1);
1223
1224 OSL_ENSURE(pNum_value_exp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1225 OSL_ENSURE(pOptEscape != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1226
1227 if (pOptEscape->count() != 0)
1228 {
1229 // aIteratorStatus.setStatementTooComplex();
1230 return;
1231 }
1232
1233 OUString aValue;
1234 OSQLParseNode * pParam = nullptr;
1235 if (SQL_ISRULE(pNum_value_exp,parameter))
1236 pParam = pNum_value_exp;
1237 else if(pNum_value_exp->isToken())
1238 // Normal value
1239 aValue = pNum_value_exp->getTokenValue();
1240 else
1241 {
1242 pNum_value_exp->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
1243 pParam = pNum_value_exp;
1244 }
1245
1246 traverseOnePredicate(pSearchCondition->getChild(0),aValue,pParam);
1247// if (! aIteratorStatus.IsSuccessful())
1248// return;
1249 }
1250 else if (SQL_ISRULE(pSearchCondition,in_predicate))
1251 {
1252 OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
1253 const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
1254
1255 traverseSearchCondition(pSearchCondition->getChild(0));
1256 // if (! aIteratorStatus.IsSuccessful()) return;
1257
1258 OSQLParseNode* pChild = pPart2->getChild(2);
1259 if ( SQL_ISRULE(pChild->getChild(0),subquery) )
1260 {
1261 traverseTableNames( *m_pImpl->m_pSubTables );
1263 }
1264 else
1265 { // '(' value_exp_commalist ')'
1266 pChild = pChild->getChild(1);
1267 sal_Int32 nCount = pChild->count();
1268 for (sal_Int32 i=0; i < nCount; ++i)
1269 {
1271 }
1272 }
1273 }
1274 else if (SQL_ISRULE(pSearchCondition,test_for_null) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
1275 {
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!");
1279
1280 OUString aString;
1281 traverseOnePredicate(pSearchCondition->getChild(0),aString,nullptr);
1282 // if (! aIteratorStatus.IsSuccessful()) return;
1283 }
1284 else if (SQL_ISRULE(pSearchCondition,num_value_exp) || SQL_ISRULE(pSearchCondition,term))
1285 {
1286 OUString aString;
1287 traverseOnePredicate(pSearchCondition->getChild(0),aString,pSearchCondition->getChild(0));
1288 traverseOnePredicate(pSearchCondition->getChild(2),aString,pSearchCondition->getChild(2));
1289 }
1290 // Just pass on the error
1291}
1292
1294 ,const OSQLParseNode* _pParentNode
1295 ,const OUString& _aColumnName
1296 ,OUString& _aTableRange
1297 ,const OUString& _rColumnAlias)
1298{
1299 if ( !SQL_ISRULE( _pParseNode, parameter ) )
1300 return;
1301
1302 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
1303 // parameters not to be included in the traversal
1304 return;
1305
1306 OSL_ENSURE(_pParseNode->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
1307 OSQLParseNode * pMark = _pParseNode->getChild(0);
1308 OUString sParameterName;
1309
1310 if (SQL_ISPUNCTUATION(pMark,"?"))
1311 {
1312 sParameterName = !_rColumnAlias.isEmpty()
1313 ? _rColumnAlias
1314 : !_aColumnName.isEmpty()
1315 ? _aColumnName
1316 : OUString("?");
1317 }
1318 else if (SQL_ISPUNCTUATION(pMark,":"))
1319 {
1320 sParameterName = _pParseNode->getChild(1)->getTokenValue();
1321 }
1322 else if (SQL_ISPUNCTUATION(pMark,"["))
1323 {
1324 sParameterName = _pParseNode->getChild(1)->getTokenValue();
1325 }
1326 else
1327 {
1328 SAL_WARN( "connectivity.parse","OSQLParseTreeIterator: error in parse tree!");
1329 }
1330
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();
1337 sal_uInt32 i = 0;
1338 for(; i < nCount;++i)
1339 {
1340 if ( _pParentNode->getChild(i) == _pParseNode )
1341 break;
1342 }
1344
1345 rtl::Reference<OParseColumn> pColumn = new OParseColumn( sParameterName,
1346 OUString(),
1347 OUString(),
1348 OUString(),
1349 ColumnValue::NULLABLE_UNKNOWN,
1350 0,
1351 0,
1352 nType,
1353 false,
1354 false,
1356 OUString(),
1357 OUString(),
1358 OUString());
1359 pColumn->setFunction(true);
1360 pColumn->setAggregateFunction(true);
1361 pColumn->setRealName(sFunctionName);
1362 m_aParameters->push_back(pColumn);
1363 }
1364 else
1365 {
1366 bool bNotFound = true;
1367 OSQLColumns::const_iterator aIter = ::connectivity::find(
1368 m_aSelectColumns->begin(),
1369 m_aSelectColumns->end(),
1371 );
1372 if(aIter != m_aSelectColumns->end())
1373 {
1374 rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(*aIter,isCaseSensitive());
1375 pNewColumn->setName(sParameterName);
1376 pNewColumn->setRealName(_aColumnName);
1377 m_aParameters->push_back(pNewColumn);
1378 bNotFound = false;
1379 }
1380 else if(!_aColumnName.isEmpty())// search in the tables for the right one
1381 {
1382
1383 Reference<XPropertySet> xColumn = findColumn( _aColumnName, _aTableRange, true );
1384
1385 if ( xColumn.is() )
1386 {
1387 rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(xColumn,isCaseSensitive());
1388 pNewColumn->setName(sParameterName);
1389 pNewColumn->setRealName(_aColumnName);
1390 m_aParameters->push_back(pNewColumn);
1391 bNotFound = false;
1392 }
1393 }
1394 if ( bNotFound )
1395 {
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)) )
1399 {
1400 const sal_uInt32 nCount = _pParentNode->count();
1401 sal_uInt32 i = 0;
1402 for(; i < nCount;++i)
1403 {
1404 if ( _pParentNode->getChild(i) == _pParseNode )
1405 break;
1406 }
1408 }
1409
1410 OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), sParameterName));
1411
1412 rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,
1413 OUString(),
1414 OUString(),
1415 OUString(),
1416 ColumnValue::NULLABLE_UNKNOWN,
1417 0,
1418 0,
1419 nType,
1420 false,
1421 false,
1423 OUString(),
1424 OUString(),
1425 OUString());
1426 pColumn->setName(aNewColName);
1427 pColumn->setRealName(sParameterName);
1428 m_aParameters->push_back(pColumn);
1429 }
1430 }
1431}
1432
1434 OSQLParseNode const * pColumnRef,
1435 OUString& rValue,
1436 OSQLParseNode const * pParseNode)
1437{
1438 if ( !pParseNode )
1439 return;
1440
1441 // Column name (and TableRange):
1442 OUString aColumnName, aTableRange, sColumnAlias;
1443 getColumnRange( pColumnRef, aColumnName, aTableRange, sColumnAlias);
1444
1445 OUString aName;
1446
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);
1451 else
1452 {
1453 traverseSearchCondition(pParseNode);
1454 // if (! aIteratorStatus.IsSuccessful()) return;
1455 }
1456}
1457
1458
1460{
1462}
1463
1464
1466{
1467 // resets our errors
1468 m_xErrors.reset();
1469
1470 m_pImpl->m_nIncludeMask = _nIncludeMask;
1471
1472 if ( !traverseTableNames( *m_pImpl->m_pTables ) )
1473 return;
1474
1475 switch ( m_eStatementType )
1476 {
1478 {
1479 const OSQLParseNode* pSelectNode = m_pParseTree;
1480 traverseParameters( pSelectNode );
1481 if ( !traverseSelectColumnNames( pSelectNode )
1482 || !traverseOrderByColumnNames( pSelectNode )
1483 || !traverseGroupByColumnNames( pSelectNode )
1484 || !traverseSelectionCriteria( pSelectNode )
1485 )
1486 return;
1487 }
1488 break;
1490 {
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);
1495 }
1496 break;
1498 break;
1499 default:
1500 break;
1501 }
1502}
1503
1504// Dummy implementations
1505
1506
1508 const OUString& rCatalogName, const OUString& rSchemaName )
1509{
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)
1514
1515 OSQLTable aReturnTable = new OTable(
1516 nullptr,
1517 false,
1518 rTableName,
1519 "Table",
1520 "New Created Table",
1521 rSchemaName,
1522 rCatalogName
1523 );
1524 return aReturnTable;
1525}
1526
1527void OSQLParseTreeIterator::appendColumns(const OUString& _rTableAlias, const OSQLTable& _rTable)
1528{
1529 if (!_rTable.is())
1530 return;
1531
1532 Reference<XNameAccess> xColumns = _rTable->getColumns();
1533 if ( !xColumns.is() )
1534 return;
1535
1536 Sequence< OUString > aColNames = xColumns->getElementNames();
1537 const OUString* pBegin = aColNames.getConstArray();
1538 const OUString* pEnd = pBegin + aColNames.getLength();
1539
1541 std::vector<OUString> aSelectColumnNames = getSelectColumnNames();
1542
1543 for(;pBegin != pEnd;++pBegin)
1544 {
1545 OUString aName(getUniqueColumnName(aSelectColumnNames, *pBegin));
1546 Reference< XPropertySet > xColumn;
1547 if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is())
1548 {
1549 rtl::Reference<OParseColumn> pColumn = new OParseColumn(aName
1559 , isCaseSensitive()
1563
1564 pColumn->setTableName(_rTableAlias);
1565 pColumn->setRealName(*pBegin);
1566 m_aSelectColumns->push_back(pColumn);
1567 // update aSelectColumnNames with newly insert aName
1568 aSelectColumnNames.insert(std::upper_bound(aSelectColumnNames.begin(), aSelectColumnNames.end(), aName, aCompare), aName);
1569 }
1570 else
1572 }
1573}
1574
1575void OSQLParseTreeIterator::setSelectColumnName(const OUString & rColumnName,const OUString & rColumnAlias, const OUString & rTableRange, bool bFkt, sal_Int32 _nType, bool bAggFkt)
1576{
1577 if(rColumnName.toChar() == '*' && rTableRange.isEmpty())
1578 { // SELECT * ...
1579 for (auto const& table : *m_pImpl->m_pTables)
1580 appendColumns(table.first, table.second);
1581 }
1582 else if( rColumnName.toChar() == '*' && !rTableRange.isEmpty() )
1583 { // SELECT <table>.*
1584 OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
1585
1586 if(aFind != m_pImpl->m_pTables->end())
1587 appendColumns(rTableRange, aFind->second);
1588 }
1589 else if ( rTableRange.isEmpty() )
1590 { // SELECT <something> ...
1591 // without table specified
1592 if ( !bFkt )
1593 {
1594 Reference< XPropertySet> xNewColumn;
1595
1596 for (auto const& table : *m_pImpl->m_pTables)
1597 {
1598 if ( !table.second.is() )
1599 continue;
1600
1601 Reference<XNameAccess> xColumns = table.second->getColumns();
1602 Reference< XPropertySet > xColumn;
1603 if ( !xColumns->hasByName( rColumnName )
1604 || !( xColumns->getByName( rColumnName ) >>= xColumn )
1605 )
1606 continue;
1607
1608 OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
1609
1610 rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
1611 xNewColumn = pColumn;
1612 pColumn->setTableName(table.first);
1613 pColumn->setName(aNewColName);
1614 pColumn->setRealName(rColumnName);
1615
1616 break;
1617 }
1618
1619 if ( !xNewColumn.is() )
1620 {
1621 // no function (due to the above !bFkt), no existing column
1622 // => assume an expression
1623 OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
1624 // did not find a column with this name in any of the tables
1625 rtl::Reference<OParseColumn> pColumn = new OParseColumn(
1626 aNewColName,
1627 "VARCHAR",
1628 // TODO: does this match with _nType?
1629 // Or should be fill this from the getTypeInfo of the connection?
1630 OUString(),
1631 OUString(),
1632 ColumnValue::NULLABLE_UNKNOWN,
1633 0,
1634 0,
1635 _nType,
1636 false,
1637 false,
1639 OUString(),
1640 OUString(),
1641 OUString()
1642 );
1643
1644 xNewColumn = pColumn;
1645 pColumn->setRealName( rColumnName );
1646 }
1647
1648 m_aSelectColumns->push_back( xNewColumn );
1649 }
1650 else
1651 {
1652 OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
1653
1654 rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1655 ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
1656 OUString(),OUString(),OUString());
1657 pColumn->setFunction(true);
1658 pColumn->setAggregateFunction(bAggFkt);
1659 pColumn->setRealName(rColumnName);
1660
1661 m_aSelectColumns->push_back(pColumn);
1662 }
1663 }
1664 else // ColumnName and TableName exist
1665 {
1666 OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
1667
1668 bool bError = false;
1669 if (aFind != m_pImpl->m_pTables->end() && aFind->second.is())
1670 {
1671 if (bFkt)
1672 {
1673 OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
1674
1675 rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1676 ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
1677 OUString(),OUString(),OUString());
1678 pColumn->setFunction(true);
1679 pColumn->setAggregateFunction(bAggFkt);
1680 pColumn->setRealName(rColumnName);
1681 SAL_WARN("connectivity.parse", "Trying to construct a column with Function==true and a TableName; this makes no sense.");
1682 assert(false);
1683 pColumn->setTableName(aFind->first);
1684
1685 m_aSelectColumns->push_back(pColumn);
1686 }
1687 else
1688 {
1689 Reference< XPropertySet > xColumn;
1690 if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn))
1691 {
1692 OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
1693
1694 rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
1695 pColumn->setName(aNewColName);
1696 pColumn->setRealName(rColumnName);
1697 pColumn->setTableName(aFind->first);
1698
1699 m_aSelectColumns->push_back(pColumn);
1700 }
1701 else
1702 bError = true;
1703 }
1704 }
1705 else
1706 bError = true;
1707
1708 // Table does not exist or lacking field
1709 if (bError)
1710 {
1711 OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
1712
1713 rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1714 ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,false,false,isCaseSensitive(),
1715 OUString(),OUString(),OUString());
1716 pColumn->setFunction(true);
1717 pColumn->setAggregateFunction(bAggFkt);
1718
1719 m_aSelectColumns->push_back(pColumn);
1720 }
1721 }
1722}
1723
1725{
1727
1728 std::vector<OUString> aColumnNames;
1730 for (const auto& col : *m_aSelectColumns)
1731 aColumnNames.push_back(getString(col->getPropertyValue(sPropertyName)));
1732 std::sort(aColumnNames.begin(), aColumnNames.end(), aCompare);
1733
1734 return aColumnNames;
1735}
1736
1737OUString OSQLParseTreeIterator::getUniqueColumnName(const std::vector<OUString>& rColumnNames, const OUString& rColumnName) const
1738{
1740 if (!std::binary_search(rColumnNames.begin(), rColumnNames.end(), rColumnName, aCompare))
1741 return rColumnName;
1742
1743 OUString aAlias;
1744 sal_Int32 i=1;
1745 do
1746 {
1747 aAlias = rColumnName + OUString::number(i++);
1748 }
1749 while (std::binary_search(rColumnNames.begin(), rColumnNames.end(), aAlias, aCompare));
1750 return aAlias;
1751}
1752
1753void OSQLParseTreeIterator::setOrderByColumnName(const OUString & rColumnName, OUString & rTableRange, bool bAscending)
1754{
1755 Reference<XPropertySet> xColumn = findSelectColumn( rColumnName );
1756 if ( !xColumn.is() )
1757 xColumn = findColumn ( rColumnName, rTableRange, false );
1758 if ( xColumn.is() )
1759 m_aOrderColumns->push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) );
1760 else
1761 {
1762 sal_Int32 nId = rColumnName.toInt32();
1763 if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
1764 m_aOrderColumns->push_back( new OOrderColumn( (*m_aSelectColumns)[nId-1], isCaseSensitive(), bAscending ) );
1765 }
1766
1767#ifdef SQL_TEST_PARSETREEITERATOR
1768 cout << "OSQLParseTreeIterator::setOrderByColumnName: "
1769 << (const char *) rColumnName << ", "
1770 << (const char *) rTableRange << ", "
1771 << (bAscending ? "true" : "false")
1772 << "\n";
1773#endif
1774}
1775
1776void OSQLParseTreeIterator::setGroupByColumnName(const OUString & rColumnName, OUString & rTableRange)
1777{
1778 Reference<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false );
1779 if ( xColumn.is() )
1780 m_aGroupColumns->push_back(new OParseColumn(xColumn,isCaseSensitive()));
1781 else
1782 {
1783 sal_Int32 nId = rColumnName.toInt32();
1784 if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
1785 m_aGroupColumns->push_back(new OParseColumn((*m_aSelectColumns)[nId-1],isCaseSensitive()));
1786 }
1787
1788#ifdef SQL_TEST_PARSETREEITERATOR
1789 cout << "OSQLParseTreeIterator::setGroupByColumnName: "
1790 << (const char *) rColumnName << ", "
1791 << (const char *) rTableRange << ", "
1792 << (bAscending ? "true" : "false")
1793 << "\n";
1794#endif
1795}
1796
1797
1799{
1800 if (!m_pParseTree)
1801 return nullptr;
1802
1803 // Analyse parse tree (depending on statement type)
1804 // and set pointer to WHERE clause:
1805 OSQLParseNode * pWhereClause = nullptr;
1807 {
1808 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1809 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1810 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1811 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1812 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1813
1814 pWhereClause = pTableExp->getChild(1);
1815 }
1816 else if (SQL_ISRULE(m_pParseTree,update_statement_searched) ||
1817 SQL_ISRULE(m_pParseTree,delete_statement_searched))
1818 {
1819 pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1);
1820 }
1821 if(pWhereClause && pWhereClause->count() != 2)
1822 pWhereClause = nullptr;
1823 return pWhereClause;
1824}
1825
1826
1828{
1830 return nullptr;
1831
1832 // Analyse parse tree (depending on statement type)
1833 // and set pointer to ORDER clause:
1834
1835 assert(SQL_ISRULE(m_pParseTree, select_statement) || SQL_ISRULE(m_pParseTree, union_statement));
1836
1837 auto pParseTree = m_pParseTree;
1838 if(SQL_ISRULE(m_pParseTree, union_statement))
1839 {
1840 assert(m_pParseTree->count() == 4);
1841 pParseTree = pParseTree->getChild(3);
1842 // since UNION is left-associative (at least in our grammar),
1843 // possibly the left-hand (m_pParseTree->getChild(0)) is a union_statement,
1844 // but the right hand cannot.
1845 assert(SQL_ISRULE(pParseTree, select_statement));
1846 }
1847
1848 OSQLParseNode * pOrderClause = nullptr;
1849 OSL_ENSURE(pParseTree->count() == 4, "OSQLParseTreeIterator::getOrderTree: expected a SELECT, and a SELECT must have exactly four children");
1850 OSQLParseNode * pTableExp = pParseTree->getChild(3);
1851 OSL_ENSURE(pTableExp != nullptr, "OSQLParseTreeIterator::getOrderTree: got NULL table_exp");
1852 OSL_ENSURE(SQL_ISRULE(pTableExp, table_exp), "OSQLParseTreeIterator::getOrderTree: expected table_exp but got something else");
1853 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator::getOrderTree: table_exp doesn't have the expected number of children");
1854 // tdf#141115 upgrade the above to an assert;
1855 // this cannot go well if there are too few children
1856 assert(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT);
1857
1858 pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
1859 // If it is an order_by, it must not be empty
1860 if(pOrderClause->count() != 3)
1861 pOrderClause = nullptr;
1862 return pOrderClause;
1863}
1864
1866{
1868 return nullptr;
1869
1870 // Analyse parse tree (depending on statement type)
1871 // and set pointer to ORDER clause:
1872 OSQLParseNode * pGroupClause = nullptr;
1873 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1874 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1875 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1876 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1877 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1878
1879 pGroupClause = pTableExp->getChild(2);
1880 // If it is an order_by, it must not be empty
1881 if(pGroupClause->count() != 3)
1882 pGroupClause = nullptr;
1883 return pGroupClause;
1884}
1885
1887{
1889 return nullptr;
1890
1891 // Analyse parse tree (depending on statement type)
1892 // and set pointer to ORDER clause:
1893 OSQLParseNode * pHavingClause = nullptr;
1894 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1895 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1896 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1897 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1898 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1899
1900 pHavingClause = pTableExp->getChild(3);
1901 // If it is an order_by, then it must not be empty
1902 if(pHavingClause->count() < 1)
1903 pHavingClause = nullptr;
1904 return pHavingClause;
1905}
1906
1908{
1909 return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) ||
1910 SQL_ISRULE(_pTableNode,schema_name) ||
1911 SQL_ISRULE(_pTableNode,table_name));
1912}
1913
1915{
1916 const OSQLParseNode* pNode = getWhereTree();
1917 return pNode ? pNode->getChild(1) : nullptr;
1918}
1919
1921{
1922 const OSQLParseNode* pNode = getOrderTree();
1923 return pNode ? pNode->getChild(2) : nullptr;
1924}
1925
1927{
1928 const OSQLParseNode* pNode = getGroupByTree();
1929 return pNode ? pNode->getChild(2) : nullptr;
1930}
1931
1933{
1934 const OSQLParseNode* pNode = getHavingTree();
1935 return pNode ? pNode->getChild(1) : nullptr;
1936}
1937
1938
1939Reference< XPropertySet > OSQLParseTreeIterator::findSelectColumn( std::u16string_view rColumnName )
1940{
1941 for (auto const& lookupColumn : *m_aSelectColumns)
1942 {
1943 Reference< XPropertySet > xColumn( lookupColumn );
1944 try
1945 {
1946 OUString sName;
1947 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sName;
1948 if ( sName == rColumnName )
1949 return xColumn;
1950 }
1951 catch( const Exception& )
1952 {
1953 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
1954 }
1955 }
1956 return nullptr;
1957}
1958
1959
1960Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const OUString & rColumnName, OUString & rTableRange, bool _bLookInSubTables )
1961{
1962 Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange );
1963 if ( !xColumn.is() && _bLookInSubTables )
1964 xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange );
1965 return xColumn;
1966}
1967
1968
1969Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables, const OUString & rColumnName, OUString & rTableRange)
1970{
1971 Reference< XPropertySet > xColumn;
1972 if ( !rTableRange.isEmpty() )
1973 {
1974 OSQLTables::const_iterator aFind = _rTables.find(rTableRange);
1975
1976 if ( aFind != _rTables.end()
1977 && aFind->second.is()
1978 && aFind->second->getColumns().is()
1979 && aFind->second->getColumns()->hasByName(rColumnName) )
1980 aFind->second->getColumns()->getByName(rColumnName) >>= xColumn;
1981 }
1982 if ( !xColumn.is() )
1983 {
1984 for (auto const& table : _rTables)
1985 {
1986 if ( table.second.is() )
1987 {
1988 Reference<XNameAccess> xColumns = table.second->getColumns();
1989 if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) )
1990 {
1991 OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!");
1992 // Cannot take "rTableRange = table.first" because that is the fully composed name
1993 // that is, catalogName.schemaName.tableName
1995 break; // This column must only exits once
1996 }
1997 }
1998 }
1999 }
2000 return xColumn;
2001}
2002
2003
2004void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const OUString* _pReplaceToken1, const OUString* _pReplaceToken2 )
2005{
2006 OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError );
2007 if ( _pReplaceToken1 )
2008 {
2009 bool bTwoTokens = ( _pReplaceToken2 != nullptr );
2010 const char* pPlaceHolder1 = bTwoTokens ? "#1" : "#";
2011 const OUString sPlaceHolder1 = OUString::createFromAscii( pPlaceHolder1 );
2012
2013 sErrorMessage = sErrorMessage.replaceFirst( sPlaceHolder1, *_pReplaceToken1 );
2014 if ( _pReplaceToken2 )
2015 sErrorMessage = sErrorMessage.replaceFirst( "#2" , *_pReplaceToken2 );
2016 }
2017
2018 impl_appendError( SQLException(
2019 sErrorMessage, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() ) );
2020}
2021
2022
2023void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError )
2024{
2025 SAL_WARN("connectivity.parse", "Adding error " << exceptionToString(Any(_rError)));
2026 if ( m_xErrors )
2027 {
2028 SQLException* pErrorChain = &*m_xErrors;
2029 while ( pErrorChain->NextException.hasValue() )
2030 pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData );
2031 pErrorChain->NextException <<= _rError;
2032 }
2033 else
2034 m_xErrors = _rError;
2035}
2036
2038{
2039 sal_Int32 nType = DataType::OTHER;
2040 OUString sFunctionName;
2041 if ( SQL_ISRULE(_pNode,length_exp) )
2042 {
2043 _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
2045 }
2046 else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) )
2047 {
2048 nType = DataType::DOUBLE;
2049 }
2050 else
2051 {
2052 _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
2053
2054 // MIN and MAX have another return type, we have to check the expression itself.
2055 // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566
2056 if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) ))
2057 {
2058 const OSQLParseNode* pValueExp = _pNode->getChild(3);
2059 if (SQL_ISRULE(pValueExp,column_ref))
2060 {
2061 OUString sColumnName;
2062 OUString aTableRange;
2063 getColumnRange(pValueExp,sColumnName,aTableRange);
2064 OSL_ENSURE(!sColumnName.isEmpty(),"Columnname must not be empty!");
2065 Reference<XPropertySet> xColumn = findColumn( sColumnName, aTableRange, true );
2066
2067 if ( xColumn.is() )
2068 {
2069 xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType;
2070 }
2071 }
2072 else
2073 {
2074 if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) )
2075 {
2076 nType = DataType::DOUBLE;
2077 }
2078 else if ( SQL_ISRULE(pValueExp,datetime_primary) )
2079 {
2080 switch(pValueExp->getChild(0)->getTokenID() )
2081 {
2082 case SQL_TOKEN_CURRENT_DATE:
2083 nType = DataType::DATE;
2084 break;
2085 case SQL_TOKEN_CURRENT_TIME:
2086 nType = DataType::TIME;
2087 break;
2088 case SQL_TOKEN_CURRENT_TIMESTAMP:
2089 nType = DataType::TIMESTAMP;
2090 break;
2091 }
2092 }
2093 else if ( SQL_ISRULE(pValueExp,value_exp_primary) )
2094 {
2095 nType = getFunctionReturnType(pValueExp->getChild(1));
2096 }
2097 else if ( SQL_ISRULE(pValueExp,concatenation)
2098 || SQL_ISRULE(pValueExp,char_factor)
2099 || SQL_ISRULE(pValueExp,bit_value_fct)
2100 || SQL_ISRULE(pValueExp,char_value_fct)
2101 || SQL_ISRULE(pValueExp,char_substring_fct)
2102 || SQL_ISRULE(pValueExp,fold)
2103 || SQL_ISTOKEN(pValueExp,STRING) )
2104 {
2105 nType = DataType::VARCHAR;
2106 }
2107 }
2108 if ( nType == DataType::OTHER )
2109 nType = DataType::DOUBLE;
2110 }
2111 else
2113 }
2114
2115 return nType;
2116}
2117
2118/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sSchema
OptionalString sCatalog
OptionalString sComposedName
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
#define MIN(x, y)
virtual OUString getErrorMessage(ErrorCode _eCodes) const =0
::dbtools::OPropertyMap & getPropMap()
Definition: TConnection.cxx:68
void parseNodeToStr(OUString &rString, const css::uno::Reference< css::sdbc::XConnection > &_rxConnection, const IParseContext *pContext=nullptr, bool _bIntl=false, bool _bQuote=true) const
sal_uInt32 getTokenID() const
Definition: sqlnode.hxx:350
static OUString getTableRange(const OSQLParseNode *_pTableRef)
return a table range when it exists.
Definition: sqlnode.cxx:2705
Rule getKnownRuleID() const
returns the ID of the rule represented by the node If the node does not represent a rule,...
Definition: sqlnode.cxx:2698
static bool getTableComponents(const OSQLParseNode *_pTableNode, css::uno::Any &_rCatalog, OUString &_rSchema, OUString &_rTable, const css::uno::Reference< css::sdbc::XDatabaseMetaData > &_xMetaData)
Definition: sqlnode.cxx:757
const OUString & getTokenValue() const
Definition: sqlnode.hxx:361
OSQLParseNode * getParent() const
Definition: sqlnode.hxx:251
OSQLParseNode * getChild(sal_uInt32 nPos) const
Definition: sqlnode.hxx:433
SQLNodeType getNodeType() const
Definition: sqlnode.hxx:339
OSQLTable impl_locateRecordSource(const OUString &_rComposedName)
locates a record source (a table or query) with the given name
::std::unique_ptr< OSQLParseTreeIteratorImpl > m_pImpl
Definition: sqliterator.hxx:92
void impl_appendError(IParseContext::ErrorCode _eError, const OUString *_pReplaceToken1=nullptr, const OUString *_pReplaceToken2=nullptr)
appends an SQLException corresponding to the given error code to our error collection
void setSelectColumnName(const OUString &rColumnName, const OUString &rColumnAlias, const OUString &rTableRange, bool bFkt=false, sal_Int32 _nType=css::sdbc::DataType::VARCHAR, bool bAggFkt=false)
void impl_fillJoinConditions(const OSQLParseNode *i_pJoinCondition)
void getSelect_statement(OSQLTables &_rTables, const OSQLParseNode *pSelect)
const ::rtl::Reference< OSQLColumns > & getParameters() const
::rtl::Reference< OSQLColumns > m_aSelectColumns
Definition: sqliterator.hxx:86
const OSQLParseNode * getHavingTree() const
::rtl::Reference< OSQLColumns > m_aCreateColumns
Definition: sqliterator.hxx:90
static css::uno::Reference< css::beans::XPropertySet > findColumn(const OSQLTables &_rTables, const OUString &rColumnName, OUString &rTableRange)
finds the column with a given name, belonging to a given table, in a given tables collection
static OUString getColumnAlias(const OSQLParseNode *_pDerivedColumn)
return the alias name of a column
bool traverseOrderByColumnNames(const OSQLParseNode *pSelectNode)
::rtl::Reference< OSQLColumns > m_aParameters
Definition: sqliterator.hxx:87
void setGroupByColumnName(const OUString &rColumnName, OUString &rTableRange)
std::vector< OUString > getSelectColumnNames() const
void setOrderByColumnName(const OUString &rColumnName, OUString &rTableRange, bool bAscending)
const OSQLParseNode * getSimpleGroupByTree() const
css::uno::Reference< css::beans::XPropertySet > findSelectColumn(std::u16string_view rColumnName)
finds a column with a given name among the select columns
const OSQLParseNode * getGroupByTree() const
void traverseOnePredicate(OSQLParseNode const *pColumnRef, OUString &aValue, OSQLParseNode const *pParameter)
OUString getUniqueColumnName(const std::vector< OUString > &rColumnNames, const OUString &rColumnName) const
void traverseOneTableName(OSQLTables &_rTables, const OSQLParseNode *pTableName, const OUString &rTableRange)
void appendColumns(const OUString &_rTableAlias, const OSQLTable &_rTable)
bool traverseGroupByColumnNames(const OSQLParseNode *pSelectNode)
bool traverseSelectionCriteria(const OSQLParseNode *pSelectNode)
const OSQLTables & getTables() const
void traverseByColumnNames(const OSQLParseNode *pSelectNode, bool _bOrder)
void getColumnRange(const OSQLParseNode *_pColumnRef, OUString &_rColumnName, OUString &_rTableRange) const
return the columname and the table range
void setParseTree(const OSQLParseNode *pNewParseTree)
const OSQLParseNode * getOrderTree() const
void impl_getQueryParameterColumns(const OSQLTable &_rQuery)
retrieves the parameter columns of the given query
const OSQLParseNode * getSimpleHavingTree() const
static bool isTableNode(const OSQLParseNode *_pTableNode)
bool traverseSelectColumnNames(const OSQLParseNode *pSelectNode)
traverses columns in a SELECT statement
::std::vector< TNodePair > & getJoinConditions() const
sal_Int32 getFunctionReturnType(const OSQLParseNode *_pNode)
void impl_traverse(TraversalParts _nIncludeMask)
implementation for both traverseAll and traverseSome
void traverseCreateColumns(const OSQLParseNode *pSelectNode)
traverses columns in a CREATE TABLE statement
void traverseParameters(const OSQLParseNode *pSelectNode)
std::optional< css::sdbc::SQLException > m_xErrors
Definition: sqliterator.hxx:82
OSQLTable impl_createTableObject(const OUString &rTableName, const OUString &rCatalogName, const OUString &rSchemaName)
creates a table object and inserts it into our tables collection
void getQualified_join(OSQLTables &_rTables, const OSQLParseNode *pTableRef, OUString &aTableRange)
void traverseSearchCondition(OSQLParseNode const *pSearchCondition)
const OSQLParseNode * getSimpleWhereTree() const
OSQLStatementType getStatementType() const
void traverseAll()
traverses the complete statement tree, and fills all our data with the information obatined during tr...
void traverseParameter(const OSQLParseNode *_pParseNode, const OSQLParseNode *_pColumnRef, const OUString &_aColumnName, OUString &_aTableRange, const OUString &_rColumnAlias)
::rtl::Reference< OSQLColumns > m_aGroupColumns
Definition: sqliterator.hxx:88
const OSQLParseNode * m_pParseTree
Definition: sqliterator.hxx:83
const OSQLParseNode * getWhereTree() const
::rtl::Reference< OSQLColumns > m_aOrderColumns
Definition: sqliterator.hxx:89
bool traverseTableNames(OSQLTables &_rTables)
traverses the list of table names, and fills _rTables
const OSQLParseNode * getSimpleOrderTree() const
const OSQLParseNode * getTableNode(OSQLTables &_rTables, const OSQLParseNode *pTableRef, OUString &aTableRange)
Parser for SQL92.
Definition: sqlparse.hxx:110
static sal_Int32 getFunctionParameterType(sal_uInt32 _nTokenId, sal_uInt32 _nPos)
Definition: sqlnode.cxx:2584
static sal_Int32 getFunctionReturnType(std::u16string_view _sFunctionName, const IParseContext *pContext)
Definition: sqlnode.cxx:2494
const SQLError & getErrorHelper() const
access to the SQLError instance owned by this parser
Definition: sqlnode.cxx:2692
const IParseContext & getContext() const
Definition: sqlparse.hxx:176
css::sdbc::SQLException getSQLException(const ErrorCondition _eCondition, const css::uno::Reference< css::uno::XInterface > &_rxContext, const std::optional< OUString > &_rParamValue1=std::nullopt, const std::optional< OUString > &_rParamValue2=std::nullopt, const std::optional< OUString > &_rParamValue3=std::nullopt) const
retrieves an SQLException object which contains information about the given error condition
Definition: sqlerror.cxx:285
encapsulates meta data about a database/connection which cannot be obtained from the usual XDatabaseM...
Definition: dbmetadata.hxx:50
bool supportsSubqueriesInFrom() const
determines whether the database supports sub queries in the FROM part of a SELECT clause are supporte...
Definition: dbmetadata.cxx:215
const OUString & getNameByIndex(sal_Int32 _nIndex) const
Definition: propertyids.cxx:95
int nCount
OString exceptionToString(const css::uno::Any &caught)
#define DBG_UNHANDLED_EXCEPTION(...)
float u
FastSaxParserImpl & m_rParser
Reference< XColumn > xColumn
OUString sName
STRING
OUString aName
sal_uInt16 nPos
#define SAL_WARN(area, stream)
RttiCompleteObjectLocator col
@ table
@ Exception
bool getBOOL(const Any &_rAny)
sal_Int32 getINT32(const Any &_rAny)
OUString getString(const Any &_rAny)
std::map< OUString, OSQLTable, comphelper::UStringMixLess > OSQLTables
Definition: CommonTools.hxx:56
ORefVector< css::uno::Reference< css::beans::XPropertySet > > OSQLColumns
Definition: CommonTools.hxx:95
css::uno::Reference< css::sdbcx::XColumnsSupplier > OSQLTable
Definition: CommonTools.hxx:54
::std::pair< const OSQLParseNode *, const OSQLParseNode * > TNodePair
Definition: sqliterator.hxx:63
OUString composeTableName(const Reference< XDatabaseMetaData > &_rxMetaData, const OUString &_rCatalog, const OUString &_rSchema, const OUString &_rName, bool _bQuote, EComposeRule _eComposeRule)
Definition: dbtools.cxx:1286
void qualifiedNameComponents(const Reference< XDatabaseMetaData > &_rxConnMetaData, const OUString &_rQualifiedName, OUString &_rCatalog, OUString &_rSchema, OUString &_rName, EComposeRule _eComposeRule)
Definition: dbtools.cxx:862
OUString getStandardSQLState(StandardSQLState _eState)
returns a standard error string for a given SQLState
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
Reference< XConnection > m_xConnection
sal_Int16 nId
#define PROPERTY_ID_NAME
Definition: propertyids.hxx:50
#define PROPERTY_ID_TYPE
Definition: propertyids.hxx:51
#define PROPERTY_ID_TABLENAME
Definition: propertyids.hxx:78
#define PROPERTY_ID_DESCRIPTION
Definition: propertyids.hxx:58
#define PROPERTY_ID_CATALOGNAME
Definition: propertyids.hxx:70
#define PROPERTY_ID_ISNULLABLE
Definition: propertyids.hxx:55
#define PROPERTY_ID_COMMAND
Definition: propertyids.hxx:72
#define PROPERTY_ID_PRECISION
Definition: propertyids.hxx:53
#define PROPERTY_ID_SCHEMANAME
Definition: propertyids.hxx:69
#define PROPERTY_ID_ISAUTOINCREMENT
Definition: propertyids.hxx:56
#define PROPERTY_ID_ISCURRENCY
Definition: propertyids.hxx:81
#define PROPERTY_ID_TYPENAME
Definition: propertyids.hxx:52
#define PROPERTY_ID_DEFAULTVALUE
Definition: propertyids.hxx:59
#define PROPERTY_ID_REALNAME
Definition: propertyids.hxx:79
#define PROPERTY_ID_ESCAPEPROCESSING
Definition: propertyids.hxx:47
#define PROPERTY_ID_SCALE
Definition: propertyids.hxx:54
QPRO_FUNC_TYPE nType
const Color aColNames[SC_RANGECOLORS]
std::shared_ptr< QueryNameSet > & m_rpAllForbiddenNames
OUString m_sForbiddenQueryName
#define SQL_ISRULE(pParseNode, eRule)
Definition: sqlnode.hxx:439
#define ORDER_BY_CHILD_POS
Definition: sqlnode.hxx:51
#define TABLE_EXPRESSION_CHILD_COUNT
Definition: sqlnode.hxx:52
#define SQL_ISPUNCTUATION(pParseNode, aString)
Definition: sqlnode.hxx:450
#define SQL_ISTOKEN(pParseNode, token)
Definition: sqlnode.hxx:447
#define SQL_ISRULEOR2(pParseNode, e1, e2)
Definition: sqlnode.hxx:440
bool isQueryAllowed(const OUString &_rQueryName)
std::vector< TNodePair > m_aJoinConditions
Definition: sqliterator.cxx:64
OSQLParseTreeIteratorImpl(const Reference< XConnection > &_rxConnection, const Reference< XNameAccess > &_rxTables)
Definition: sqliterator.cxx:78
Reference< XDatabaseMetaData > m_xDatabaseMetaData
Definition: sqliterator.cxx:66
std::shared_ptr< OSQLTables > m_pTables
Definition: sqliterator.cxx:70
std::shared_ptr< QueryNameSet > m_pForbiddenQueryNames
Definition: sqliterator.cxx:72
Reference< XNameAccess > m_xQueryContainer
Definition: sqliterator.cxx:68
Reference< XConnection > m_xConnection
Definition: sqliterator.cxx:65
Reference< XNameAccess > m_xTableContainer
Definition: sqliterator.cxx:67
std::shared_ptr< OSQLTables > m_pSubTables
Definition: sqliterator.cxx:71
IS
AND
OR