Coverage Report

Created: 2026-06-30 11:14

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