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
20 #include <connectivity/sqliterator.hxx>
21 #include <connectivity/sdbcx/VTable.hxx>
22 #include <connectivity/sqlparse.hxx>
23 #include <sqlbison.hxx>
24 #include <connectivity/dbtools.hxx>
25 #include <connectivity/sqlerror.hxx>
26 #include <com/sun/star/sdbc/ColumnValue.hpp>
27 #include <com/sun/star/sdbc/DataType.hpp>
28 #include <com/sun/star/sdbc/XRow.hpp>
29 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
30 #include <com/sun/star/sdb/ErrorCondition.hpp>
31 #ifdef SQL_TEST_PARSETREEITERATOR
32 #include <iostream>
33 #endif
34 #include <connectivity/PColumn.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <TConnection.hxx>
37 #include <comphelper/types.hxx>
38 #include <connectivity/dbmetadata.hxx>
39 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
40 #include <sal/log.hxx>
41
42 #include <iterator>
43 #include <memory>
44
45 using namespace ::comphelper;
46 using namespace ::connectivity;
47 using namespace ::connectivity::sdbcx;
48 using namespace ::dbtools;
49 using namespace ::connectivity::parse;
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::container;
53 using namespace ::com::sun::star::sdbcx;
54 using namespace ::com::sun::star::beans;
55 using namespace ::com::sun::star::sdbc;
56 using namespace ::com::sun::star::sdb;
57
58 namespace connectivity
59 {
60 struct OSQLParseTreeIteratorImpl
61 {
62 std::vector< TNodePair > m_aJoinConditions;
63 Reference< XConnection > m_xConnection;
64 Reference< XDatabaseMetaData > m_xDatabaseMetaData;
65 Reference< XNameAccess > m_xTableContainer;
66 Reference< XNameAccess > m_xQueryContainer;
67
68 std::shared_ptr< OSQLTables > m_pTables; // all tables which participate in the SQL statement
69 std::shared_ptr< OSQLTables > m_pSubTables; // all tables from sub queries not the tables from the select tables
70 std::shared_ptr< QueryNameSet > m_pForbiddenQueryNames;
71
72 TraversalParts m_nIncludeMask;
73
74 bool m_bIsCaseSensitive;
75
OSQLParseTreeIteratorImplconnectivity::OSQLParseTreeIteratorImpl76 OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables )
77 :m_xConnection( _rxConnection )
78 ,m_nIncludeMask( TraversalParts::All )
79 ,m_bIsCaseSensitive( true )
80 {
81 OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" );
82 m_xDatabaseMetaData = m_xConnection->getMetaData();
83
84 m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers();
85 m_pTables.reset( new OSQLTables( m_bIsCaseSensitive ) );
86 m_pSubTables.reset( new OSQLTables( m_bIsCaseSensitive ) );
87
88 m_xTableContainer = _rxTables;
89
90 DatabaseMetaData aMetaData( m_xConnection );
91 if ( aMetaData.supportsSubqueriesInFrom() )
92 {
93 // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection
94 // service
95 Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY );
96 if ( xSuppQueries.is() )
97 m_xQueryContainer = xSuppQueries->getQueries();
98 }
99 }
100
101 public:
isQueryAllowedconnectivity::OSQLParseTreeIteratorImpl102 bool isQueryAllowed( const OUString& _rQueryName )
103 {
104 if ( !m_pForbiddenQueryNames.get() )
105 return true;
106 if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() )
107 return true;
108 return false;
109 }
110 };
111
112
113 /** helper class for temporarily adding a query name to a list of forbidden query names
114 */
115 class ForbidQueryName
116 {
117 std::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames;
118 OUString m_sForbiddenQueryName;
119
120 public:
ForbidQueryName(OSQLParseTreeIteratorImpl & _rIteratorImpl,const OUString & _rForbiddenQueryName)121 ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, const OUString& _rForbiddenQueryName )
122 :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames )
123 ,m_sForbiddenQueryName( _rForbiddenQueryName )
124 {
125 if ( !m_rpAllForbiddenNames.get() )
126 m_rpAllForbiddenNames.reset( new QueryNameSet );
127 m_rpAllForbiddenNames->insert( m_sForbiddenQueryName );
128 }
129
~ForbidQueryName()130 ~ForbidQueryName()
131 {
132 m_rpAllForbiddenNames->erase( m_sForbiddenQueryName );
133 }
134 };
135 }
136
OSQLParseTreeIterator(const Reference<XConnection> & _rxConnection,const Reference<XNameAccess> & _rxTables,const OSQLParser & _rParser)137 OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference< XConnection >& _rxConnection,
138 const Reference< XNameAccess >& _rxTables,
139 const OSQLParser& _rParser )
140 :m_rParser( _rParser )
141 ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection, _rxTables ) )
142 {
143 setParseTree(nullptr);
144 }
145
146
OSQLParseTreeIterator(const OSQLParseTreeIterator & _rParentIterator,const OSQLParser & _rParser,const OSQLParseNode * pRoot)147 OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator& _rParentIterator, const OSQLParser& _rParser, const OSQLParseNode* pRoot )
148 :m_rParser( _rParser )
149 ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator.m_pImpl->m_xConnection, _rParentIterator.m_pImpl->m_xTableContainer ) )
150 {
151 m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames;
152 setParseTree( pRoot );
153 }
154
155
~OSQLParseTreeIterator()156 OSQLParseTreeIterator::~OSQLParseTreeIterator()
157 {
158 dispose();
159 }
160
161
getTables() const162 const OSQLTables& OSQLParseTreeIterator::getTables() const
163 {
164 return *m_pImpl->m_pTables;
165 }
166
167
isCaseSensitive() const168 bool OSQLParseTreeIterator::isCaseSensitive() const
169 {
170 return m_pImpl->m_bIsCaseSensitive;
171 }
172
173
dispose()174 void OSQLParseTreeIterator::dispose()
175 {
176 m_aSelectColumns = nullptr;
177 m_aGroupColumns = nullptr;
178 m_aOrderColumns = nullptr;
179 m_aParameters = nullptr;
180 m_pImpl->m_xTableContainer = nullptr;
181 m_pImpl->m_xDatabaseMetaData = nullptr;
182 m_aCreateColumns = nullptr;
183 m_pImpl->m_pTables->clear();
184 m_pImpl->m_pSubTables->clear();
185 }
186
setParseTree(const OSQLParseNode * pNewParseTree)187 void OSQLParseTreeIterator::setParseTree(const OSQLParseNode * pNewParseTree)
188 {
189 m_pImpl->m_pTables->clear();
190 m_pImpl->m_pSubTables->clear();
191
192 m_aSelectColumns = new OSQLColumns();
193 m_aGroupColumns = new OSQLColumns();
194 m_aOrderColumns = new OSQLColumns();
195 m_aParameters = new OSQLColumns();
196 m_aCreateColumns = new OSQLColumns();
197
198 m_pParseTree = pNewParseTree;
199 if (!m_pParseTree)
200 {
201 m_eStatementType = OSQLStatementType::Unknown;
202 return;
203 }
204
205 // If m_pParseTree, but no connection then return
206 if ( !m_pImpl->m_xTableContainer.is() )
207 return;
208
209 m_aErrors = SQLException();
210
211
212 // Determine statement type ...
213 if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) )
214 {
215 m_eStatementType = OSQLStatementType::Select;
216 }
217 else if (SQL_ISRULE(m_pParseTree,insert_statement))
218 {
219 m_eStatementType = OSQLStatementType::Insert;
220 }
221 else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
222 {
223 m_eStatementType = OSQLStatementType::Update;
224 }
225 else if (SQL_ISRULE(m_pParseTree,delete_statement_searched))
226 {
227 m_eStatementType = OSQLStatementType::Delete;
228 }
229 else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec))
230 {
231 m_eStatementType = OSQLStatementType::OdbcCall;
232 }
233 else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def))
234 {
235 m_eStatementType = OSQLStatementType::CreateTable;
236 m_pParseTree = m_pParseTree->getChild(0);
237 }
238 else
239 {
240 m_eStatementType = OSQLStatementType::Unknown;
241 //aIteratorStatus.setInvalidStatement();
242 return;
243 }
244 }
245
246
247 namespace
248 {
249
impl_getRowString(const Reference<XRow> & _rxRow,const sal_Int32 _nColumnIndex,OUString & _out_rString)250 void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, OUString& _out_rString )
251 {
252 _out_rString = _rxRow->getString( _nColumnIndex );
253 if ( _rxRow->wasNull() )
254 _out_rString.clear();
255 }
256
257
lcl_findTableInMetaData(const Reference<XDatabaseMetaData> & _rxDBMeta,const OUString & _rCatalog,const OUString & _rSchema,const OUString & _rTableName)258 OUString lcl_findTableInMetaData(
259 const Reference< XDatabaseMetaData >& _rxDBMeta, const OUString& _rCatalog,
260 const OUString& _rSchema, const OUString& _rTableName )
261 {
262 OUString sComposedName;
263
264 static const char s_sWildcard[] = "%" ;
265
266 // we want all catalogues, all schemas, all tables
267 Sequence< OUString > sTableTypes(3);
268 sTableTypes[0] = "VIEW";
269 sTableTypes[1] = "TABLE";
270 sTableTypes[2] = s_sWildcard; // just to be sure to include anything else...
271
272 if ( _rxDBMeta.is() )
273 {
274 sComposedName.clear();
275
276 Reference< XResultSet> xRes = _rxDBMeta->getTables(
277 !_rCatalog.isEmpty() ? makeAny( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _rSchema : s_sWildcard, _rTableName, sTableTypes );
278
279 Reference< XRow > xCurrentRow( xRes, UNO_QUERY );
280 if ( xCurrentRow.is() && xRes->next() )
281 {
282 OUString sCatalog, sSchema, sName;
283
284 impl_getRowString( xCurrentRow, 1, sCatalog );
285 impl_getRowString( xCurrentRow, 2, sSchema );
286 impl_getRowString( xCurrentRow, 3, sName );
287
288 sComposedName = ::dbtools::composeTableName(
289 _rxDBMeta,
290 sCatalog,
291 sSchema,
292 sName,
293 false,
294 ::dbtools::EComposeRule::InDataManipulation
295 );
296 }
297 }
298 return sComposedName;
299 }
300 }
301
302
impl_getQueryParameterColumns(const OSQLTable & _rQuery)303 void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable& _rQuery )
304 {
305 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
306 // parameters not to be included in the traversal
307 return;
308
309 ::rtl::Reference pSubQueryParameterColumns( new OSQLColumns() );
310
311 // get the command and the EscapeProcessing properties from the sub query
312 OUString sSubQueryCommand;
313 bool bEscapeProcessing = false;
314 try
315 {
316 Reference< XPropertySet > xQueryProperties( _rQuery, UNO_QUERY_THROW );
317 OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sSubQueryCommand );
318 OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
319 }
320 catch( const Exception& )
321 {
322 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
323 }
324
325 // parse the sub query
326 do {
327
328 if ( !bEscapeProcessing || ( sSubQueryCommand.isEmpty() ) )
329 break;
330
331 OUString sError;
332 std::unique_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand ) );
333 if (!pSubQueryNode)
334 break;
335
336 OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() );
337 aSubQueryIterator.impl_traverse( TraversalParts::Parameters | TraversalParts::SelectColumns );
338 // SelectColumns might also contain parameters #i77635#
339 pSubQueryParameterColumns = aSubQueryIterator.getParameters();
340 aSubQueryIterator.dispose();
341
342 } while ( false );
343
344 // copy the parameters of the sub query to our own parameter array
345 std::copy( pSubQueryParameterColumns->get().begin(), pSubQueryParameterColumns->get().end(),
346 std::insert_iterator< OSQLColumns::Vector >( m_aParameters->get(), m_aParameters->get().end() ) );
347 }
348
349
impl_locateRecordSource(const OUString & _rComposedName)350 OSQLTable OSQLParseTreeIterator::impl_locateRecordSource( const OUString& _rComposedName )
351 {
352 if ( _rComposedName.isEmpty() )
353 {
354 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" );
355 return OSQLTable();
356 }
357
358 OSQLTable aReturn;
359 OUString sComposedName( _rComposedName );
360
361 try
362 {
363 OUString sCatalog, sSchema, sName;
364 qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
365
366 // check whether there is a query with the given name
367 bool bQueryDoesExist = m_pImpl->m_xQueryContainer.is() && m_pImpl->m_xQueryContainer->hasByName( sComposedName );
368
369 // check whether the table container contains an object with the given name
370 if ( !bQueryDoesExist && !m_pImpl->m_xTableContainer->hasByName( sComposedName ) )
371 sComposedName = lcl_findTableInMetaData( m_pImpl->m_xDatabaseMetaData, sCatalog, sSchema, sName );
372 bool bTableDoesExist = m_pImpl->m_xTableContainer->hasByName( sComposedName );
373
374 // now obtain the object
375
376 // if we're creating a table, and there already is a table or query with the same name,
377 // this is worth an error
378 if ( OSQLStatementType::CreateTable == m_eStatementType )
379 {
380 if ( bQueryDoesExist )
381 impl_appendError( IParseContext::ErrorCode::InvalidQueryExist, &sName );
382 else if ( bTableDoesExist )
383 impl_appendError( IParseContext::ErrorCode::InvalidTableExist, &sName );
384 else
385 aReturn = impl_createTableObject( sName, sCatalog, sSchema );
386 }
387 else
388 {
389 // queries win over tables, so if there's a query with this name, take this, no matter if
390 // there's a table, too
391 if ( bQueryDoesExist )
392 {
393 if ( !m_pImpl->isQueryAllowed( sComposedName ) )
394 {
395 impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, nullptr ) );
396 return nullptr;
397 }
398
399 m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn;
400
401 // collect the parameters from the sub query
402 ForbidQueryName aForbidName( *m_pImpl, sComposedName );
403 impl_getQueryParameterColumns( aReturn );
404 }
405 else if ( bTableDoesExist )
406 m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn;
407 else
408 {
409 if ( m_pImpl->m_xQueryContainer.is() )
410 // the connection on which we're working supports sub queries in from (else
411 // m_xQueryContainer would not have been set), so emit a better error message
412 impl_appendError( IParseContext::ErrorCode::InvalidTableOrQuery, &sName );
413 else
414 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sName );
415 }
416 }
417 }
418 catch(Exception&)
419 {
420 impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sComposedName );
421 }
422
423 return aReturn;
424 }
425
426
traverseOneTableName(OSQLTables & _rTables,const OSQLParseNode * pTableName,const OUString & rTableRange)427 void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const OUString & rTableRange )
428 {
429 if ( !( m_pImpl->m_nIncludeMask & TraversalParts::TableNames ) )
430 // tables should not be included in the traversal
431 return;
432
433 OSL_ENSURE(pTableName != nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
434
435 Any aCatalog;
436 OUString aSchema,aTableName,aComposedName;
437 OUString aTableRange(rTableRange);
438
439 // Get table name
440 OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData);
441
442 // create the composed name like DOMAIN.USER.TABLE1
443 aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData,
444 aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : OUString(),
445 aSchema,
446 aTableName,
447 false,
448 ::dbtools::EComposeRule::InDataManipulation);
449
450 // if there is no alias for the table name assign the original name to it
451 if ( aTableRange.isEmpty() )
452 aTableRange = aComposedName;
453
454 // get the object representing this table/query
455 OSQLTable aTable = impl_locateRecordSource( aComposedName );
456 if ( aTable.is() )
457 _rTables[ aTableRange ] = aTable;
458 }
459
impl_fillJoinConditions(const OSQLParseNode * i_pJoinCondition)460 void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode* i_pJoinCondition)
461 {
462 if (i_pJoinCondition->count() == 3 && // Expression with brackets
463 SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") &&
464 SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")"))
465 {
466 impl_fillJoinConditions(i_pJoinCondition->getChild(1));
467 }
468 else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR logic operation:
469 i_pJoinCondition->count() == 3)
470 {
471 // Only allow AND logic operation
472 if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) )
473 {
474 impl_fillJoinConditions(i_pJoinCondition->getChild(0));
475 impl_fillJoinConditions(i_pJoinCondition->getChild(1));
476 }
477 }
478 else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate))
479 {
480 // only the comparison of columns is allowed
481 OSL_ENSURE(i_pJoinCondition->count() == 3,"OQueryDesignView::InsertJoinConnection: error in the parse tree");
482 if (SQL_ISRULE(i_pJoinCondition->getChild(0),column_ref) &&
483 SQL_ISRULE(i_pJoinCondition->getChild(2),column_ref) &&
484 i_pJoinCondition->getChild(1)->getNodeType() == SQLNodeType::Equal)
485 {
486 m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) );
487 }
488 }
489 }
490
getJoinConditions() const491 std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const
492 {
493 return m_pImpl->m_aJoinConditions;
494 }
495
getQualified_join(OSQLTables & _rTables,const OSQLParseNode * pTableRef,OUString & aTableRange)496 void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, OUString& aTableRange )
497 {
498 OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) ,
499 "OSQLParseTreeIterator::getQualified_join: illegal node!" );
500
501 aTableRange.clear();
502
503 const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange);
504 if ( isTableNode( pNode ) )
505 traverseOneTableName( _rTables, pNode, aTableRange );
506
507 sal_uInt32 nPos = 4;
508 if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL)
509 {
510 nPos = 3;
511 // join_condition,named_columns_join
512 if ( SQL_ISRULE( pTableRef, qualified_join ) )
513 {
514 const OSQLParseNode* pJoin_spec = pTableRef->getChild(4);
515 if ( SQL_ISRULE( pJoin_spec, join_condition ) )
516 {
517 impl_fillJoinConditions(pJoin_spec->getChild(1));
518 }
519 else
520 {
521 const OSQLParseNode* pColumnCommalist = pJoin_spec->getChild(2);
522 // All columns in the column_commalist ...
523 for (size_t i = 0; i < pColumnCommalist->count(); i++)
524 {
525 const OSQLParseNode * pCol = pColumnCommalist->getChild(i);
526 // add twice because the column must exists in both tables
527 m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) );
528 }
529 }
530 }
531 }
532
533 pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange);
534 if ( isTableNode( pNode ) )
535 traverseOneTableName( _rTables, pNode, aTableRange );
536 }
537
getTableNode(OSQLTables & _rTables,const OSQLParseNode * pTableRef,OUString & rTableRange)538 const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,OUString& rTableRange )
539 {
540 OSL_PRECOND( SQL_ISRULE( pTableRef, table_ref ) || SQL_ISRULE( pTableRef, joined_table )
541 || SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ),
542 "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" );
543
544 const OSQLParseNode* pTableNameNode = nullptr;
545
546 if ( SQL_ISRULE( pTableRef, joined_table ) )
547 {
548 getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
549 }
550 if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) )
551 {
552 getQualified_join( _rTables, pTableRef, rTableRange );
553 }
554 else
555 {
556 rTableRange = OSQLParseNode::getTableRange(pTableRef);
557 if ( ( pTableRef->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
558 || ( pTableRef->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist
559 )
560 {
561 getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange );
562 }
563 else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')'
564 {
565 const OSQLParseNode* pSubQuery = pTableRef->getChild(0);
566 if ( pSubQuery->isToken() )
567 {
568 getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
569 }
570 else
571 {
572 OSL_ENSURE( pSubQuery->count() == 3, "sub queries should have 3 children!" );
573 const OSQLParseNode* pQueryExpression = pSubQuery->getChild(1);
574 if ( SQL_ISRULE( pQueryExpression, select_statement ) )
575 {
576 getSelect_statement( *m_pImpl->m_pSubTables, pQueryExpression );
577 // TODO: now, we need to setup an OSQLTable from pQueryExpression in some way
578 // and stick it in _rTables[rTableRange]. Probably fake it by
579 // setting up a full OSQLParseTreeIterator on pQueryExpression
580 // and using its m_aSelectColumns
581 // This is necessary in stuff like "SELECT * FROM tbl1 INNER JOIN (SELECT foo, bar FROM tbl2) AS tbl3"
582 // so that setSelectColumnName() can expand the "*" correctly.
583 // See e.g. R_UserAndLastSubscription query of https://bugs.libreoffice.org/attachment.cgi?id=71871
584 }
585 else
586 {
587 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" );
588 }
589 }
590 }
591 else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column
592 {
593 pTableNameNode = pTableRef->getChild(0);
594 }
595 else
596 SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" );
597 }
598
599 return pTableNameNode;
600 }
601
getSelect_statement(OSQLTables & _rTables,const OSQLParseNode * pSelect)602 void OSQLParseTreeIterator::getSelect_statement(OSQLTables& _rTables,const OSQLParseNode* pSelect)
603 {
604 if(SQL_ISRULE(pSelect,union_statement))
605 {
606 getSelect_statement(_rTables,pSelect->getChild(0));
607 //getSelect_statement(pSelect->getChild(3));
608 return;
609 }
610 OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1);
611
612 OSL_ENSURE(pTableRefCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
613 OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!");
614
615 const OSQLParseNode* pTableName = nullptr;
616 OUString aTableRange;
617 for (size_t i = 0; i < pTableRefCommalist->count(); i++)
618 { // Process FROM clause
619 aTableRange.clear();
620
621 const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i);
622 if ( isTableNode( pTableListElement ) )
623 {
624 traverseOneTableName( _rTables, pTableListElement, aTableRange );
625 }
626 else if ( SQL_ISRULE( pTableListElement, table_ref ) )
627 {
628 // Table references can be made up of table names, table names (+),'('joined_table')'(+)
629 pTableName = pTableListElement->getChild(0);
630 if( isTableNode( pTableName ) )
631 { // Found table names
632 aTableRange = OSQLParseNode::getTableRange(pTableListElement);
633 traverseOneTableName( _rTables, pTableName, aTableRange );
634 }
635 else if(SQL_ISPUNCTUATION(pTableName,"{"))
636 { // '{' SQL_TOKEN_OJ joined_table '}'
637 getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange );
638 }
639 else
640 { // '(' joined_table ')' range_variable op_column_commalist
641 getTableNode( _rTables, pTableListElement, aTableRange );
642 }
643 }
644 else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) )
645 {
646 getQualified_join( _rTables, pTableListElement, aTableRange );
647 }
648 else if ( SQL_ISRULE( pTableListElement, joined_table ) )
649 {
650 getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange );
651 }
652
653 // if (! aIteratorStatus.IsSuccessful()) break;
654 }
655 }
656
traverseTableNames(OSQLTables & _rTables)657 bool OSQLParseTreeIterator::traverseTableNames(OSQLTables& _rTables)
658 {
659 if ( m_pParseTree == nullptr )
660 return false;
661
662 OSQLParseNode* pTableName = nullptr;
663
664 switch ( m_eStatementType )
665 {
666 case OSQLStatementType::Select:
667 getSelect_statement( _rTables, m_pParseTree );
668 break;
669
670 case OSQLStatementType::CreateTable:
671 case OSQLStatementType::Insert:
672 case OSQLStatementType::Delete:
673 pTableName = m_pParseTree->getChild(2);
674 break;
675
676 case OSQLStatementType::Update:
677 pTableName = m_pParseTree->getChild(1);
678 break;
679 default:
680 break;
681 }
682
683 if ( pTableName )
684 {
685 traverseOneTableName( _rTables, pTableName, OUString() );
686 }
687
688 return !hasErrors();
689 }
690
getColumnAlias(const OSQLParseNode * _pDerivedColumn)691 OUString OSQLParseTreeIterator::getColumnAlias(const OSQLParseNode* _pDerivedColumn)
692 {
693 OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!");
694 OUString sColumnAlias;
695 if(_pDerivedColumn->getChild(1)->count() == 2)
696 sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue();
697 else if(!_pDerivedColumn->getChild(1)->isRule())
698 sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue();
699 return sColumnAlias;
700 }
701
702
703 namespace
704 {
lcl_getColumnRange(const OSQLParseNode * _pColumnRef,const Reference<XConnection> & _rxConnection,OUString & _out_rColumnName,OUString & _out_rTableRange,const OSQLColumns * _pSelectColumns,OUString & _out_rColumnAliasIfPresent)705 void lcl_getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection,
706 OUString& _out_rColumnName, OUString& _out_rTableRange,
707 const OSQLColumns* _pSelectColumns, OUString& _out_rColumnAliasIfPresent )
708 {
709 _out_rColumnName.clear();
710 _out_rTableRange.clear();
711 _out_rColumnAliasIfPresent.clear();
712 if ( SQL_ISRULE( _pColumnRef, column_ref ) )
713 {
714 if( _pColumnRef->count() > 1 )
715 {
716 for ( sal_Int32 i=0; i<static_cast<sal_Int32>(_pColumnRef->count())-2; ++i )
717 _pColumnRef->getChild(i)->parseNodeToStr( _out_rTableRange, _rxConnection, nullptr, false, false );
718 _out_rColumnName = _pColumnRef->getChild( _pColumnRef->count()-1 )->getChild(0)->getTokenValue();
719 }
720 else
721 _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue();
722
723 // look up the column in the select column, to find a possible alias
724 if ( _pSelectColumns )
725 {
726 for (const Reference< XPropertySet >& xColumn : _pSelectColumns->get())
727 {
728 try
729 {
730 OUString sName, sTableName;
731 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) >>= sName;
732 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName;
733 if ( sName == _out_rColumnName && ( _out_rTableRange.isEmpty() || sTableName == _out_rTableRange ) )
734 {
735 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent;
736 break;
737 }
738 }
739 catch( const Exception& )
740 {
741 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
742 }
743 }
744 }
745 }
746 else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec))
747 { // Function
748 _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection );
749 }
750 else if(_pColumnRef->getNodeType() == SQLNodeType::Name)
751 _out_rColumnName = _pColumnRef->getTokenValue();
752 }
753 }
754
755
getColumnRange(const OSQLParseNode * _pColumnRef,OUString & _rColumnName,OUString & _rTableRange) const756 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
757 OUString& _rColumnName,
758 OUString& _rTableRange) const
759 {
760 OUString sDummy;
761 lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, nullptr, sDummy );
762 }
763
764
getColumnRange(const OSQLParseNode * _pColumnRef,OUString & _rColumnName,OUString & _rTableRange,OUString & _out_rColumnAliasIfPresent) const765 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
766 OUString& _rColumnName,
767 OUString& _rTableRange,
768 OUString& _out_rColumnAliasIfPresent ) const
769 {
770 lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent );
771 }
772
773
getColumnRange(const OSQLParseNode * _pColumnRef,const Reference<XConnection> & _rxConnection,OUString & _out_rColumnName,OUString & _out_rTableRange)774 void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
775 const Reference< XConnection >& _rxConnection, OUString& _out_rColumnName, OUString& _out_rTableRange )
776 {
777 OUString sDummy;
778 lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, nullptr, sDummy );
779 }
780
781
traverseCreateColumns(const OSQLParseNode * pSelectNode)782 void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode* pSelectNode)
783 {
784 // aIteratorStatus.Clear();
785
786 if (!pSelectNode || m_eStatementType != OSQLStatementType::CreateTable || m_pImpl->m_pTables->empty())
787 {
788 impl_appendError( IParseContext::ErrorCode::General );
789 return;
790 }
791 if (!SQL_ISRULE(pSelectNode,base_table_element_commalist))
792 return ;
793
794 for (size_t i = 0; i < pSelectNode->count(); i++)
795 {
796 OSQLParseNode *pColumnRef = pSelectNode->getChild(i);
797
798 if (SQL_ISRULE(pColumnRef,column_def))
799 {
800 OUString aColumnName;
801 OUString aTypeName;
802 sal_Int32 nType = DataType::VARCHAR;
803 aColumnName = pColumnRef->getChild(0)->getTokenValue();
804
805 OSQLParseNode *pDatatype = pColumnRef->getChild(1);
806 if (pDatatype && SQL_ISRULE(pDatatype,character_string_type))
807 {
808 const OSQLParseNode *pType = pDatatype->getChild(0);
809 aTypeName = pType->getTokenValue();
810 if (pDatatype->count() == 2 && (pType->getTokenID() == SQL_TOKEN_CHAR || pType->getTokenID() == SQL_TOKEN_CHARACTER ))
811 nType = DataType::CHAR;
812 }
813 else if(pDatatype && pDatatype->getNodeType() == SQLNodeType::Keyword)
814 {
815 aTypeName = "VARCHAR";
816 }
817
818 if (!aTypeName.isEmpty())
819 {
820 //TODO:Create a new class for create statement to handle field length
821 OParseColumn* pColumn = new OParseColumn(aColumnName,aTypeName,OUString(),OUString(),
822 ColumnValue::NULLABLE_UNKNOWN,0,0,nType,false,false,isCaseSensitive(),
823 OUString(),OUString(),OUString());
824 pColumn->setFunction(false);
825 pColumn->setRealName(aColumnName);
826
827 Reference< XPropertySet> xCol = pColumn;
828 m_aCreateColumns->get().push_back(xCol);
829 }
830 }
831
832 }
833 }
834
traverseSelectColumnNames(const OSQLParseNode * pSelectNode)835 bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode* pSelectNode)
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 {
842 impl_appendError( IParseContext::ErrorCode::General );
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(m_aSelectColumns, "*", "", "");
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(m_aSelectColumns, "*", "", 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(m_aSelectColumns,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
traverseOrderByColumnNames(const OSQLParseNode * pSelectNode)937 bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode* pSelectNode)
938 {
939 traverseByColumnNames( pSelectNode, true );
940 return !hasErrors();
941 }
942
traverseByColumnNames(const OSQLParseNode * pSelectNode,bool _bOrder)943 void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode* pSelectNode, bool _bOrder)
944 {
945 // aIteratorStatus.Clear();
946
947 if (pSelectNode == nullptr)
948 {
949 //aIteratorStatus.setInvalidStatement();
950 return;
951 }
952
953 if (m_eStatementType != OSQLStatementType::Select)
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
traverseGroupByColumnNames(const OSQLParseNode * pSelectNode)1027 bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode* pSelectNode)
1028 {
1029 traverseByColumnNames( pSelectNode, false );
1030 return !hasErrors();
1031 }
1032
1033
1034 namespace
1035 {
lcl_generateParameterName(const OSQLParseNode & _rParentNode,const OSQLParseNode & _rParamNode)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
traverseParameters(const OSQLParseNode * _pNode)1053 void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode* _pNode)
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
traverseSelectionCriteria(const OSQLParseNode * pSelectNode)1106 bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode* pSelectNode)
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
1116 if (m_eStatementType == OSQLStatementType::Select)
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
traverseSearchCondition(OSQLParseNode const * pSearchCondition)1168 void OSQLParseTreeIterator::traverseSearchCondition(OSQLParseNode const * pSearchCondition)
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 nCurentPos = pPart2->count()-2;
1220
1221 OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurentPos);
1222 OSQLParseNode * pOptEscape = pPart2->getChild(nCurentPos+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 );
1262 traverseSelectionCriteria(pChild->getChild(0)->getChild(1));
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 {
1270 traverseSearchCondition(pChild->getChild(i));
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
traverseParameter(const OSQLParseNode * _pParseNode,const OSQLParseNode * _pParentNode,const OUString & _aColumnName,OUString & _aTableRange,const OUString & _rColumnAlias)1293 void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode* _pParseNode
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 }
1343 sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode->getChild(0)->getTokenID(), i-1);
1344
1345 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,
1355 isCaseSensitive(),
1356 OUString(),
1357 OUString(),
1358 OUString());
1359 pColumn->setFunction(true);
1360 pColumn->setAggregateFunction(true);
1361 pColumn->setRealName(sFunctionName);
1362 m_aParameters->get().push_back(pColumn);
1363 }
1364 else
1365 {
1366 bool bNotFound = true;
1367 OSQLColumns::Vector::const_iterator aIter = ::connectivity::find(
1368 m_aSelectColumns->get().begin(),
1369 m_aSelectColumns->get().end(),
1370 _aColumnName,::comphelper::UStringMixEqual( isCaseSensitive() )
1371 );
1372 if(aIter != m_aSelectColumns->get().end())
1373 {
1374 OParseColumn* pNewColumn = new OParseColumn(*aIter,isCaseSensitive());
1375 pNewColumn->setName(sParameterName);
1376 pNewColumn->setRealName(_aColumnName);
1377 m_aParameters->get().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 OParseColumn* pNewColumn = new OParseColumn(xColumn,isCaseSensitive());
1388 pNewColumn->setName(sParameterName);
1389 pNewColumn->setRealName(_aColumnName);
1390 m_aParameters->get().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 }
1407 nType = ::connectivity::OSQLParser::getFunctionParameterType( pParent->getChild(0)->getTokenID(), i+1);
1408 }
1409
1410 OUString aNewColName( getUniqueColumnName( sParameterName ) );
1411
1412 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,
1422 isCaseSensitive(),
1423 OUString(),
1424 OUString(),
1425 OUString());
1426 pColumn->setName(aNewColName);
1427 pColumn->setRealName(sParameterName);
1428 m_aParameters->get().push_back(pColumn);
1429 }
1430 }
1431 }
1432
traverseOnePredicate(OSQLParseNode const * pColumnRef,OUString & rValue,OSQLParseNode const * pParseNode)1433 void OSQLParseTreeIterator::traverseOnePredicate(
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
traverseAll()1459 void OSQLParseTreeIterator::traverseAll()
1460 {
1461 impl_traverse( TraversalParts::All );
1462 }
1463
1464
impl_traverse(TraversalParts _nIncludeMask)1465 void OSQLParseTreeIterator::impl_traverse( TraversalParts _nIncludeMask )
1466 {
1467 // resets our errors
1468 m_aErrors = css::sdbc::SQLException();
1469
1470 m_pImpl->m_nIncludeMask = _nIncludeMask;
1471
1472 if ( !traverseTableNames( *m_pImpl->m_pTables ) )
1473 return;
1474
1475 switch ( m_eStatementType )
1476 {
1477 case OSQLStatementType::Select:
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;
1489 case OSQLStatementType::CreateTable:
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;
1497 case OSQLStatementType::Insert:
1498 break;
1499 default:
1500 break;
1501 }
1502 }
1503
1504 // Dummy implementations
1505
1506
impl_createTableObject(const OUString & rTableName,const OUString & rCatalogName,const OUString & rSchemaName)1507 OSQLTable OSQLParseTreeIterator::impl_createTableObject( const OUString& rTableName,
1508 const OUString& rCatalogName, const OUString& rSchemaName )
1509 {
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)
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
appendColumns(::rtl::Reference<OSQLColumns> const & _rColumns,const OUString & _rTableAlias,const OSQLTable & _rTable)1527 void OSQLParseTreeIterator::appendColumns(::rtl::Reference<OSQLColumns> const & _rColumns,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
1540 for(;pBegin != pEnd;++pBegin)
1541 {
1542
1543 OUString aName(getUniqueColumnName(*pBegin));
1544 Reference< XPropertySet > xColumn;
1545 if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is())
1546 {
1547 OParseColumn* pColumn = new OParseColumn(aName
1548 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
1549 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
1550 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
1551 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
1552 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
1553 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
1554 , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
1555 , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
1556 , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
1557 , isCaseSensitive()
1558 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
1559 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
1560 , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))));
1561
1562 pColumn->setTableName(_rTableAlias);
1563 pColumn->setRealName(*pBegin);
1564 Reference< XPropertySet> xCol = pColumn;
1565 _rColumns->get().push_back(xCol);
1566 }
1567 else
1568 impl_appendError( IParseContext::ErrorCode::InvalidColumn, pBegin, &_rTableAlias );
1569 }
1570 }
1571
setSelectColumnName(::rtl::Reference<OSQLColumns> const & _rColumns,const OUString & rColumnName,const OUString & rColumnAlias,const OUString & rTableRange,bool bFkt,sal_Int32 _nType,bool bAggFkt)1572 void OSQLParseTreeIterator::setSelectColumnName(::rtl::Reference<OSQLColumns> const & _rColumns,const OUString & rColumnName,const OUString & rColumnAlias, const OUString & rTableRange, bool bFkt, sal_Int32 _nType, bool bAggFkt)
1573 {
1574 if(rColumnName.toChar() == '*' && rTableRange.isEmpty())
1575 { // SELECT * ...
1576 OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!");
1577 for (auto const& table : *m_pImpl->m_pTables)
1578 appendColumns(_rColumns,table.first,table.second);
1579 }
1580 else if( rColumnName.toChar() == '*' && !rTableRange.isEmpty() )
1581 { // SELECT <table>.*
1582 OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!");
1583 OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
1584
1585 if(aFind != m_pImpl->m_pTables->end())
1586 appendColumns(_rColumns,rTableRange,aFind->second);
1587 }
1588 else if ( rTableRange.isEmpty() )
1589 { // SELECT <something> ...
1590 // without table specified
1591 if ( !bFkt )
1592 {
1593 Reference< XPropertySet> xNewColumn;
1594
1595 for (auto const& table : *m_pImpl->m_pTables)
1596 {
1597 if ( !table.second.is() )
1598 continue;
1599
1600 Reference<XNameAccess> xColumns = table.second->getColumns();
1601 Reference< XPropertySet > xColumn;
1602 if ( !xColumns->hasByName( rColumnName )
1603 || !( xColumns->getByName( rColumnName ) >>= xColumn )
1604 )
1605 continue;
1606
1607 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1608
1609 OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive());
1610 xNewColumn = pColumn;
1611 pColumn->setTableName(table.first);
1612 pColumn->setName(aNewColName);
1613 pColumn->setRealName(rColumnName);
1614
1615 break;
1616 }
1617
1618 if ( !xNewColumn.is() )
1619 {
1620 // no function (due to the above !bFkt), no existing column
1621 // => assume an expression
1622 OUString aNewColName( getUniqueColumnName( rColumnAlias ) );
1623 // did not find a column with this name in any of the tables
1624 OParseColumn* pColumn = new OParseColumn(
1625 aNewColName,
1626 "VARCHAR",
1627 // TODO: does this match with _nType?
1628 // Or should be fill this from the getTypeInfo of the connection?
1629 OUString(),
1630 OUString(),
1631 ColumnValue::NULLABLE_UNKNOWN,
1632 0,
1633 0,
1634 _nType,
1635 false,
1636 false,
1637 isCaseSensitive(),
1638 OUString(),
1639 OUString(),
1640 OUString()
1641 );
1642
1643 xNewColumn = pColumn;
1644 pColumn->setRealName( rColumnName );
1645 }
1646
1647 _rColumns->get().push_back( xNewColumn );
1648 }
1649 else
1650 {
1651 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1652
1653 OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1654 ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
1655 OUString(),OUString(),OUString());
1656 pColumn->setFunction(true);
1657 pColumn->setAggregateFunction(bAggFkt);
1658 pColumn->setRealName(rColumnName);
1659
1660 Reference< XPropertySet> xCol = pColumn;
1661 _rColumns->get().push_back(xCol);
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(rColumnAlias));
1674
1675 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 Reference< XPropertySet> xCol = pColumn;
1686 _rColumns->get().push_back(xCol);
1687 }
1688 else
1689 {
1690 Reference< XPropertySet > xColumn;
1691 if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn))
1692 {
1693 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1694
1695 OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive());
1696 pColumn->setName(aNewColName);
1697 pColumn->setRealName(rColumnName);
1698 pColumn->setTableName(aFind->first);
1699
1700 Reference< XPropertySet> xCol = pColumn;
1701 _rColumns->get().push_back(xCol);
1702 }
1703 else
1704 bError = true;
1705 }
1706 }
1707 else
1708 bError = true;
1709
1710 // Table does not exist or lacking field
1711 if (bError)
1712 {
1713 OUString aNewColName(getUniqueColumnName(rColumnAlias));
1714
1715 OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
1716 ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,false,false,isCaseSensitive(),
1717 OUString(),OUString(),OUString());
1718 pColumn->setFunction(true);
1719 pColumn->setAggregateFunction(bAggFkt);
1720
1721 Reference< XPropertySet> xCol = pColumn;
1722 _rColumns->get().push_back(xCol);
1723 }
1724 }
1725 }
1726
getUniqueColumnName(const OUString & rColumnName) const1727 OUString OSQLParseTreeIterator::getUniqueColumnName(const OUString & rColumnName) const
1728 {
1729 OUString aAlias(rColumnName);
1730
1731 OSQLColumns::Vector::const_iterator aIter = find(
1732 m_aSelectColumns->get().begin(),
1733 m_aSelectColumns->get().end(),
1734 aAlias,
1735 ::comphelper::UStringMixEqual( isCaseSensitive() )
1736 );
1737 sal_Int32 i=1;
1738 while(aIter != m_aSelectColumns->get().end())
1739 {
1740 aAlias = rColumnName + OUString::number(i++);
1741 aIter = find(
1742 m_aSelectColumns->get().begin(),
1743 m_aSelectColumns->get().end(),
1744 aAlias,
1745 ::comphelper::UStringMixEqual( isCaseSensitive() )
1746 );
1747 }
1748 return aAlias;
1749 }
1750
setOrderByColumnName(const OUString & rColumnName,OUString & rTableRange,bool bAscending)1751 void OSQLParseTreeIterator::setOrderByColumnName(const OUString & rColumnName, OUString & rTableRange, bool bAscending)
1752 {
1753 Reference<XPropertySet> xColumn = findSelectColumn( rColumnName );
1754 if ( !xColumn.is() )
1755 xColumn = findColumn ( rColumnName, rTableRange, false );
1756 if ( xColumn.is() )
1757 m_aOrderColumns->get().push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) );
1758 else
1759 {
1760 sal_Int32 nId = rColumnName.toInt32();
1761 if ( nId > 0 && nId < static_cast<sal_Int32>(m_aSelectColumns->get().size()) )
1762 m_aOrderColumns->get().push_back( new OOrderColumn( ( m_aSelectColumns->get() )[nId-1], isCaseSensitive(), bAscending ) );
1763 }
1764
1765 #ifdef SQL_TEST_PARSETREEITERATOR
1766 cout << "OSQLParseTreeIterator::setOrderByColumnName: "
1767 << (const char *) rColumnName << ", "
1768 << (const char *) rTableRange << ", "
1769 << (bAscending ? "true" : "false")
1770 << "\n";
1771 #endif
1772 }
1773
setGroupByColumnName(const OUString & rColumnName,OUString & rTableRange)1774 void OSQLParseTreeIterator::setGroupByColumnName(const OUString & rColumnName, OUString & rTableRange)
1775 {
1776 Reference<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false );
1777 if ( xColumn.is() )
1778 m_aGroupColumns->get().push_back(new OParseColumn(xColumn,isCaseSensitive()));
1779 else
1780 {
1781 sal_Int32 nId = rColumnName.toInt32();
1782 if ( nId > 0 && nId < static_cast<sal_Int32>(m_aSelectColumns->get().size()) )
1783 m_aGroupColumns->get().push_back(new OParseColumn((m_aSelectColumns->get())[nId-1],isCaseSensitive()));
1784 }
1785
1786 #ifdef SQL_TEST_PARSETREEITERATOR
1787 cout << "OSQLParseTreeIterator::setGroupByColumnName: "
1788 << (const char *) rColumnName << ", "
1789 << (const char *) rTableRange << ", "
1790 << (bAscending ? "true" : "false")
1791 << "\n";
1792 #endif
1793 }
1794
1795
getWhereTree() const1796 const OSQLParseNode* OSQLParseTreeIterator::getWhereTree() const
1797 {
1798 if (!m_pParseTree)
1799 return nullptr;
1800
1801 // Analyse parse tree (depending on statement type)
1802 // and set pointer to WHERE clause:
1803 OSQLParseNode * pWhereClause = nullptr;
1804 if(getStatementType() == OSQLStatementType::Select)
1805 {
1806 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1807 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1808 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1809 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1810 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1811
1812 pWhereClause = pTableExp->getChild(1);
1813 }
1814 else if (SQL_ISRULE(m_pParseTree,update_statement_searched) ||
1815 SQL_ISRULE(m_pParseTree,delete_statement_searched))
1816 {
1817 pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1);
1818 }
1819 if(pWhereClause && pWhereClause->count() != 2)
1820 pWhereClause = nullptr;
1821 return pWhereClause;
1822 }
1823
1824
getOrderTree() const1825 const OSQLParseNode* OSQLParseTreeIterator::getOrderTree() const
1826 {
1827 if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
1828 return nullptr;
1829
1830 // Analyse parse tree (depending on statement type)
1831 // and set pointer to ORDER clause:
1832 OSQLParseNode * pOrderClause = nullptr;
1833 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1834 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1835 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1836 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1837 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1838
1839 pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
1840 // If it is an order_by, it must not be empty
1841 if(pOrderClause->count() != 3)
1842 pOrderClause = nullptr;
1843 return pOrderClause;
1844 }
1845
getGroupByTree() const1846 const OSQLParseNode* OSQLParseTreeIterator::getGroupByTree() const
1847 {
1848 if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
1849 return nullptr;
1850
1851 // Analyse parse tree (depending on statement type)
1852 // and set pointer to ORDER clause:
1853 OSQLParseNode * pGroupClause = nullptr;
1854 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1855 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1856 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1857 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1858 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1859
1860 pGroupClause = pTableExp->getChild(2);
1861 // If it is an order_by, it must not be empty
1862 if(pGroupClause->count() != 3)
1863 pGroupClause = nullptr;
1864 return pGroupClause;
1865 }
1866
getHavingTree() const1867 const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const
1868 {
1869 if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
1870 return nullptr;
1871
1872 // Analyse parse tree (depending on statement type)
1873 // and set pointer to ORDER clause:
1874 OSQLParseNode * pHavingClause = nullptr;
1875 OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
1876 OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
1877 OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
1878 OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
1879 OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
1880
1881 pHavingClause = pTableExp->getChild(3);
1882 // If it is an order_by, then it must not be empty
1883 if(pHavingClause->count() < 1)
1884 pHavingClause = nullptr;
1885 return pHavingClause;
1886 }
1887
isTableNode(const OSQLParseNode * _pTableNode)1888 bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode* _pTableNode)
1889 {
1890 return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) ||
1891 SQL_ISRULE(_pTableNode,schema_name) ||
1892 SQL_ISRULE(_pTableNode,table_name));
1893 }
1894
getSimpleWhereTree() const1895 const OSQLParseNode* OSQLParseTreeIterator::getSimpleWhereTree() const
1896 {
1897 const OSQLParseNode* pNode = getWhereTree();
1898 return pNode ? pNode->getChild(1) : nullptr;
1899 }
1900
getSimpleOrderTree() const1901 const OSQLParseNode* OSQLParseTreeIterator::getSimpleOrderTree() const
1902 {
1903 const OSQLParseNode* pNode = getOrderTree();
1904 return pNode ? pNode->getChild(2) : nullptr;
1905 }
1906
getSimpleGroupByTree() const1907 const OSQLParseNode* OSQLParseTreeIterator::getSimpleGroupByTree() const
1908 {
1909 const OSQLParseNode* pNode = getGroupByTree();
1910 return pNode ? pNode->getChild(2) : nullptr;
1911 }
1912
getSimpleHavingTree() const1913 const OSQLParseNode* OSQLParseTreeIterator::getSimpleHavingTree() const
1914 {
1915 const OSQLParseNode* pNode = getHavingTree();
1916 return pNode ? pNode->getChild(1) : nullptr;
1917 }
1918
1919
findSelectColumn(const OUString & rColumnName)1920 Reference< XPropertySet > OSQLParseTreeIterator::findSelectColumn( const OUString & rColumnName )
1921 {
1922 for (auto const& lookupColumn : m_aSelectColumns->get())
1923 {
1924 Reference< XPropertySet > xColumn( lookupColumn );
1925 try
1926 {
1927 OUString sName;
1928 xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sName;
1929 if ( sName == rColumnName )
1930 return xColumn;
1931 }
1932 catch( const Exception& )
1933 {
1934 DBG_UNHANDLED_EXCEPTION("connectivity.parse");
1935 }
1936 }
1937 return nullptr;
1938 }
1939
1940
findColumn(const OUString & rColumnName,OUString & rTableRange,bool _bLookInSubTables)1941 Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const OUString & rColumnName, OUString & rTableRange, bool _bLookInSubTables )
1942 {
1943 Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange );
1944 if ( !xColumn.is() && _bLookInSubTables )
1945 xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange );
1946 return xColumn;
1947 }
1948
1949
findColumn(const OSQLTables & _rTables,const OUString & rColumnName,OUString & rTableRange)1950 Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables, const OUString & rColumnName, OUString & rTableRange)
1951 {
1952 Reference< XPropertySet > xColumn;
1953 if ( !rTableRange.isEmpty() )
1954 {
1955 OSQLTables::const_iterator aFind = _rTables.find(rTableRange);
1956
1957 if ( aFind != _rTables.end()
1958 && aFind->second.is()
1959 && aFind->second->getColumns().is()
1960 && aFind->second->getColumns()->hasByName(rColumnName) )
1961 aFind->second->getColumns()->getByName(rColumnName) >>= xColumn;
1962 }
1963 if ( !xColumn.is() )
1964 {
1965 for (auto const& table : _rTables)
1966 {
1967 if ( table.second.is() )
1968 {
1969 Reference<XNameAccess> xColumns = table.second->getColumns();
1970 if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) )
1971 {
1972 OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!");
1973 // Cannot take "rTableRange = table.first" because that is the fully composed name
1974 // that is, catalogName.schemaName.tableName
1975 rTableRange = getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)));
1976 break; // This column must only exits once
1977 }
1978 }
1979 }
1980 }
1981 return xColumn;
1982 }
1983
1984
impl_appendError(IParseContext::ErrorCode _eError,const OUString * _pReplaceToken1,const OUString * _pReplaceToken2)1985 void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const OUString* _pReplaceToken1, const OUString* _pReplaceToken2 )
1986 {
1987 OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError );
1988 if ( _pReplaceToken1 )
1989 {
1990 bool bTwoTokens = ( _pReplaceToken2 != nullptr );
1991 const sal_Char* pPlaceHolder1 = bTwoTokens ? "#1" : "#";
1992 const OUString sPlaceHolder1 = OUString::createFromAscii( pPlaceHolder1 );
1993
1994 sErrorMessage = sErrorMessage.replaceFirst( sPlaceHolder1, *_pReplaceToken1 );
1995 if ( _pReplaceToken2 )
1996 sErrorMessage = sErrorMessage.replaceFirst( "#2" , *_pReplaceToken2 );
1997 }
1998
1999 impl_appendError( SQLException(
2000 sErrorMessage, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() ) );
2001 }
2002
2003
impl_appendError(const SQLException & _rError)2004 void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError )
2005 {
2006 if ( !m_aErrors.Message.isEmpty() )
2007 {
2008 SQLException* pErrorChain = &m_aErrors;
2009 while ( pErrorChain->NextException.hasValue() )
2010 pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData );
2011 pErrorChain->NextException <<= _rError;
2012 }
2013 else
2014 m_aErrors = _rError;
2015 }
2016
getFunctionReturnType(const OSQLParseNode * _pNode)2017 sal_Int32 OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode* _pNode )
2018 {
2019 sal_Int32 nType = DataType::OTHER;
2020 OUString sFunctionName;
2021 if ( SQL_ISRULE(_pNode,length_exp) )
2022 {
2023 _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
2024 nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
2025 }
2026 else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) )
2027 {
2028 nType = DataType::DOUBLE;
2029 }
2030 else
2031 {
2032 _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
2033
2034 // MIN and MAX have another return type, we have to check the expression itself.
2035 // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566
2036 if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) ))
2037 {
2038 const OSQLParseNode* pValueExp = _pNode->getChild(3);
2039 if (SQL_ISRULE(pValueExp,column_ref))
2040 {
2041 OUString sColumnName;
2042 OUString aTableRange;
2043 getColumnRange(pValueExp,sColumnName,aTableRange);
2044 OSL_ENSURE(!sColumnName.isEmpty(),"Columnname must not be empty!");
2045 Reference<XPropertySet> xColumn = findColumn( sColumnName, aTableRange, true );
2046
2047 if ( xColumn.is() )
2048 {
2049 xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType;
2050 }
2051 }
2052 else
2053 {
2054 if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) )
2055 {
2056 nType = DataType::DOUBLE;
2057 }
2058 else if ( SQL_ISRULE(pValueExp,datetime_primary) )
2059 {
2060 switch(pValueExp->getChild(0)->getTokenID() )
2061 {
2062 case SQL_TOKEN_CURRENT_DATE:
2063 nType = DataType::DATE;
2064 break;
2065 case SQL_TOKEN_CURRENT_TIME:
2066 nType = DataType::TIME;
2067 break;
2068 case SQL_TOKEN_CURRENT_TIMESTAMP:
2069 nType = DataType::TIMESTAMP;
2070 break;
2071 }
2072 }
2073 else if ( SQL_ISRULE(pValueExp,value_exp_primary) )
2074 {
2075 nType = getFunctionReturnType(pValueExp->getChild(1));
2076 }
2077 else if ( SQL_ISRULE(pValueExp,concatenation)
2078 || SQL_ISRULE(pValueExp,char_factor)
2079 || SQL_ISRULE(pValueExp,bit_value_fct)
2080 || SQL_ISRULE(pValueExp,char_value_fct)
2081 || SQL_ISRULE(pValueExp,char_substring_fct)
2082 || SQL_ISRULE(pValueExp,fold)
2083 || SQL_ISTOKEN(pValueExp,STRING) )
2084 {
2085 nType = DataType::VARCHAR;
2086 }
2087 }
2088 if ( nType == DataType::OTHER )
2089 nType = DataType::DOUBLE;
2090 }
2091 else
2092 nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
2093 }
2094
2095 return nType;
2096 }
2097
2098 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2099