/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: */ |