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