nss: upgrade to release 3.73
[LibreOffice.git] / dbaccess / source / core / api / SingleSelectQueryComposer.cxx
blob6ca83d6d9879c6810a2f340aaa874b39f4f0564e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
21 #include <sal/log.hxx>
22 #include <composertools.hxx>
23 #include <strings.hrc>
24 #include <core_resource.hxx>
25 #include <stringconstants.hxx>
26 #include "HelperCollections.hxx"
27 #include <SingleSelectQueryComposer.hxx>
28 #include <sqlbison.hxx>
29 #include <sdbcoretools.hxx>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/i18n/LocaleData.hpp>
33 #include <com/sun/star/script/Converter.hpp>
34 #include <com/sun/star/sdb/BooleanComparisonMode.hpp>
35 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
36 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
37 #include <com/sun/star/sdb/CommandType.hpp>
38 #include <com/sun/star/sdbc/ColumnSearch.hpp>
39 #include <com/sun/star/sdbc/DataType.hpp>
40 #include <com/sun/star/sdbc/XConnection.hpp>
41 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
42 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
43 #include <com/sun/star/sdbc/XParameters.hpp>
44 #include <com/sun/star/util/NumberFormatter.hpp>
46 #include <comphelper/types.hxx>
47 #include <cppuhelper/exc_hlp.hxx>
48 #include <connectivity/dbtools.hxx>
49 #include <connectivity/PColumn.hxx>
50 #include <connectivity/predicateinput.hxx>
51 #include <tools/diagnose_ex.h>
52 #include <osl/diagnose.h>
53 #include <unotools/sharedunocomponent.hxx>
55 #include <memory>
56 #include <string_view>
58 using namespace ::dbaccess;
59 using namespace ::dbtools;
60 using namespace ::comphelper;
61 using namespace ::connectivity;
62 using namespace ::com::sun::star::uno;
63 using namespace ::com::sun::star::beans;
64 using namespace ::com::sun::star::sdbc;
65 using namespace ::com::sun::star::sdb;
66 using namespace ::com::sun::star::sdbcx;
67 using namespace ::com::sun::star::container;
68 using namespace ::com::sun::star::i18n;
69 using namespace ::com::sun::star::lang;
70 using namespace ::com::sun::star::script;
71 using namespace ::com::sun::star::util;
72 using namespace ::cppu;
73 using namespace ::osl;
74 using namespace ::utl;
76 namespace dbaccess {
77 namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;
80 #define STR_SELECT "SELECT "
81 #define STR_FROM " FROM "
82 #define STR_WHERE " WHERE "
83 #define STR_GROUP_BY " GROUP BY "
84 #define STR_HAVING " HAVING "
85 #define STR_ORDER_BY " ORDER BY "
86 #define STR_AND " AND "
87 #define STR_OR " OR "
88 #define STR_LIKE OUString(" LIKE ")
89 #define L_BRACKET "("
90 #define R_BRACKET ")"
91 #define COMMA ","
93 namespace
95 /** parses the given statement, using the given parser, returns a parse node representing
96 the statement
98 If the statement cannot be parsed, an error is thrown.
100 std::unique_ptr<OSQLParseNode> parseStatement_throwError( OSQLParser& _rParser, const OUString& _rStatement, const Reference< XInterface >& _rxContext )
102 OUString aErrorMsg;
103 std::unique_ptr<OSQLParseNode> pNewSqlParseNode = _rParser.parseTree( aErrorMsg, _rStatement );
104 if ( !pNewSqlParseNode )
106 OUString sSQLStateGeneralError( getStandardSQLState( StandardSQLState::GENERAL_ERROR ) );
107 SQLException aError2( aErrorMsg, _rxContext, sSQLStateGeneralError, 1000, Any() );
108 SQLException aError1( _rStatement, _rxContext, sSQLStateGeneralError, 1000, makeAny( aError2 ) );
109 throw SQLException(_rParser.getContext().getErrorMessage(OParseContext::ErrorCode::General),_rxContext,sSQLStateGeneralError,1000,makeAny(aError1));
111 return pNewSqlParseNode;
114 /** checks whether the given parse node describes a valid single select statement, throws
115 an error if not
117 void checkForSingleSelect_throwError( const OSQLParseNode* pStatementNode, OSQLParseTreeIterator& _rIterator,
118 const Reference< XInterface >& _rxContext, const OUString& _rOriginatingCommand )
120 const OSQLParseNode* pOldNode = _rIterator.getParseTree();
122 // determine the statement type
123 _rIterator.setParseTree( pStatementNode );
124 _rIterator.traverseAll();
125 bool bIsSingleSelect = ( _rIterator.getStatementType() == OSQLStatementType::Select );
127 // throw the error, if necessary
128 if ( !bIsSingleSelect || SQL_ISRULE( pStatementNode, union_statement ) ) // #i4229# OJ
130 // restore the old node before throwing the exception
131 _rIterator.setParseTree( pOldNode );
132 // and now really ...
133 SQLException aError1( _rOriginatingCommand, _rxContext, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() );
134 throw SQLException( DBA_RES( RID_STR_ONLY_QUERY ), _rxContext,
135 getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, makeAny( aError1 ) );
138 delete pOldNode;
141 /** combines parseStatement_throwError and checkForSingleSelect_throwError
143 void parseAndCheck_throwError( OSQLParser& _rParser, const OUString& _rStatement,
144 OSQLParseTreeIterator& _rIterator, const Reference< XInterface >& _rxContext )
146 std::unique_ptr<OSQLParseNode> pNode = parseStatement_throwError( _rParser, _rStatement, _rxContext );
147 checkForSingleSelect_throwError( pNode.release(), _rIterator, _rxContext, _rStatement );
150 /** transforms a parse node describing a complete statement into a pure select
151 statement, without any filter/order/groupby/having clauses
153 OUString getPureSelectStatement( const OSQLParseNode* _pRootNode, const Reference< XConnection >& _rxConnection )
155 OUString sSQL = STR_SELECT;
156 _pRootNode->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
157 _pRootNode->getChild(2)->parseNodeToStr( sSQL, _rxConnection );
158 sSQL += STR_FROM;
159 _pRootNode->getChild(3)->getChild(0)->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
160 return sSQL;
163 /** resets an SQL iterator, including deletion of the parse tree, and dispose
165 void resetIterator( OSQLParseTreeIterator& _rIterator )
167 const OSQLParseNode* pSqlParseNode = _rIterator.getParseTree();
168 _rIterator.setParseTree(nullptr);
169 delete pSqlParseNode;
170 _rIterator.dispose();
172 void lcl_addFilterCriteria_throw(sal_Int32 i_nFilterOperator,const OUString& i_sValue,OUStringBuffer& o_sRet)
174 switch( i_nFilterOperator )
176 case SQLFilterOperator::EQUAL:
177 o_sRet.append(" = " ).append( i_sValue);
178 break;
179 case SQLFilterOperator::NOT_EQUAL:
180 o_sRet.append(" <> " ).append( i_sValue);
181 break;
182 case SQLFilterOperator::LESS:
183 o_sRet.append(" < " ).append( i_sValue);
184 break;
185 case SQLFilterOperator::GREATER:
186 o_sRet.append(" > " ).append( i_sValue);
187 break;
188 case SQLFilterOperator::LESS_EQUAL:
189 o_sRet.append(" <= " ).append( i_sValue);
190 break;
191 case SQLFilterOperator::GREATER_EQUAL:
192 o_sRet.append(" >= " ).append( i_sValue);
193 break;
194 case SQLFilterOperator::LIKE:
195 o_sRet.append(" LIKE " ).append( i_sValue);
196 break;
197 case SQLFilterOperator::NOT_LIKE:
198 o_sRet.append(" NOT LIKE " ).append( i_sValue);
199 break;
200 case SQLFilterOperator::SQLNULL:
201 o_sRet.append(" IS NULL");
202 break;
203 case SQLFilterOperator::NOT_SQLNULL:
204 o_sRet.append(" IS NOT NULL");
205 break;
206 default:
207 throw SQLException();
214 OSingleSelectQueryComposer::OSingleSelectQueryComposer(const Reference< XNameAccess>& _rxTables,
215 const Reference< XConnection>& _xConnection,
216 const Reference<XComponentContext>& _rContext )
217 :OSubComponent(m_aMutex,_xConnection)
218 ,OPropertyContainer(m_aBHelper)
219 ,m_aSqlParser( _rContext, &m_aParseContext )
220 ,m_aSqlIterator( _xConnection, _rxTables, m_aSqlParser )
221 ,m_aAdditiveIterator( _xConnection, _rxTables, m_aSqlParser )
222 ,m_aElementaryParts( size_t(SQLPartCount) )
223 ,m_xConnection(_xConnection)
224 ,m_xMetaData(_xConnection->getMetaData())
225 ,m_xConnectionTables( _rxTables )
226 ,m_aContext( _rContext )
227 ,m_nBoolCompareMode( BooleanComparisonMode::EQUAL_INTEGER )
228 ,m_nCommandType(CommandType::COMMAND)
230 if ( !m_aContext.is() || !m_xConnection.is() || !m_xConnectionTables.is() )
231 throw IllegalArgumentException();
233 registerProperty(PROPERTY_ORIGINAL,PROPERTY_ID_ORIGINAL,PropertyAttribute::BOUND|PropertyAttribute::READONLY,&m_sOriginal,cppu::UnoType<decltype(m_sOriginal)>::get());
235 m_aCurrentColumns.resize(4);
237 m_aLocale = m_aParseContext.getPreferredLocale();
238 m_xNumberFormatsSupplier = dbtools::getNumberFormats( m_xConnection, true, m_aContext );
239 Reference< XLocaleData4 > xLocaleData( LocaleData::create(m_aContext) );
240 LocaleDataItem aData = xLocaleData->getLocaleItem(m_aLocale);
241 m_sDecimalSep = aData.decimalSeparator;
242 OSL_ENSURE(m_sDecimalSep.getLength() == 1,"OSingleSelectQueryComposer::OSingleSelectQueryComposer decimal separator is not 1 length");
245 Any aValue;
246 Reference<XInterface> xDs = dbaccess::getDataSource(_xConnection);
247 if ( dbtools::getDataSourceSetting(xDs,static_cast <OUString> (PROPERTY_BOOLEANCOMPARISONMODE),aValue) )
249 OSL_VERIFY( aValue >>= m_nBoolCompareMode );
251 Reference< XQueriesSupplier > xQueriesAccess(m_xConnection, UNO_QUERY);
252 if (xQueriesAccess.is())
253 m_xConnectionQueries = xQueriesAccess->getQueries();
255 catch(Exception&)
260 OSingleSelectQueryComposer::~OSingleSelectQueryComposer()
264 // OComponentHelper
265 void SAL_CALL OSingleSelectQueryComposer::disposing()
267 OSubComponent::disposing();
269 MutexGuard aGuard(m_aMutex);
271 resetIterator( m_aSqlIterator );
272 resetIterator( m_aAdditiveIterator );
274 m_xConnectionTables = nullptr;
275 m_xConnection = nullptr;
277 clearCurrentCollections();
280 IMPLEMENT_FORWARD_XINTERFACE3(OSingleSelectQueryComposer,OSubComponent,OSingleSelectQueryComposer_BASE,OPropertyContainer)
281 IMPLEMENT_SERVICE_INFO1(OSingleSelectQueryComposer,"org.openoffice.comp.dba.OSingleSelectQueryComposer",SERVICE_NAME_SINGLESELECTQUERYCOMPOSER)
283 css::uno::Sequence<sal_Int8> OSingleSelectQueryComposer::getImplementationId()
285 return css::uno::Sequence<sal_Int8>();
288 IMPLEMENT_GETTYPES3(OSingleSelectQueryComposer,OSubComponent,OSingleSelectQueryComposer_BASE,OPropertyContainer)
289 IMPLEMENT_PROPERTYCONTAINER_DEFAULTS(OSingleSelectQueryComposer)
291 // XSingleSelectQueryAnalyzer
292 OUString SAL_CALL OSingleSelectQueryComposer::getQuery( )
294 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
295 ::osl::MutexGuard aGuard( m_aMutex );
297 TGetParseNode F_tmp(&OSQLParseTreeIterator::getParseTree);
298 return getStatementPart(F_tmp,m_aSqlIterator);
301 void SAL_CALL OSingleSelectQueryComposer::setQuery( const OUString& command )
303 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
305 ::osl::MutexGuard aGuard( m_aMutex );
306 m_nCommandType = CommandType::COMMAND;
307 // first clear the tables and columns
308 clearCurrentCollections();
309 // now set the new one
310 setQuery_Impl(command);
311 m_sOriginal = command;
313 // reset the additive iterator to the same statement
314 parseAndCheck_throwError( m_aSqlParser, m_sOriginal, m_aAdditiveIterator, *this );
316 // we have no "elementary" parts anymore (means filter/groupby/having/order clauses)
317 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
318 m_aElementaryParts[ eLoopParts ].clear();
321 void SAL_CALL OSingleSelectQueryComposer::setCommand( const OUString& Command,sal_Int32 _nCommandType )
323 OUStringBuffer sSQL;
324 switch(_nCommandType)
326 case CommandType::COMMAND:
327 setElementaryQuery(Command);
328 return;
329 case CommandType::TABLE:
330 if ( m_xConnectionTables->hasByName(Command) )
332 sSQL.append("SELECT * FROM ");
333 Reference< XPropertySet > xTable;
336 m_xConnectionTables->getByName( Command ) >>= xTable;
338 catch(const WrappedTargetException& e)
340 SQLException e2;
341 if ( e.TargetException >>= e2 )
342 throw e2;
344 catch(Exception&)
346 DBG_UNHANDLED_EXCEPTION("dbaccess");
349 sSQL.append(dbtools::composeTableNameForSelect(m_xConnection,xTable));
351 else
353 OUString sMessage( DBA_RES( RID_STR_TABLE_DOES_NOT_EXIST ) );
354 throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
356 break;
357 case CommandType::QUERY:
358 if ( m_xConnectionQueries->hasByName(Command) )
361 Reference<XPropertySet> xQuery(m_xConnectionQueries->getByName(Command),UNO_QUERY);
362 OUString sCommand;
363 xQuery->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
364 sSQL.append(sCommand);
366 else
368 OUString sMessage( DBA_RES( RID_STR_QUERY_DOES_NOT_EXIST ) );
369 throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
372 break;
373 default:
374 break;
376 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
378 ::osl::MutexGuard aGuard( m_aMutex );
379 m_nCommandType = _nCommandType;
380 m_sCommand = Command;
381 // first clear the tables and columns
382 clearCurrentCollections();
383 // now set the new one
384 OUString sCommand = sSQL.makeStringAndClear();
385 setElementaryQuery(sCommand);
386 m_sOriginal = sCommand;
389 void OSingleSelectQueryComposer::setQuery_Impl( const OUString& command )
391 // parse this
392 parseAndCheck_throwError( m_aSqlParser, command, m_aSqlIterator, *this );
394 // strip it from all clauses, to have the pure SELECT statement
395 m_aPureSelectSQL = getPureSelectStatement( m_aSqlIterator.getParseTree(), m_xConnection );
397 // update tables
398 getTables();
401 Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredHavingClause( )
403 TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleHavingTree);
404 return getStructuredCondition(F_tmp);
407 Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredFilter( )
409 TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
410 return getStructuredCondition(F_tmp);
413 void SAL_CALL OSingleSelectQueryComposer::appendHavingClauseByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
415 auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetHavingClause);
416 setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
419 void SAL_CALL OSingleSelectQueryComposer::appendFilterByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
421 auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetFilter);
422 setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
425 OUString OSingleSelectQueryComposer::impl_getColumnRealName_throw(const Reference< XPropertySet >& column, bool bGroupBy)
427 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
429 getColumns();
430 if ( !column.is()
431 || !m_aCurrentColumns[SelectColumns]
432 || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
435 OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
436 SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
437 throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,makeAny(aErr) );
440 OUString aName, aNewName;
441 column->getPropertyValue(PROPERTY_NAME) >>= aName;
443 if ( bGroupBy &&
444 !m_xMetaData->supportsGroupByUnrelated() &&
445 m_aCurrentColumns[SelectColumns] &&
446 !m_aCurrentColumns[SelectColumns]->hasByName(aName) )
448 OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
449 throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
452 OUString aQuote = m_xMetaData->getIdentifierQuoteString();
453 if ( m_aCurrentColumns[SelectColumns]->hasByName(aName) )
455 Reference<XPropertySet> xColumn;
456 m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
457 OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
458 OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
459 OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName("Function"),"Property FUNCTION not available!");
461 OUString sRealName, sTableName;
462 xColumn->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
463 xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
464 bool bFunction = false;
465 xColumn->getPropertyValue("Function") >>= bFunction;
466 if ( sRealName == aName )
468 if ( bFunction )
469 aNewName = aName;
470 else
472 if(sTableName.indexOf('.') != -1)
474 OUString aCatlog,aSchema,aTable;
475 ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
476 sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
478 else if (!sTableName.isEmpty())
479 sTableName = ::dbtools::quoteName(aQuote,sTableName);
481 if(sTableName.isEmpty())
482 aNewName = ::dbtools::quoteName(aQuote,sRealName);
483 else
484 aNewName = sTableName + "." + ::dbtools::quoteName(aQuote,sRealName);
487 else
488 aNewName = ::dbtools::quoteName(aQuote,aName);
490 else
491 aNewName = getTableAlias(column) + ::dbtools::quoteName(aQuote,aName);
492 return aNewName;
495 OUString OSingleSelectQueryComposer::impl_getColumnNameOrderBy_throw(const Reference< XPropertySet >& column)
497 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
499 getColumns();
500 if ( !column.is()
501 || !m_aCurrentColumns[SelectColumns]
502 || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
505 OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
506 SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
507 throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,makeAny(aErr) );
510 OUString aName;
511 column->getPropertyValue(PROPERTY_NAME) >>= aName;
513 const OUString aQuote = m_xMetaData->getIdentifierQuoteString();
515 if ( m_aCurrentColumns[SelectColumns] &&
516 m_aCurrentColumns[SelectColumns]->hasByName(aName) )
518 // It is a column from the SELECT list, use it as such.
519 return ::dbtools::quoteName(aQuote,aName);
522 // Nope, it is an unrelated column.
523 // Is that supported?
524 if ( !m_xMetaData->supportsOrderByUnrelated() )
526 OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
527 throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
530 // We need to refer to it by its "real" name, that is by schemaName.tableName.columnNameInTable
531 return impl_getColumnRealName_throw(column, false);
534 void SAL_CALL OSingleSelectQueryComposer::appendOrderByColumn( const Reference< XPropertySet >& column, sal_Bool ascending )
536 ::osl::MutexGuard aGuard( m_aMutex );
537 OUString sColumnName( impl_getColumnNameOrderBy_throw(column) );
538 OUString sOrder = getOrder();
539 if ( !(sOrder.isEmpty() || sColumnName.isEmpty()) )
540 sOrder += COMMA;
541 sOrder += sColumnName;
542 if ( !(ascending || sColumnName.isEmpty()) )
543 sOrder += " DESC ";
545 setOrder(sOrder);
548 void SAL_CALL OSingleSelectQueryComposer::appendGroupByColumn( const Reference< XPropertySet >& column)
550 ::osl::MutexGuard aGuard( m_aMutex );
551 OUString sColumnName( impl_getColumnRealName_throw(column, true) );
552 OrderCreator aComposer;
553 aComposer.append( getGroup() );
554 aComposer.append( sColumnName );
555 setGroup( aComposer.getComposedAndClear() );
558 OUString OSingleSelectQueryComposer::composeStatementFromParts( const std::vector< OUString >& _rParts )
560 OSL_ENSURE( _rParts.size() == size_t(SQLPartCount), "OSingleSelectQueryComposer::composeStatementFromParts: invalid parts array!" );
562 OUStringBuffer aSql( m_aPureSelectSQL );
563 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
564 if ( !_rParts[ eLoopParts ].isEmpty() )
566 aSql.append( getKeyword( eLoopParts ) );
567 aSql.append( _rParts[ eLoopParts ] );
570 return aSql.makeStringAndClear();
573 OUString SAL_CALL OSingleSelectQueryComposer::getElementaryQuery()
575 return composeStatementFromParts( m_aElementaryParts );
578 void SAL_CALL OSingleSelectQueryComposer::setElementaryQuery( const OUString& _rElementary )
580 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
581 ::osl::MutexGuard aGuard( m_aMutex );
583 // remember the 4 current "additive" clauses
584 std::vector< OUString > aAdditiveClauses( SQLPartCount );
585 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
586 aAdditiveClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, false );
588 // clear the tables and columns
589 clearCurrentCollections();
590 // set and parse the new query
591 setQuery_Impl( _rElementary );
593 // get the 4 elementary parts of the statement
594 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
595 m_aElementaryParts[ eLoopParts ] = getSQLPart( eLoopParts, m_aSqlIterator, false );
597 // reset the AdditiveIterator: m_aPureSelectSQL may have changed
600 parseAndCheck_throwError( m_aSqlParser, composeStatementFromParts( aAdditiveClauses ), m_aAdditiveIterator, *this );
602 catch( const Exception& )
604 DBG_UNHANDLED_EXCEPTION("dbaccess");
605 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setElementaryQuery: there should be no error anymore for the additive statement!" );
606 // every part of the additive statement should have passed other tests already, and should not
607 // be able to cause any errors ... me thinks
611 namespace
613 OUString getComposedClause( const OUString& _rElementaryClause, const OUString& _rAdditionalClause,
614 TokenComposer& _rComposer, const OUString& _rKeyword )
616 _rComposer.clear();
617 _rComposer.append( _rElementaryClause );
618 _rComposer.append( _rAdditionalClause );
619 OUString sComposed = _rComposer.getComposedAndClear();
620 if ( !sComposed.isEmpty() )
621 sComposed = _rKeyword + sComposed;
622 return sComposed;
626 void OSingleSelectQueryComposer::setSingleAdditiveClause( SQLPart _ePart, const OUString& _rClause )
628 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
629 ::osl::MutexGuard aGuard( m_aMutex );
631 // if nothing is changed, do nothing
632 if ( getSQLPart( _ePart, m_aAdditiveIterator, false ) == _rClause )
633 return;
635 // collect the 4 single parts as they're currently set
636 std::vector< OUString > aClauses;
637 aClauses.reserve( size_t(SQLPartCount) );
638 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
639 aClauses.push_back( getSQLPart( eLoopParts, m_aSqlIterator, true ) );
641 // overwrite the one part in question here
642 std::unique_ptr< TokenComposer > pComposer;
643 if ( ( _ePart == Where ) || ( _ePart == Having ) )
644 pComposer.reset( new FilterCreator );
645 else
646 pComposer.reset( new OrderCreator );
647 aClauses[ _ePart ] = getComposedClause( m_aElementaryParts[ _ePart ], _rClause,
648 *pComposer, getKeyword( _ePart ) );
650 // construct the complete statement
651 OUStringBuffer aSql(m_aPureSelectSQL);
652 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
653 aSql.append(aClauses[ eLoopParts ]);
655 // set the query
656 setQuery_Impl(aSql.makeStringAndClear());
658 // clear column collections which (might) have changed
659 clearColumns( ParameterColumns );
660 if ( _ePart == Order )
661 clearColumns( OrderColumns );
662 else if ( _ePart == Group )
663 clearColumns( GroupByColumns );
665 // also, since the "additive filter" change, we need to rebuild our "additive" statement
666 aSql = m_aPureSelectSQL;
667 // again, first get all the old additive parts
668 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
669 aClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, true );
670 // then overwrite the one in question
671 aClauses[ _ePart ] = getComposedClause( OUString(), _rClause, *pComposer, getKeyword( _ePart ) );
672 // and parse it, so that m_aAdditiveIterator is up to date
673 for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
674 aSql.append(aClauses[ eLoopParts ]);
677 parseAndCheck_throwError( m_aSqlParser, aSql.makeStringAndClear(), m_aAdditiveIterator, *this );
679 catch( const Exception& )
681 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setSingleAdditiveClause: there should be no error anymore for the additive statement!" );
682 // every part of the additive statement should have passed other tests already, and should not
683 // be able to cause any errors ... me thinks
687 void SAL_CALL OSingleSelectQueryComposer::setFilter( const OUString& filter )
689 setSingleAdditiveClause( Where, filter );
692 void SAL_CALL OSingleSelectQueryComposer::setOrder( const OUString& order )
694 setSingleAdditiveClause( Order, order );
697 void SAL_CALL OSingleSelectQueryComposer::setGroup( const OUString& group )
699 setSingleAdditiveClause( Group, group );
702 void SAL_CALL OSingleSelectQueryComposer::setHavingClause( const OUString& filter )
704 setSingleAdditiveClause( Having, filter );
707 // XTablesSupplier
708 Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getTables( )
710 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
712 ::osl::MutexGuard aGuard( m_aMutex );
713 if ( !m_pTables )
715 const OSQLTables& aTables = m_aSqlIterator.getTables();
716 std::vector< OUString> aNames;
717 for (auto const& elem : aTables)
718 aNames.push_back(elem.first);
720 m_pTables.reset( new OPrivateTables(aTables,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames) );
723 return m_pTables.get();
726 // XColumnsSupplier
727 Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getColumns( )
729 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
730 ::osl::MutexGuard aGuard( m_aMutex );
731 if ( !!m_aCurrentColumns[SelectColumns] )
732 return m_aCurrentColumns[SelectColumns].get();
734 std::vector< OUString> aNames;
735 ::rtl::Reference< OSQLColumns> aSelectColumns;
736 bool bCase = true;
737 Reference< XNameAccess> xQueryColumns;
738 if ( m_nCommandType == CommandType::QUERY )
740 Reference<XColumnsSupplier> xSup(m_xConnectionQueries->getByName(m_sCommand),UNO_QUERY);
741 if(xSup.is())
742 xQueryColumns = xSup->getColumns();
745 do {
749 SharedUNOComponent< XStatement, DisposableComponent > xStatement;
750 SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
752 bCase = m_xMetaData->supportsMixedCaseQuotedIdentifiers();
753 aSelectColumns = m_aSqlIterator.getSelectColumns();
755 OUStringBuffer aSQL( m_aPureSelectSQL + STR_WHERE " ( 0 = 1 )");
757 // preserve the original WHERE clause
758 // #i102234#
759 OUString sOriginalWhereClause = getSQLPart( Where, m_aSqlIterator, false );
760 if ( !sOriginalWhereClause.isEmpty() )
762 aSQL.append( " AND ( " ).append( sOriginalWhereClause ).append( " ) " );
765 OUString sGroupBy = getSQLPart( Group, m_aSqlIterator, true );
766 if ( !sGroupBy.isEmpty() )
767 aSQL.append( sGroupBy );
769 OUString sSQL( aSQL.makeStringAndClear() );
770 // normalize the statement so that it doesn't contain any application-level features anymore
771 OUString sError;
772 const std::unique_ptr< OSQLParseNode > pStatementTree( m_aSqlParser.parseTree( sError, sSQL ) );
773 OSL_ENSURE(pStatementTree, "OSingleSelectQueryComposer::getColumns: could not parse the "
774 "column retrieval statement!");
775 if (pStatementTree)
776 if ( !pStatementTree->parseNodeToExecutableStatement( sSQL, m_xConnection, m_aSqlParser, nullptr ) )
777 break;
779 Reference< XResultSetMetaData > xResultSetMeta;
780 Reference< XResultSetMetaDataSupplier > xResMetaDataSup;
783 xPreparedStatement.set( m_xConnection->prepareStatement( sSQL ), UNO_QUERY_THROW );
784 xResMetaDataSup.set( xPreparedStatement, UNO_QUERY_THROW );
785 xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
787 catch( const Exception& ) { }
789 if ( !xResultSetMeta.is() && xPreparedStatement.is() )
793 //@see issue http://qa.openoffice.org/issues/show_bug.cgi?id=110111
794 // access returns a different order of column names when executing select * from
795 // and asking the columns from the metadata.
796 Reference< XParameters > xParameters( xPreparedStatement, UNO_QUERY_THROW );
797 Reference< XIndexAccess > xPara = getParameters();
798 for(sal_Int32 i = 1;i <= xPara->getCount();++i)
799 xParameters->setNull(i,DataType::VARCHAR);
800 xResMetaDataSup.set(xPreparedStatement->executeQuery(), UNO_QUERY_THROW );
801 xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
803 catch( const Exception& ) { }
806 if ( !xResultSetMeta.is() )
808 xStatement.reset( Reference< XStatement >( m_xConnection->createStatement(), UNO_SET_THROW ) );
809 Reference< XPropertySet > xStatementProps( xStatement, UNO_QUERY_THROW );
810 try { xStatementProps->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, makeAny( false ) ); }
811 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
812 xResMetaDataSup.set( xStatement->executeQuery( sSQL ), UNO_QUERY_THROW );
813 xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
815 if (xResultSetMeta.is())
817 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getColumns failed to get xResultSetMeta from executed PreparedStatement, but got it from 'no escape processing' statement. SQL command:\n\t" << sSQL );
821 if ( aSelectColumns->empty() )
823 // This is a valid case. If we can syntactically parse the query, but not semantically
824 // (e.g. because it is based on a table we do not know), then there will be no SelectColumns
825 aSelectColumns = ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, m_xMetaData ,xQueryColumns);
826 break;
829 const ::comphelper::UStringMixEqual aCaseCompare( bCase );
830 std::set< size_t > aUsedSelectColumns;
831 ::connectivity::parse::OParseColumn::StringMap aColumnNames;
833 sal_Int32 nCount = xResultSetMeta->getColumnCount();
834 OSL_ENSURE( static_cast<size_t>(nCount) == aSelectColumns->size(), "OSingleSelectQueryComposer::getColumns: inconsistent column counts, this might result in wrong columns!" );
835 for(sal_Int32 i=1;i<=nCount;++i)
837 OUString sColumnName = xResultSetMeta->getColumnName(i);
838 OUString sColumnLabel;
839 if ( xQueryColumns.is() && xQueryColumns->hasByName(sColumnName) )
841 Reference<XPropertySet> xQueryColumn(xQueryColumns->getByName(sColumnName),UNO_QUERY_THROW);
842 xQueryColumn->getPropertyValue(PROPERTY_LABEL) >>= sColumnLabel;
844 else
845 sColumnLabel = xResultSetMeta->getColumnLabel(i);
846 bool bFound = false;
847 OSQLColumns::Vector::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),sColumnLabel,aCaseCompare);
848 size_t nFoundSelectColumnPos = aFind - aSelectColumns->begin();
849 if ( aFind != aSelectColumns->end() )
851 if ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
852 { // we found a column name which exists twice
853 // so we start after the first found
856 aFind = ::connectivity::findRealName(++aFind,aSelectColumns->end(),sColumnName,aCaseCompare);
857 nFoundSelectColumnPos = aFind - aSelectColumns->begin();
859 while ( ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
860 && ( aFind != aSelectColumns->end() )
863 if ( aFind != aSelectColumns->end() )
865 (*aFind)->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
866 aUsedSelectColumns.insert( nFoundSelectColumnPos );
867 aNames.push_back(sColumnName);
868 bFound = true;
872 if ( bFound )
873 continue;
875 OSQLColumns::Vector::const_iterator aRealFind = ::connectivity::findRealName(
876 aSelectColumns->begin(), aSelectColumns->end(), sColumnName, aCaseCompare );
878 if ( i > static_cast< sal_Int32>( aSelectColumns->size() ) )
880 aSelectColumns->emplace_back(::connectivity::parse::OParseColumn::createColumnForResultSet( xResultSetMeta, m_xMetaData, i ,aColumnNames)
882 OSL_ENSURE( aSelectColumns->size() == static_cast<size_t>(i), "OSingleSelectQueryComposer::getColumns: inconsistency!" );
884 else if ( aRealFind == aSelectColumns->end() )
886 // we can now only look if we found it under the realname property
887 // here we have to make the assumption that the position is correct
888 OSQLColumns::Vector::const_iterator aFind2 = aSelectColumns->begin() + i-1;
889 Reference<XPropertySet> xProp = *aFind2;
890 if ( !xProp.is() || !xProp->getPropertySetInfo()->hasPropertyByName( PROPERTY_REALNAME ) )
891 continue;
893 ::connectivity::parse::OParseColumn* pColumn = new ::connectivity::parse::OParseColumn(xProp,bCase);
894 pColumn->setFunction(::comphelper::getBOOL(xProp->getPropertyValue("Function")));
895 pColumn->setAggregateFunction(::comphelper::getBOOL(xProp->getPropertyValue("AggregateFunction")));
897 OUString sRealName;
898 xProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
899 if ( sColumnName.isEmpty() )
900 xProp->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
902 sal_Int32 j = 0;
903 while ( std::any_of(aNames.begin(),aNames.end(),
904 [&aCaseCompare, &sColumnName](const OUString& lhs)
905 { return aCaseCompare(lhs, sColumnName); } ) )
907 sColumnName += OUString::number(++j);
910 pColumn->setName(sColumnName);
911 pColumn->setRealName(sRealName);
912 pColumn->setTableName(::comphelper::getString(xProp->getPropertyValue(PROPERTY_TABLENAME)));
914 (*aSelectColumns)[i-1] = pColumn;
916 else
917 continue;
919 aUsedSelectColumns.insert( static_cast<size_t>(i - 1) );
920 aNames.push_back( sColumnName );
923 catch(const Exception&)
927 } while ( false );
929 bool bMissingSomeColumnLabels = !aNames.empty() && aNames.size() != aSelectColumns->size();
930 SAL_WARN_IF(bMissingSomeColumnLabels, "dbaccess", "We have column labels for *some* columns but not all");
931 //^^this happens in the evolution address book where we have real column names of e.g.
932 //first_name, second_name and city. On parsing via
933 //OSQLParseTreeIterator::appendColumns it creates some labels using those real names
934 //but the evo address book gives them proper labels of First Name, Second Name and City
935 //the munge means that here we have e.g. just "City" as a label because it matches
937 //This is all a horrible mess
938 if (bMissingSomeColumnLabels)
939 aNames.clear();
941 if ( aNames.empty() )
942 m_aCurrentColumns[ SelectColumns ] = OPrivateColumns::createWithIntrinsicNames( aSelectColumns, bCase, *this, m_aMutex );
943 else
944 m_aCurrentColumns[ SelectColumns ].reset( new OPrivateColumns( aSelectColumns, bCase, *this, m_aMutex, aNames ) );
946 return m_aCurrentColumns[SelectColumns].get();
949 bool OSingleSelectQueryComposer::setORCriteria(OSQLParseNode const * pCondition, OSQLParseTreeIterator& _rIterator,
950 std::vector< std::vector < PropertyValue > >& rFilters, const Reference< css::util::XNumberFormatter > & xFormatter) const
952 // Round brackets around the expression
953 if (pCondition->count() == 3 &&
954 SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
955 SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
957 return setORCriteria(pCondition->getChild(1), _rIterator, rFilters, xFormatter);
959 // OR logic expression
960 // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
961 else if (SQL_ISRULE(pCondition,search_condition))
963 bool bResult = true;
964 for (int i = 0; bResult && i < 3; i+=2)
966 // Is the first element a OR logic expression again?
967 // Then descend recursively ...
968 if (SQL_ISRULE(pCondition->getChild(i),search_condition))
969 bResult = setORCriteria(pCondition->getChild(i), _rIterator, rFilters, xFormatter);
970 else
972 rFilters.emplace_back();
973 bResult = setANDCriteria(pCondition->getChild(i), _rIterator, rFilters[rFilters.size() - 1], xFormatter);
976 return bResult;
978 else
980 rFilters.emplace_back();
981 return setANDCriteria(pCondition, _rIterator, rFilters[rFilters.size() - 1], xFormatter);
985 bool OSingleSelectQueryComposer::setANDCriteria( OSQLParseNode const * pCondition,
986 OSQLParseTreeIterator& _rIterator, std::vector < PropertyValue >& rFilter, const Reference< XNumberFormatter > & xFormatter) const
988 // Round brackets
989 if (SQL_ISRULE(pCondition,boolean_primary))
991 // this should not occur
992 SAL_WARN("dbaccess","boolean_primary in And-Criteria");
993 return false;
995 // The first element is an AND logical expression again
996 else if ( SQL_ISRULE(pCondition,boolean_term) && pCondition->count() == 3 )
998 return setANDCriteria(pCondition->getChild(0), _rIterator, rFilter, xFormatter) &&
999 setANDCriteria(pCondition->getChild(2), _rIterator, rFilter, xFormatter);
1001 else if (SQL_ISRULE(pCondition, comparison_predicate))
1003 return setComparisonPredicate(pCondition,_rIterator,rFilter,xFormatter);
1005 else if (SQL_ISRULE(pCondition,like_predicate))
1007 return setLikePredicate(pCondition,_rIterator,rFilter,xFormatter);
1009 else if (SQL_ISRULE(pCondition,test_for_null) ||
1010 SQL_ISRULE(pCondition,in_predicate) ||
1011 SQL_ISRULE(pCondition,all_or_any_predicate) ||
1012 SQL_ISRULE(pCondition,between_predicate))
1014 if (SQL_ISRULE(pCondition->getChild(0), column_ref))
1016 PropertyValue aItem;
1017 OUString aValue;
1018 OUString aColumnName;
1020 pCondition->parseNodeToStr( aValue, m_xConnection );
1021 pCondition->getChild(0)->parseNodeToStr( aColumnName, m_xConnection );
1023 // don't display the column name
1024 aValue = aValue.copy(aColumnName.getLength());
1025 aValue = aValue.trim();
1027 aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
1028 aItem.Value <<= aValue;
1029 aItem.Handle = 0; // just to know that this is not one the known ones
1030 if ( SQL_ISRULE(pCondition,like_predicate) )
1032 if ( SQL_ISTOKEN(pCondition->getChild(1)->getChild(0),NOT) )
1033 aItem.Handle = SQLFilterOperator::NOT_LIKE;
1034 else
1035 aItem.Handle = SQLFilterOperator::LIKE;
1037 else if (SQL_ISRULE(pCondition,test_for_null))
1039 if (SQL_ISTOKEN(pCondition->getChild(1)->getChild(1),NOT) )
1040 aItem.Handle = SQLFilterOperator::NOT_SQLNULL;
1041 else
1042 aItem.Handle = SQLFilterOperator::SQLNULL;
1044 else if (SQL_ISRULE(pCondition,in_predicate))
1046 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: in_predicate not implemented!" );
1048 else if (SQL_ISRULE(pCondition,all_or_any_predicate))
1050 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: all_or_any_predicate not implemented!" );
1052 else if (SQL_ISRULE(pCondition,between_predicate))
1054 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: between_predicate not implemented!" );
1057 rFilter.push_back(aItem);
1059 else
1060 return false;
1062 else if (SQL_ISRULE(pCondition,existence_test) ||
1063 SQL_ISRULE(pCondition,unique_test))
1065 // this couldn't be handled here, too complex
1066 // as we need a field name
1067 return false;
1069 else
1070 return false;
1072 return true;
1075 sal_Int32 OSingleSelectQueryComposer::getPredicateType(OSQLParseNode const * _pPredicate)
1077 sal_Int32 nPredicate = SQLFilterOperator::EQUAL;
1078 switch (_pPredicate->getNodeType())
1080 case SQLNodeType::Equal:
1081 nPredicate = SQLFilterOperator::EQUAL;
1082 break;
1083 case SQLNodeType::NotEqual:
1084 nPredicate = SQLFilterOperator::NOT_EQUAL;
1085 break;
1086 case SQLNodeType::Less:
1087 nPredicate = SQLFilterOperator::LESS;
1088 break;
1089 case SQLNodeType::LessEq:
1090 nPredicate = SQLFilterOperator::LESS_EQUAL;
1091 break;
1092 case SQLNodeType::Great:
1093 nPredicate = SQLFilterOperator::GREATER;
1094 break;
1095 case SQLNodeType::GreatEq:
1096 nPredicate = SQLFilterOperator::GREATER_EQUAL;
1097 break;
1098 default:
1099 SAL_WARN("dbaccess","Wrong NodeType!");
1101 return nPredicate;
1104 bool OSingleSelectQueryComposer::setLikePredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
1105 std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
1107 OSL_ENSURE(SQL_ISRULE(pCondition, like_predicate),"setLikePredicate: pCondition is not a LikePredicate");
1109 assert(pCondition->count() == 2);
1110 OSQLParseNode const *pRowValue = pCondition->getChild(0);
1111 OSQLParseNode const *pPart2 = pCondition->getChild(1);
1113 PropertyValue aItem;
1114 if ( SQL_ISTOKEN(pPart2->getChild(0),NOT) )
1115 aItem.Handle = SQLFilterOperator::NOT_LIKE;
1116 else
1117 aItem.Handle = SQLFilterOperator::LIKE;
1119 if (SQL_ISRULE(pRowValue, column_ref))
1121 OUString aValue;
1123 // skip (optional "NOT") and "LIKE"
1124 for (size_t i=2; i < pPart2->count(); i++)
1126 pPart2->getChild(i)->parseNodeToPredicateStr(
1127 aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1130 aItem.Name = getColumnName(pRowValue,_rIterator);
1131 aItem.Value <<= aValue;
1132 rFilter.push_back(aItem);
1134 else if (SQL_ISRULE(pRowValue, set_fct_spec ) ||
1135 SQL_ISRULE(pRowValue, general_set_fct))
1137 OUString aValue;
1138 OUString aColumnName;
1140 pPart2->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1141 pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1142 pRowValue->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1144 aItem.Name = getColumnName(pRowValue,_rIterator);
1145 aItem.Value <<= aValue;
1146 rFilter.push_back(aItem);
1148 else // Can only be an expression
1150 OUString aName, aValue;
1152 OSQLParseNode const *pValue = pPart2->getChild(2);
1154 // Field names
1155 for (size_t i=0;i< pRowValue->count();i++)
1156 pRowValue->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1158 // Criterion
1159 for(size_t i=0;i< pValue->count();i++)
1160 pValue->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1161 pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1163 aItem.Name = aName;
1164 aItem.Value <<= aValue;
1165 rFilter.push_back(aItem);
1167 return true;
1170 bool OSingleSelectQueryComposer::setComparisonPredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
1171 std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
1173 OSL_ENSURE(SQL_ISRULE(pCondition, comparison_predicate),"setComparisonPredicate: pCondition is not a ComparisonPredicate");
1174 if (SQL_ISRULE(pCondition->getChild(0), column_ref) ||
1175 SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
1177 PropertyValue aItem;
1178 OUString aValue;
1179 sal_uInt32 nPos;
1180 if (SQL_ISRULE(pCondition->getChild(0), column_ref))
1182 nPos = 0;
1183 size_t i=1;
1185 aItem.Handle = getPredicateType(pCondition->getChild(i));
1187 // go forward - don't display the operator
1188 for (i++;i < pCondition->count();i++)
1189 pCondition->getChild(i)->parseNodeToPredicateStr(
1190 aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1192 else if (SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
1194 nPos = pCondition->count()-1;
1196 sal_Int32 i = pCondition->count() - 2;
1197 switch (pCondition->getChild(i)->getNodeType())
1199 case SQLNodeType::Equal:
1200 aItem.Handle = SQLFilterOperator::EQUAL;
1201 break;
1202 case SQLNodeType::NotEqual:
1203 aItem.Handle = SQLFilterOperator::NOT_EQUAL;
1204 break;
1205 case SQLNodeType::Less:
1206 // take the opposite as we change the order
1207 aItem.Handle = SQLFilterOperator::GREATER_EQUAL;
1208 break;
1209 case SQLNodeType::LessEq:
1210 // take the opposite as we change the order
1211 aItem.Handle = SQLFilterOperator::GREATER;
1212 break;
1213 case SQLNodeType::Great:
1214 // take the opposite as we change the order
1215 aItem.Handle = SQLFilterOperator::LESS_EQUAL;
1216 break;
1217 case SQLNodeType::GreatEq:
1218 // take the opposite as we change the order
1219 aItem.Handle = SQLFilterOperator::LESS;
1220 break;
1221 default:
1222 break;
1225 // go backward - don't display the operator
1226 for (i--; i >= 0; i--)
1227 pCondition->getChild(i)->parseNodeToPredicateStr(
1228 aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1230 else
1231 return false;
1233 aItem.Name = getColumnName(pCondition->getChild(nPos),_rIterator);
1234 aItem.Value <<= aValue;
1235 rFilter.push_back(aItem);
1237 else if (SQL_ISRULE(pCondition->getChild(0), set_fct_spec ) ||
1238 SQL_ISRULE(pCondition->getChild(0), general_set_fct))
1240 PropertyValue aItem;
1241 OUString aValue;
1242 OUString aColumnName;
1244 pCondition->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1245 pCondition->getChild(0)->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1247 aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
1248 aItem.Value <<= aValue;
1249 aItem.Handle = getPredicateType(pCondition->getChild(1));
1250 rFilter.push_back(aItem);
1252 else // Can only be an expression
1254 PropertyValue aItem;
1255 OUString aName, aValue;
1257 OSQLParseNode *pLhs = pCondition->getChild(0);
1258 OSQLParseNode *pRhs = pCondition->getChild(2);
1260 // Field names
1261 for (size_t i=0;i< pLhs->count();i++)
1262 pLhs->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1264 // Criterion
1265 aItem.Handle = getPredicateType(pCondition->getChild(1));
1266 for(size_t i=0;i< pRhs->count();i++)
1267 pRhs->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1269 aItem.Name = aName;
1270 aItem.Value <<= aValue;
1271 rFilter.push_back(aItem);
1273 return true;
1276 // Functions for analysing SQL
1277 OUString OSingleSelectQueryComposer::getColumnName( ::connectivity::OSQLParseNode const * pColumnRef, OSQLParseTreeIterator const & _rIterator )
1279 OUString aTableRange, aColumnName;
1280 _rIterator.getColumnRange(pColumnRef,aColumnName,aTableRange);
1281 return aColumnName;
1284 OUString SAL_CALL OSingleSelectQueryComposer::getFilter( )
1286 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1287 ::osl::MutexGuard aGuard( m_aMutex );
1288 return getSQLPart(Where,m_aAdditiveIterator,false);
1291 OUString SAL_CALL OSingleSelectQueryComposer::getOrder( )
1293 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1294 ::osl::MutexGuard aGuard( m_aMutex );
1295 return getSQLPart(Order,m_aAdditiveIterator,false);
1298 OUString SAL_CALL OSingleSelectQueryComposer::getGroup( )
1300 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1301 ::osl::MutexGuard aGuard( m_aMutex );
1302 return getSQLPart(Group,m_aAdditiveIterator,false);
1305 OUString OSingleSelectQueryComposer::getHavingClause()
1307 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1308 ::osl::MutexGuard aGuard( m_aMutex );
1309 return getSQLPart(Having,m_aAdditiveIterator,false);
1312 OUString OSingleSelectQueryComposer::getTableAlias(const Reference< XPropertySet >& column) const
1314 OUString sReturn;
1315 if(m_pTables && m_pTables->getCount() > 1)
1317 OUString aCatalog,aSchema,aTable,aColumnName;
1318 if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_CATALOGNAME))
1319 column->getPropertyValue(PROPERTY_CATALOGNAME) >>= aCatalog;
1320 if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_SCHEMANAME))
1321 column->getPropertyValue(PROPERTY_SCHEMANAME) >>= aSchema;
1322 if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME))
1323 column->getPropertyValue(PROPERTY_TABLENAME) >>= aTable;
1324 column->getPropertyValue(PROPERTY_NAME) >>= aColumnName;
1326 Sequence< OUString> aNames(m_pTables->getElementNames());
1327 const OUString* pBegin = aNames.getConstArray();
1328 const OUString* const pEnd = pBegin + aNames.getLength();
1330 if(aTable.isEmpty())
1331 { // we haven't found a table name, now we must search every table for this column
1332 for(;pBegin != pEnd;++pBegin)
1334 Reference<XColumnsSupplier> xColumnsSupp;
1335 m_pTables->getByName(*pBegin) >>= xColumnsSupp;
1337 if(xColumnsSupp.is() && xColumnsSupp->getColumns()->hasByName(aColumnName))
1339 aTable = *pBegin;
1340 break;
1344 else
1346 OUString aComposedName = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, false, ::dbtools::EComposeRule::InDataManipulation );
1348 // Is this the right case for the table name?
1349 // Else, look for it with different case, if applicable.
1351 if(!m_pTables->hasByName(aComposedName))
1353 ::comphelper::UStringMixLess aTmp(m_aAdditiveIterator.getTables().key_comp());
1354 ::comphelper::UStringMixEqual aComp(aTmp.isCaseSensitive());
1355 for(;pBegin != pEnd;++pBegin)
1357 Reference<XPropertySet> xTableProp;
1358 m_pTables->getByName(*pBegin) >>= xTableProp;
1359 OSL_ENSURE(xTableProp.is(),"Table isn't a propertyset!");
1360 if(xTableProp.is())
1362 OUString aCatalog2,aSchema2,aTable2;
1363 xTableProp->getPropertyValue(PROPERTY_CATALOGNAME) >>= aCatalog2;
1364 xTableProp->getPropertyValue(PROPERTY_SCHEMANAME) >>= aSchema2;
1365 xTableProp->getPropertyValue(PROPERTY_NAME) >>= aTable2;
1366 if(aComp(aCatalog,aCatalog2) && aComp(aSchema,aSchema2) && aComp(aTable,aTable2))
1368 aCatalog = aCatalog2;
1369 aSchema = aSchema2;
1370 aTable = aTable2;
1371 break;
1377 if(pBegin != pEnd)
1379 sReturn = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ) + ".";
1382 return sReturn;
1385 Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getParameters( )
1387 // now set the Parameters
1388 if ( !m_aCurrentColumns[ParameterColumns] )
1390 ::rtl::Reference< OSQLColumns> aCols = m_aSqlIterator.getParameters();
1391 std::vector< OUString> aNames;
1392 for (auto const& elem : *aCols)
1393 aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
1394 m_aCurrentColumns[ParameterColumns].reset( new OPrivateColumns(aCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
1397 return m_aCurrentColumns[ParameterColumns].get();
1400 void OSingleSelectQueryComposer::clearColumns( const EColumnType _eType )
1402 OPrivateColumns* pColumns = m_aCurrentColumns[ _eType ].get();
1403 if ( pColumns != nullptr )
1405 pColumns->disposing();
1406 m_aColumnsCollection.push_back( std::move(m_aCurrentColumns[ _eType ]) );
1410 void OSingleSelectQueryComposer::clearCurrentCollections()
1412 for (auto & currentColumn : m_aCurrentColumns)
1414 if (currentColumn)
1416 currentColumn->disposing();
1417 m_aColumnsCollection.push_back(std::move(currentColumn));
1421 if(m_pTables)
1423 m_pTables->disposing();
1424 m_aTablesCollection.push_back(std::move(m_pTables));
1428 Reference< XIndexAccess > OSingleSelectQueryComposer::setCurrentColumns( EColumnType _eType,
1429 const ::rtl::Reference< OSQLColumns >& _rCols )
1431 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1433 ::osl::MutexGuard aGuard( m_aMutex );
1434 // now set the group columns
1435 if ( !m_aCurrentColumns[_eType] )
1437 std::vector< OUString> aNames;
1438 for (auto const& elem : *_rCols)
1439 aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
1440 m_aCurrentColumns[_eType].reset( new OPrivateColumns(_rCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
1443 return m_aCurrentColumns[_eType].get();
1446 Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getGroupColumns( )
1448 return setCurrentColumns( GroupByColumns, m_aAdditiveIterator.getGroupColumns() );
1451 Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getOrderColumns( )
1453 return setCurrentColumns( OrderColumns, m_aAdditiveIterator.getOrderColumns() );
1456 OUString SAL_CALL OSingleSelectQueryComposer::getQueryWithSubstitution( )
1458 ::osl::MutexGuard aGuard( m_aMutex );
1459 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1461 OUString sSqlStatement( getQuery() );
1463 const OSQLParseNode* pStatementNode = m_aSqlIterator.getParseTree();
1464 if ( pStatementNode )
1466 SQLException aError;
1467 if ( !pStatementNode->parseNodeToExecutableStatement( sSqlStatement, m_xConnection, m_aSqlParser, &aError ) )
1468 throw aError;
1471 return sSqlStatement;
1474 OUString OSingleSelectQueryComposer::getStatementPart( TGetParseNode const & _aGetFunctor, OSQLParseTreeIterator& _rIterator )
1476 OUString sResult;
1478 const OSQLParseNode* pNode = _aGetFunctor( &_rIterator );
1479 if ( pNode )
1480 pNode->parseNodeToStr( sResult, m_xConnection );
1482 return sResult;
1485 namespace
1487 OUString lcl_getDecomposedColumnName(const OUString& rComposedName, const OUString& rQuoteString)
1489 const sal_Int32 nQuoteLength = rQuoteString.getLength();
1490 OUString sName = rComposedName.trim();
1491 OUString sColumnName;
1492 sal_Int32 nPos, nRPos = 0;
1494 for (;;)
1496 nPos = sName.indexOf( rQuoteString, nRPos );
1497 if ( nPos >= 0 )
1499 nRPos = sName.indexOf( rQuoteString, nPos + nQuoteLength );
1500 if ( nRPos > nPos )
1502 if ( nRPos + nQuoteLength < sName.getLength() )
1504 nRPos += nQuoteLength; // -1 + 1 skip dot
1506 else
1508 sColumnName = sName.copy( nPos + nQuoteLength, nRPos - nPos - nQuoteLength );
1509 break;
1512 else
1513 break;
1515 else
1516 break;
1518 return sColumnName.isEmpty() ? rComposedName : sColumnName;
1521 OUString lcl_getCondition(const Sequence< Sequence< PropertyValue > >& filter,
1522 const OPredicateInputController& i_aPredicateInputController,
1523 const Reference< XNameAccess >& i_xSelectColumns,
1524 const OUString& rQuoteString)
1526 OUStringBuffer sRet;
1527 const Sequence< PropertyValue >* pOrIter = filter.getConstArray();
1528 const Sequence< PropertyValue >* pOrEnd = pOrIter + filter.getLength();
1529 while ( pOrIter != pOrEnd )
1531 if ( pOrIter->hasElements() )
1533 sRet.append(L_BRACKET);
1534 const PropertyValue* pAndIter = pOrIter->getConstArray();
1535 const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength();
1536 while ( pAndIter != pAndEnd )
1538 sRet.append(pAndIter->Name);
1539 OUString sValue;
1540 pAndIter->Value >>= sValue;
1541 const OUString sColumnName = lcl_getDecomposedColumnName( pAndIter->Name, rQuoteString );
1542 if ( i_xSelectColumns.is() && i_xSelectColumns->hasByName(sColumnName) )
1544 Reference<XPropertySet> xColumn(i_xSelectColumns->getByName(sColumnName),UNO_QUERY);
1545 sValue = i_aPredicateInputController.getPredicateValueStr(sValue,xColumn);
1547 else
1549 sValue = i_aPredicateInputController.getPredicateValueStr(pAndIter->Name,sValue);
1551 lcl_addFilterCriteria_throw(pAndIter->Handle,sValue,sRet);
1552 ++pAndIter;
1553 if ( pAndIter != pAndEnd )
1554 sRet.append(STR_AND);
1556 sRet.append(R_BRACKET);
1558 ++pOrIter;
1559 if ( pOrIter != pOrEnd && !sRet.isEmpty() )
1560 sRet.append(STR_OR);
1562 return sRet.makeStringAndClear();
1566 void SAL_CALL OSingleSelectQueryComposer::setStructuredFilter( const Sequence< Sequence< PropertyValue > >& filter )
1568 OPredicateInputController aPredicateInput(m_aContext, m_xConnection, &m_aParseContext);
1569 setFilter(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
1572 void SAL_CALL OSingleSelectQueryComposer::setStructuredHavingClause( const Sequence< Sequence< PropertyValue > >& filter )
1574 OPredicateInputController aPredicateInput(m_aContext, m_xConnection);
1575 setHavingClause(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
1578 void OSingleSelectQueryComposer::setConditionByColumn( const Reference< XPropertySet >& column, bool andCriteria, std::function<bool(OSingleSelectQueryComposer *, const OUString&)> const & _aSetFunctor, sal_Int32 filterOperator)
1582 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1584 if ( !column.is()
1585 || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_VALUE)
1586 || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
1587 || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE))
1588 throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any() );
1590 sal_Int32 nType = 0;
1591 column->getPropertyValue(PROPERTY_TYPE) >>= nType;
1592 sal_Int32 nSearchable = dbtools::getSearchColumnFlag(m_xConnection,nType);
1593 if(nSearchable == ColumnSearch::NONE)
1594 throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_SEARCHABLE),*this,SQLSTATE_GENERAL,1000,Any() );
1596 ::osl::MutexGuard aGuard( m_aMutex );
1598 OUString aName;
1599 column->getPropertyValue(PROPERTY_NAME) >>= aName;
1601 const Any aValue = column->getPropertyValue(PROPERTY_VALUE);
1603 OUStringBuffer aSQL;
1604 const OUString aQuote = m_xMetaData->getIdentifierQuoteString();
1605 getColumns();
1607 // TODO: if this is called for HAVING, check that the column is a GROUP BY column
1608 // or that it is an aggregate function
1610 if ( m_aCurrentColumns[SelectColumns] && m_aCurrentColumns[SelectColumns]->hasByName(aName) )
1612 Reference<XPropertySet> xColumn;
1613 m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
1614 OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
1615 OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
1616 OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName("AggregateFunction"),"Property AggregateFunction not available!");
1618 OUString sRealName,sTableName;
1619 xColumn->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
1620 xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
1621 if(sTableName.indexOf('.') != -1)
1623 OUString aCatlog,aSchema,aTable;
1624 ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
1625 sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
1627 else
1628 sTableName = ::dbtools::quoteName(aQuote,sTableName);
1630 if ( !::comphelper::getBOOL(xColumn->getPropertyValue("Function")) )
1632 aSQL = sTableName + "." + ::dbtools::quoteName( aQuote, sRealName );
1634 else
1635 aSQL = sRealName;
1637 else
1639 aSQL = getTableAlias( column ) + ::dbtools::quoteName( aQuote, aName );
1642 if ( aValue.hasValue() )
1644 if( !m_xTypeConverter.is() )
1645 m_xTypeConverter.set( Converter::create(m_aContext) );
1646 OSL_ENSURE(m_xTypeConverter.is(),"NO typeconverter!");
1648 if ( nType != DataType::BOOLEAN && DataType::BIT != nType )
1650 lcl_addFilterCriteria_throw(filterOperator,"",aSQL);
1653 switch(nType)
1655 case DataType::VARCHAR:
1656 case DataType::CHAR:
1657 case DataType::LONGVARCHAR:
1658 aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
1659 break;
1660 case DataType::CLOB:
1662 Reference< XClob > xClob(aValue,UNO_QUERY);
1663 if ( xClob.is() )
1665 const ::sal_Int64 nLength = xClob->length();
1666 if ( sal_Int64(nLength + aSQL.getLength() + STR_LIKE.getLength() ) < sal_Int64(SAL_MAX_INT32) )
1668 aSQL.append("'").append(xClob->getSubString(1,static_cast<sal_Int32>(nLength))).append("'");
1671 else
1673 aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
1676 break;
1677 case DataType::VARBINARY:
1678 case DataType::BINARY:
1679 case DataType::LONGVARBINARY:
1681 Sequence<sal_Int8> aSeq;
1682 if(!(aValue >>= aSeq))
1683 throw SQLException(DBA_RES(RID_STR_NOT_SEQUENCE_INT8),*this,SQLSTATE_GENERAL,1000,Any() );
1684 if(nSearchable == ColumnSearch::CHAR)
1686 aSQL.append( "\'" );
1688 aSQL.append( "0x" );
1689 const sal_Int8* pBegin = aSeq.getConstArray();
1690 const sal_Int8* pEnd = pBegin + aSeq.getLength();
1691 for(;pBegin != pEnd;++pBegin)
1693 aSQL.append( static_cast<sal_Int32>(*pBegin), 16 );
1695 if(nSearchable == ColumnSearch::CHAR)
1696 aSQL.append( "\'" );
1698 break;
1699 case DataType::BIT:
1700 case DataType::BOOLEAN:
1702 bool bValue = false;
1703 m_xTypeConverter->convertToSimpleType(aValue, TypeClass_BOOLEAN) >>= bValue;
1705 OUString sColumnExp = aSQL.makeStringAndClear();
1706 getBooleanComparisonPredicate( sColumnExp, bValue, m_nBoolCompareMode, aSQL );
1708 break;
1709 default:
1710 aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
1711 break;
1714 else
1716 sal_Int32 nFilterOp = filterOperator;
1717 if ( filterOperator != SQLFilterOperator::SQLNULL && filterOperator != SQLFilterOperator::NOT_SQLNULL )
1718 nFilterOp = SQLFilterOperator::SQLNULL;
1719 lcl_addFilterCriteria_throw(nFilterOp,"",aSQL);
1722 // Attach filter
1723 // Construct SELECT without WHERE and ORDER BY
1724 OUString sFilter = getFilter();
1726 if ( !sFilter.isEmpty() && !aSQL.isEmpty() )
1728 sFilter = L_BRACKET + sFilter + R_BRACKET +
1729 (andCriteria ? std::u16string_view(u"" STR_AND) : std::u16string_view(u"" STR_OR));
1731 sFilter += aSQL;
1733 // add the filter and the sort order
1734 _aSetFunctor(this,sFilter);
1736 catch (css::lang::WrappedTargetException & e)
1738 if (e.TargetException.isExtractableTo(
1739 cppu::UnoType<css::sdbc::SQLException>::get()))
1741 cppu::throwException(e.TargetException);
1743 else
1745 throw;
1750 Sequence< Sequence< PropertyValue > > OSingleSelectQueryComposer::getStructuredCondition( TGetParseNode const & _aGetFunctor )
1752 ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1754 MutexGuard aGuard(m_aMutex);
1756 Sequence< Sequence< PropertyValue > > aFilterSeq;
1757 OUString sFilter = getStatementPart( _aGetFunctor, m_aAdditiveIterator );
1760 if ( !sFilter.isEmpty() )
1762 OUString aSql(m_aPureSelectSQL + STR_WHERE + sFilter);
1763 // build a temporary parse node
1764 const OSQLParseNode* pTempNode = m_aAdditiveIterator.getParseTree();
1766 OUString aErrorMsg;
1767 std::unique_ptr<OSQLParseNode> pSqlParseNode( m_aSqlParser.parseTree(aErrorMsg,aSql));
1768 if (pSqlParseNode)
1770 m_aAdditiveIterator.setParseTree(pSqlParseNode.get());
1771 // normalize the filter
1772 OSQLParseNode* pWhereNode = const_cast<OSQLParseNode*>(m_aAdditiveIterator.getWhereTree());
1774 OSQLParseNode* pCondition = pWhereNode->getChild(1);
1775 #if OSL_DEBUG_LEVEL > 0
1776 OUString sCondition;
1777 pCondition->parseNodeToStr( sCondition, m_xConnection );
1778 #endif
1779 OSQLParseNode::negateSearchCondition(pCondition);
1781 pCondition = pWhereNode->getChild(1);
1782 #if OSL_DEBUG_LEVEL > 0
1783 sCondition.clear();
1784 pCondition->parseNodeToStr( sCondition, m_xConnection );
1785 #endif
1786 OSQLParseNode::disjunctiveNormalForm(pCondition);
1788 pCondition = pWhereNode->getChild(1);
1789 #if OSL_DEBUG_LEVEL > 0
1790 sCondition.clear();
1791 pCondition->parseNodeToStr( sCondition, m_xConnection );
1792 #endif
1793 OSQLParseNode::absorptions(pCondition);
1795 pCondition = pWhereNode->getChild(1);
1796 #if OSL_DEBUG_LEVEL > 0
1797 sCondition.clear();
1798 pCondition->parseNodeToStr( sCondition, m_xConnection );
1799 #endif
1800 if ( pCondition )
1802 std::vector< std::vector < PropertyValue > > aFilters;
1803 Reference< XNumberFormatter > xFormatter( NumberFormatter::create(m_aContext), UNO_QUERY_THROW );
1804 xFormatter->attachNumberFormatsSupplier( m_xNumberFormatsSupplier );
1806 if (setORCriteria(pCondition, m_aAdditiveIterator, aFilters, xFormatter))
1808 aFilterSeq.realloc(aFilters.size());
1809 Sequence<PropertyValue>* pFilters = aFilterSeq.getArray();
1810 for (auto const& filter : aFilters)
1812 pFilters->realloc(filter.size());
1813 PropertyValue* pFilter = pFilters->getArray();
1814 for (auto const& elem : filter)
1816 *pFilter = elem;
1817 ++pFilter;
1819 ++pFilters;
1823 // restore
1824 m_aAdditiveIterator.setParseTree(pTempNode);
1827 return aFilterSeq;
1830 OUString OSingleSelectQueryComposer::getKeyword( SQLPart _ePart )
1832 OUString sKeyword;
1833 switch(_ePart)
1835 default:
1836 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getKeyWord: Invalid enum value!" );
1837 [[fallthrough]]; // fallback to WHERE
1838 case Where:
1839 sKeyword = STR_WHERE;
1840 break;
1841 case Group:
1842 sKeyword = STR_GROUP_BY;
1843 break;
1844 case Having:
1845 sKeyword = STR_HAVING;
1846 break;
1847 case Order:
1848 sKeyword = STR_ORDER_BY;
1849 break;
1851 return sKeyword;
1854 OUString OSingleSelectQueryComposer::getSQLPart( SQLPart _ePart, OSQLParseTreeIterator& _rIterator, bool _bWithKeyword )
1856 TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
1857 OUString sKeyword( getKeyword( _ePart ) );
1858 switch(_ePart)
1860 case Where:
1861 F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleWhereTree);
1862 break;
1863 case Group:
1864 F_tmp = TGetParseNode (&OSQLParseTreeIterator::getSimpleGroupByTree);
1865 break;
1866 case Having:
1867 F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleHavingTree);
1868 break;
1869 case Order:
1870 F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleOrderTree);
1871 break;
1872 default:
1873 SAL_WARN("dbaccess","Invalid enum value!");
1876 OUString sRet = getStatementPart( F_tmp, _rIterator );
1877 if ( _bWithKeyword && !sRet.isEmpty() )
1878 sRet = sKeyword + sRet;
1879 return sRet;
1882 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */