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 <string.h>
21 #include <sal/log.hxx>
22 #include <composertools.hxx>
23 #include <strings.hrc>
24 #include <strings.hxx>
25 #include <core_resource.hxx>
26 #include <stringconstants.hxx>
27 #include "HelperCollections.hxx"
28 #include <SingleSelectQueryComposer.hxx>
29 #include <sqlbison.hxx>
30 #include <sdbcoretools.hxx>
31 
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <com/sun/star/i18n/LocaleData.hpp>
34 #include <com/sun/star/script/Converter.hpp>
35 #include <com/sun/star/sdb/BooleanComparisonMode.hpp>
36 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
37 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
38 #include <com/sun/star/sdb/CommandType.hpp>
39 #include <com/sun/star/sdbc/ColumnSearch.hpp>
40 #include <com/sun/star/sdbc/DataType.hpp>
41 #include <com/sun/star/sdbc/XConnection.hpp>
42 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
43 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
44 #include <com/sun/star/sdbc/XParameters.hpp>
45 #include <com/sun/star/util/NumberFormatter.hpp>
46 
47 #include <comphelper/types.hxx>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include <connectivity/dbtools.hxx>
50 #include <connectivity/PColumn.hxx>
51 #include <connectivity/predicateinput.hxx>
52 #include <comphelper/diagnose_ex.hxx>
53 #include <osl/diagnose.h>
54 #include <unotools/sharedunocomponent.hxx>
55 
56 #include <memory>
57 #include <string_view>
58 
59 using namespace ::dbaccess;
60 using namespace ::dbtools;
61 using namespace ::comphelper;
62 using namespace ::connectivity;
63 using namespace ::com::sun::star::uno;
64 using namespace ::com::sun::star::beans;
65 using namespace ::com::sun::star::sdbc;
66 using namespace ::com::sun::star::sdb;
67 using namespace ::com::sun::star::sdbcx;
68 using namespace ::com::sun::star::container;
69 using namespace ::com::sun::star::i18n;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::script;
72 using namespace ::com::sun::star::util;
73 using namespace ::cppu;
74 using namespace ::osl;
75 using namespace ::utl;
76 
77 namespace dbaccess {
78 namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;
79 }
80 
81 constexpr OUStringLiteral STR_SELECT = u"SELECT ";
82 constexpr OUStringLiteral STR_FROM = u" FROM ";
83 constexpr OUString STR_WHERE = u" WHERE "_ustr;
84 constexpr OUStringLiteral STR_GROUP_BY = u" GROUP BY ";
85 constexpr OUStringLiteral STR_HAVING = u" HAVING ";
86 constexpr OUStringLiteral STR_ORDER_BY = u" ORDER BY ";
87 constexpr OUString STR_AND = u" AND "_ustr;
88 constexpr OUString STR_OR = u" OR "_ustr;
89 constexpr OUStringLiteral STR_LIKE = u" LIKE ";
90 constexpr OUString L_BRACKET = u"("_ustr;
91 constexpr OUString R_BRACKET = u")"_ustr;
92 constexpr OUStringLiteral COMMA = u",";
93 
94 namespace
95 {
96     /** parses the given statement, using the given parser, returns a parse node representing
97         the statement
98 
99         If the statement cannot be parsed, an error is thrown.
100     */
parseStatement_throwError(OSQLParser & _rParser,const OUString & _rStatement,const Reference<XInterface> & _rxContext)101     std::unique_ptr<OSQLParseNode> parseStatement_throwError( OSQLParser& _rParser, const OUString& _rStatement, const Reference< XInterface >& _rxContext )
102     {
103         OUString aErrorMsg;
104         std::unique_ptr<OSQLParseNode> pNewSqlParseNode = _rParser.parseTree( aErrorMsg, _rStatement );
105         if ( !pNewSqlParseNode )
106         {
107             OUString sSQLStateGeneralError( getStandardSQLState( StandardSQLState::GENERAL_ERROR ) );
108             SQLException aError2( aErrorMsg, _rxContext, sSQLStateGeneralError, 1000, Any() );
109             SQLException aError1( _rStatement, _rxContext, sSQLStateGeneralError, 1000, Any( aError2 ) );
110             throw SQLException(_rParser.getContext().getErrorMessage(OParseContext::ErrorCode::General),_rxContext,sSQLStateGeneralError,1000,Any(aError1));
111         }
112         return pNewSqlParseNode;
113     }
114 
115     /** checks whether the given parse node describes a valid single select statement, throws
116         an error if not
117     */
checkForSingleSelect_throwError(const OSQLParseNode * pStatementNode,OSQLParseTreeIterator & _rIterator,const Reference<XInterface> & _rxContext,const OUString & _rOriginatingCommand)118     void checkForSingleSelect_throwError( const OSQLParseNode* pStatementNode, OSQLParseTreeIterator& _rIterator,
119         const Reference< XInterface >& _rxContext, const OUString& _rOriginatingCommand )
120     {
121         const OSQLParseNode* pOldNode = _rIterator.getParseTree();
122 
123         // determine the statement type
124         _rIterator.setParseTree( pStatementNode );
125         _rIterator.traverseAll();
126         bool bIsSingleSelect = ( _rIterator.getStatementType() == OSQLStatementType::Select );
127 
128         // throw the error, if necessary
129         if ( !bIsSingleSelect || SQL_ISRULE( pStatementNode, union_statement ) ) // #i4229# OJ
130         {
131             // restore the old node before throwing the exception
132             _rIterator.setParseTree( pOldNode );
133             // and now really ...
134             SQLException aError1( _rOriginatingCommand, _rxContext, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() );
135             throw SQLException( DBA_RES( RID_STR_ONLY_QUERY ), _rxContext,
136                 getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any( aError1 ) );
137         }
138 
139         delete pOldNode;
140     }
141 
142     /** combines parseStatement_throwError and checkForSingleSelect_throwError
143     */
parseAndCheck_throwError(OSQLParser & _rParser,const OUString & _rStatement,OSQLParseTreeIterator & _rIterator,const Reference<XInterface> & _rxContext)144     void parseAndCheck_throwError( OSQLParser& _rParser, const OUString& _rStatement,
145         OSQLParseTreeIterator& _rIterator, const Reference< XInterface >& _rxContext )
146     {
147         std::unique_ptr<OSQLParseNode> pNode = parseStatement_throwError( _rParser, _rStatement, _rxContext );
148         checkForSingleSelect_throwError( pNode.release(), _rIterator, _rxContext, _rStatement );
149     }
150 
151     /** transforms a parse node describing a complete statement into a pure select
152         statement, without any filter/order/groupby/having clauses
153     */
getPureSelectStatement(const OSQLParseNode * _pRootNode,const Reference<XConnection> & _rxConnection)154     OUString getPureSelectStatement( const OSQLParseNode* _pRootNode, const Reference< XConnection >& _rxConnection )
155     {
156         OUString sSQL = STR_SELECT;
157         _pRootNode->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
158         _pRootNode->getChild(2)->parseNodeToStr( sSQL, _rxConnection );
159         sSQL += STR_FROM;
160         _pRootNode->getChild(3)->getChild(0)->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
161         return sSQL;
162     }
163 
164     /** resets an SQL iterator, including deletion of the parse tree, and dispose
165     */
resetIterator(OSQLParseTreeIterator & _rIterator)166     void resetIterator( OSQLParseTreeIterator& _rIterator )
167     {
168         const OSQLParseNode* pSqlParseNode = _rIterator.getParseTree();
169         _rIterator.setParseTree(nullptr);
170         delete pSqlParseNode;
171         _rIterator.dispose();
172     }
lcl_addFilterCriteria_throw(sal_Int32 i_nFilterOperator,std::u16string_view i_sValue,OUStringBuffer & o_sRet)173     void lcl_addFilterCriteria_throw(sal_Int32 i_nFilterOperator,std::u16string_view i_sValue,OUStringBuffer& o_sRet)
174     {
175         switch( i_nFilterOperator )
176         {
177             case SQLFilterOperator::EQUAL:
178                 o_sRet.append(OUString::Concat(" = ") + i_sValue);
179                 break;
180             case SQLFilterOperator::NOT_EQUAL:
181                 o_sRet.append(OUString::Concat(" <> ") + i_sValue);
182                 break;
183             case SQLFilterOperator::LESS:
184                 o_sRet.append(OUString::Concat(" < ") + i_sValue);
185                 break;
186             case SQLFilterOperator::GREATER:
187                 o_sRet.append(OUString::Concat(" > ") + i_sValue);
188                 break;
189             case SQLFilterOperator::LESS_EQUAL:
190                 o_sRet.append(OUString::Concat(" <= ") + i_sValue);
191                 break;
192             case SQLFilterOperator::GREATER_EQUAL:
193                 o_sRet.append(OUString::Concat(" >= ") + i_sValue);
194                 break;
195             case SQLFilterOperator::LIKE:
196                 o_sRet.append(OUString::Concat(" LIKE ") + i_sValue);
197                 break;
198             case SQLFilterOperator::NOT_LIKE:
199                 o_sRet.append(OUString::Concat(" NOT LIKE ") + i_sValue);
200                 break;
201             case SQLFilterOperator::SQLNULL:
202                 o_sRet.append(" IS NULL");
203                 break;
204             case SQLFilterOperator::NOT_SQLNULL:
205                 o_sRet.append(" IS NOT NULL");
206                 break;
207             default:
208                 throw SQLException();
209         }
210     }
211 
212 }
213 
214 
OSingleSelectQueryComposer(const Reference<XNameAccess> & _rxTables,const Reference<XConnection> & _xConnection,const Reference<XComponentContext> & _rContext)215 OSingleSelectQueryComposer::OSingleSelectQueryComposer(const Reference< XNameAccess>& _rxTables,
216                                const Reference< XConnection>& _xConnection,
217                                const Reference<XComponentContext>& _rContext )
218     :OSubComponent(m_aMutex,_xConnection)
219     ,OPropertyContainer(m_aBHelper)
220     ,m_aSqlParser( _rContext, &m_aParseContext, &m_aNeutralContext )
221     ,m_aSqlIterator( _xConnection, _rxTables, m_aSqlParser )
222     ,m_aAdditiveIterator( _xConnection, _rxTables, m_aSqlParser )
223     ,m_aElementaryParts( size_t(SQLPartCount) )
224     ,m_xConnection(_xConnection)
225     ,m_xMetaData(_xConnection->getMetaData())
226     ,m_xConnectionTables( _rxTables )
227     ,m_aContext( _rContext )
228     ,m_nBoolCompareMode( BooleanComparisonMode::EQUAL_INTEGER )
229     ,m_nCommandType(CommandType::COMMAND)
230 {
231     if ( !m_aContext.is() || !m_xConnection.is() || !m_xConnectionTables.is() )
232         throw IllegalArgumentException();
233 
234     registerProperty(PROPERTY_ORIGINAL,PROPERTY_ID_ORIGINAL,PropertyAttribute::BOUND|PropertyAttribute::READONLY,&m_sOriginal,cppu::UnoType<decltype(m_sOriginal)>::get());
235 
236     m_aCurrentColumns.resize(4);
237 
238     m_aLocale = m_aParseContext.getPreferredLocale();
239     m_xNumberFormatsSupplier = dbtools::getNumberFormats( m_xConnection, true, m_aContext );
240     Reference< XLocaleData4 > xLocaleData( LocaleData::create(m_aContext) );
241     LocaleDataItem aData = xLocaleData->getLocaleItem(m_aLocale);
242     m_sDecimalSep = aData.decimalSeparator;
243     OSL_ENSURE(m_sDecimalSep.getLength() == 1,"OSingleSelectQueryComposer::OSingleSelectQueryComposer decimal separator is not 1 length");
244     try
245     {
246         Any aValue;
247         Reference<XInterface> xDs = dbaccess::getDataSource(_xConnection);
248         if ( dbtools::getDataSourceSetting(xDs,PROPERTY_BOOLEANCOMPARISONMODE,aValue) )
249         {
250             OSL_VERIFY( aValue >>= m_nBoolCompareMode );
251         }
252         Reference< XQueriesSupplier >  xQueriesAccess(m_xConnection, UNO_QUERY);
253         if (xQueriesAccess.is())
254             m_xConnectionQueries = xQueriesAccess->getQueries();
255     }
256     catch(Exception&)
257     {
258     }
259 }
260 
~OSingleSelectQueryComposer()261 OSingleSelectQueryComposer::~OSingleSelectQueryComposer()
262 {
263 }
264 
265 // OComponentHelper
disposing()266 void SAL_CALL OSingleSelectQueryComposer::disposing()
267 {
268     OSubComponent::disposing();
269 
270     MutexGuard aGuard(m_aMutex);
271 
272     resetIterator( m_aSqlIterator );
273     resetIterator( m_aAdditiveIterator );
274 
275     m_xConnectionTables = nullptr;
276     m_xConnection       = nullptr;
277 
278     clearCurrentCollections();
279 }
280 
IMPLEMENT_FORWARD_XINTERFACE3(OSingleSelectQueryComposer,OSubComponent,OSingleSelectQueryComposer_BASE,OPropertyContainer)281 IMPLEMENT_FORWARD_XINTERFACE3(OSingleSelectQueryComposer,OSubComponent,OSingleSelectQueryComposer_BASE,OPropertyContainer)
282 OUString SAL_CALL OSingleSelectQueryComposer::getImplementationName()
283     {
284         return u"org.openoffice.comp.dba.OSingleSelectQueryComposer"_ustr;
285     }
supportsService(const OUString & _rServiceName)286 sal_Bool SAL_CALL OSingleSelectQueryComposer::supportsService(const OUString& _rServiceName)
287     {
288         const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
289         for (const OUString& s : aSupported)
290             if (s == _rServiceName)
291                 return true;
292 
293         return false;
294     }
getSupportedServiceNames()295 css::uno::Sequence< OUString > SAL_CALL OSingleSelectQueryComposer::getSupportedServiceNames()
296 {
297     return { SERVICE_NAME_SINGLESELECTQUERYCOMPOSER };
298 }
299 
getImplementationId()300 css::uno::Sequence<sal_Int8> OSingleSelectQueryComposer::getImplementationId()
301 {
302     return css::uno::Sequence<sal_Int8>();
303 }
304 
getTypes()305 css::uno::Sequence< css::uno::Type > OSingleSelectQueryComposer::getTypes()
306 {
307     return  ::comphelper::concatSequences(
308         OSubComponent::getTypes( ),
309         OSingleSelectQueryComposer_BASE::getTypes( ),
310         OPropertyContainer::getTypes( )
311     );
312 }
313 
getPropertySetInfo()314 css::uno::Reference< css::beans::XPropertySetInfo >  SAL_CALL OSingleSelectQueryComposer::getPropertySetInfo()
315 {
316     Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
317     return xInfo;
318 }
getInfoHelper()319 ::cppu::IPropertyArrayHelper& OSingleSelectQueryComposer::getInfoHelper()
320 {
321     return *OSingleSelectQueryComposer::getArrayHelper();
322 }
createArrayHelper() const323 ::cppu::IPropertyArrayHelper* OSingleSelectQueryComposer::createArrayHelper( ) const
324 {
325     css::uno::Sequence< css::beans::Property > aProps;
326     describeProperties(aProps);
327     return new ::cppu::OPropertyArrayHelper(aProps);
328 }
329 
330 
331 // XSingleSelectQueryAnalyzer
getQuery()332 OUString SAL_CALL OSingleSelectQueryComposer::getQuery(  )
333 {
334     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
335     ::osl::MutexGuard aGuard( m_aMutex );
336 
337     TGetParseNode F_tmp(&OSQLParseTreeIterator::getParseTree);
338     return getStatementPart(F_tmp,m_aSqlIterator);
339 }
340 
setQuery(const OUString & command)341 void SAL_CALL OSingleSelectQueryComposer::setQuery( const OUString& command )
342 {
343     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
344 
345     ::osl::MutexGuard aGuard( m_aMutex );
346     m_nCommandType = CommandType::COMMAND;
347     // first clear the tables and columns
348     clearCurrentCollections();
349     // now set the new one
350     setQuery_Impl(command);
351     m_sOriginal = command;
352 
353     // reset the additive iterator to the same statement
354     parseAndCheck_throwError( m_aSqlParser, m_sOriginal, m_aAdditiveIterator, *this );
355 
356     // we have no "elementary" parts anymore (means filter/groupby/having/order clauses)
357     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
358         m_aElementaryParts[ eLoopParts ].clear();
359 }
360 
setCommand(const OUString & Command,sal_Int32 _nCommandType)361 void SAL_CALL OSingleSelectQueryComposer::setCommand( const OUString& Command,sal_Int32 _nCommandType )
362 {
363     OUStringBuffer sSQL;
364     switch(_nCommandType)
365     {
366         case CommandType::COMMAND:
367             setElementaryQuery(Command);
368             return;
369         case CommandType::TABLE:
370             if ( m_xConnectionTables->hasByName(Command) )
371             {
372                 sSQL.append("SELECT * FROM ");
373                 Reference< XPropertySet > xTable;
374                 try
375                 {
376                     m_xConnectionTables->getByName( Command ) >>= xTable;
377                 }
378                 catch(const WrappedTargetException& e)
379                 {
380                     SQLException e2;
381                     if ( e.TargetException >>= e2 )
382                         throw e2;
383                 }
384                 catch(Exception&)
385                 {
386                     DBG_UNHANDLED_EXCEPTION("dbaccess");
387                 }
388 
389                 sSQL.append(dbtools::composeTableNameForSelect(m_xConnection,xTable));
390             }
391             else
392             {
393                 OUString sMessage( DBA_RES( RID_STR_TABLE_DOES_NOT_EXIST ) );
394                 throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
395             }
396             break;
397         case CommandType::QUERY:
398             if ( m_xConnectionQueries->hasByName(Command) )
399             {
400 
401                 Reference<XPropertySet> xQuery(m_xConnectionQueries->getByName(Command),UNO_QUERY);
402                 OUString sCommand;
403                 xQuery->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
404                 sSQL.append(sCommand);
405             }
406             else
407             {
408                 OUString sMessage( DBA_RES( RID_STR_QUERY_DOES_NOT_EXIST ) );
409                 throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
410             }
411 
412             break;
413         default:
414             break;
415     }
416     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
417 
418     ::osl::MutexGuard aGuard( m_aMutex );
419     m_nCommandType = _nCommandType;
420     m_sCommand = Command;
421     // first clear the tables and columns
422     clearCurrentCollections();
423     // now set the new one
424     OUString sCommand = sSQL.makeStringAndClear();
425     setElementaryQuery(sCommand);
426     m_sOriginal = sCommand;
427 }
428 
setQuery_Impl(const OUString & command)429 void OSingleSelectQueryComposer::setQuery_Impl( const OUString& command )
430 {
431     // parse this
432     parseAndCheck_throwError( m_aSqlParser, command, m_aSqlIterator, *this );
433 
434     // strip it from all clauses, to have the pure SELECT statement
435     m_aPureSelectSQL = getPureSelectStatement( m_aSqlIterator.getParseTree(), m_xConnection );
436 
437     // update tables
438     getTables();
439 }
440 
getStructuredHavingClause()441 Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredHavingClause(  )
442 {
443     TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleHavingTree);
444     return getStructuredCondition(F_tmp);
445 }
446 
getStructuredFilter()447 Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredFilter(  )
448 {
449     TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
450     return getStructuredCondition(F_tmp);
451 }
452 
appendHavingClauseByColumn(const Reference<XPropertySet> & column,sal_Bool andCriteria,sal_Int32 filterOperator)453 void SAL_CALL OSingleSelectQueryComposer::appendHavingClauseByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
454 {
455     auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetHavingClause);
456     setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
457 }
458 
appendFilterByColumn(const Reference<XPropertySet> & column,sal_Bool andCriteria,sal_Int32 filterOperator)459 void SAL_CALL OSingleSelectQueryComposer::appendFilterByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
460 {
461     auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetFilter);
462     setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
463 }
464 
impl_getColumnRealName_throw(const Reference<XPropertySet> & column,bool bGroupBy)465 OUString OSingleSelectQueryComposer::impl_getColumnRealName_throw(const Reference< XPropertySet >& column, bool bGroupBy)
466 {
467     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
468 
469     getColumns();
470     if ( !column.is()
471         || !m_aCurrentColumns[SelectColumns]
472         || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
473         )
474     {
475         OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
476         SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
477         throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any(aErr) );
478     }
479 
480     OUString aName, aNewName;
481     column->getPropertyValue(PROPERTY_NAME)         >>= aName;
482 
483     if ( bGroupBy &&
484          !m_xMetaData->supportsGroupByUnrelated() &&
485          m_aCurrentColumns[SelectColumns] &&
486          !m_aCurrentColumns[SelectColumns]->hasByName(aName) )
487     {
488         OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
489         throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
490     }
491 
492     OUString aQuote  = m_xMetaData->getIdentifierQuoteString();
493     if ( m_aCurrentColumns[SelectColumns]->hasByName(aName) )
494     {
495         Reference<XPropertySet> xColumn;
496         m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
497         OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
498         OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
499         OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(u"Function"_ustr),"Property FUNCTION not available!");
500 
501         OUString sRealName, sTableName;
502         xColumn->getPropertyValue(PROPERTY_REALNAME)    >>= sRealName;
503         xColumn->getPropertyValue(PROPERTY_TABLENAME)   >>= sTableName;
504         bool bFunction = false;
505         xColumn->getPropertyValue(u"Function"_ustr) >>= bFunction;
506         if ( sRealName == aName )
507         {
508             if ( bFunction )
509                 aNewName = aName;
510             else
511             {
512                 if(sTableName.indexOf('.') != -1)
513                 {
514                     OUString aCatalog,aSchema,aTable;
515                     ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
516                     sTableName = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
517                 }
518                 else if (!sTableName.isEmpty())
519                     sTableName = ::dbtools::quoteName(aQuote,sTableName);
520 
521                 if(sTableName.isEmpty())
522                     aNewName =  ::dbtools::quoteName(aQuote,sRealName);
523                 else
524                     aNewName =  sTableName + "." + ::dbtools::quoteName(aQuote,sRealName);
525             }
526         }
527         else
528             aNewName = ::dbtools::quoteName(aQuote,aName);
529     }
530     else
531         aNewName = getTableAlias(column) + ::dbtools::quoteName(aQuote,aName);
532     return aNewName;
533 }
534 
impl_getColumnNameOrderBy_throw(const Reference<XPropertySet> & column)535 OUString OSingleSelectQueryComposer::impl_getColumnNameOrderBy_throw(const Reference< XPropertySet >& column)
536 {
537     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
538 
539     getColumns();
540     if ( !column.is()
541         || !m_aCurrentColumns[SelectColumns]
542         || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
543         )
544     {
545         OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
546         SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
547         throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any(aErr) );
548     }
549 
550     OUString aName;
551     column->getPropertyValue(PROPERTY_NAME)         >>= aName;
552 
553     const OUString aQuote  = m_xMetaData->getIdentifierQuoteString();
554 
555     if ( m_aCurrentColumns[SelectColumns] &&
556          m_aCurrentColumns[SelectColumns]->hasByName(aName) )
557     {
558         // It is a column from the SELECT list, use it as such.
559         return ::dbtools::quoteName(aQuote,aName);
560     }
561 
562     // Nope, it is an unrelated column.
563     // Is that supported?
564     if ( !m_xMetaData->supportsOrderByUnrelated() )
565     {
566         OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
567         throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
568     }
569 
570     // We need to refer to it by its "real" name, that is by schemaName.tableName.columnNameInTable
571     return impl_getColumnRealName_throw(column, false);
572 }
573 
appendOrderByColumn(const Reference<XPropertySet> & column,sal_Bool ascending)574 void SAL_CALL OSingleSelectQueryComposer::appendOrderByColumn( const Reference< XPropertySet >& column, sal_Bool ascending )
575 {
576     ::osl::MutexGuard aGuard( m_aMutex );
577     OUString sColumnName( impl_getColumnNameOrderBy_throw(column) );
578     OUString sOrder = getOrder();
579     if ( !(sOrder.isEmpty() || sColumnName.isEmpty()) )
580         sOrder += COMMA;
581     sOrder += sColumnName;
582     if ( !(ascending || sColumnName.isEmpty()) )
583         sOrder += " DESC ";
584 
585     setOrder(sOrder);
586 }
587 
appendGroupByColumn(const Reference<XPropertySet> & column)588 void SAL_CALL OSingleSelectQueryComposer::appendGroupByColumn( const Reference< XPropertySet >& column)
589 {
590     ::osl::MutexGuard aGuard( m_aMutex );
591     OUString sColumnName( impl_getColumnRealName_throw(column, true) );
592     OrderCreator aComposer;
593     aComposer.append( getGroup() );
594     aComposer.append( sColumnName );
595     setGroup( aComposer.getComposedAndClear() );
596 }
597 
composeStatementFromParts(const std::vector<OUString> & _rParts)598 OUString OSingleSelectQueryComposer::composeStatementFromParts( const std::vector< OUString >& _rParts )
599 {
600     OSL_ENSURE( _rParts.size() == size_t(SQLPartCount), "OSingleSelectQueryComposer::composeStatementFromParts: invalid parts array!" );
601 
602     OUStringBuffer aSql( m_aPureSelectSQL );
603     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
604         if ( !_rParts[ eLoopParts ].isEmpty() )
605         {
606             aSql.append( getKeyword( eLoopParts ) );
607             aSql.append( _rParts[ eLoopParts ] );
608         }
609 
610     return aSql.makeStringAndClear();
611 }
612 
getElementaryQuery()613 OUString SAL_CALL OSingleSelectQueryComposer::getElementaryQuery()
614 {
615     return composeStatementFromParts( m_aElementaryParts );
616 }
617 
setElementaryQuery(const OUString & _rElementary)618 void SAL_CALL OSingleSelectQueryComposer::setElementaryQuery( const OUString& _rElementary )
619 {
620     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
621     ::osl::MutexGuard aGuard( m_aMutex );
622 
623     // remember the 4 current "additive" clauses
624     std::vector< OUString > aAdditiveClauses( SQLPartCount );
625     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
626         aAdditiveClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, false );
627 
628     // clear the tables and columns
629     clearCurrentCollections();
630     // set and parse the new query
631     setQuery_Impl( _rElementary );
632 
633     // get the 4 elementary parts of the statement
634     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
635         m_aElementaryParts[ eLoopParts ] = getSQLPart( eLoopParts, m_aSqlIterator, false );
636 
637     // reset the AdditiveIterator: m_aPureSelectSQL may have changed
638     try
639     {
640         parseAndCheck_throwError( m_aSqlParser, composeStatementFromParts( aAdditiveClauses ), m_aAdditiveIterator, *this );
641     }
642     catch( const Exception& )
643     {
644         DBG_UNHANDLED_EXCEPTION("dbaccess");
645         SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setElementaryQuery: there should be no error anymore for the additive statement!" );
646         // every part of the additive statement should have passed other tests already, and should not
647         // be able to cause any errors ... me thinks
648     }
649 }
650 
651 namespace
652 {
getComposedClause(const OUString & _rElementaryClause,const OUString & _rAdditionalClause,TokenComposer & _rComposer,std::u16string_view _rKeyword)653     OUString getComposedClause( const OUString& _rElementaryClause, const OUString& _rAdditionalClause,
654         TokenComposer& _rComposer, std::u16string_view _rKeyword )
655     {
656         _rComposer.clear();
657         _rComposer.append( _rElementaryClause );
658         _rComposer.append( _rAdditionalClause );
659         OUString sComposed = _rComposer.getComposedAndClear();
660         if ( !sComposed.isEmpty() )
661             sComposed = _rKeyword + sComposed;
662         return sComposed;
663     }
664 }
665 
setSingleAdditiveClause(SQLPart _ePart,const OUString & _rClause)666 void OSingleSelectQueryComposer::setSingleAdditiveClause( SQLPart _ePart, const OUString& _rClause )
667 {
668     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
669     ::osl::MutexGuard aGuard( m_aMutex );
670 
671     // if nothing is changed, do nothing
672     if ( getSQLPart( _ePart, m_aAdditiveIterator, false ) == _rClause )
673         return;
674 
675     // collect the 4 single parts as they're currently set
676     std::vector< OUString > aClauses;
677     aClauses.reserve( size_t(SQLPartCount) );
678     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
679         aClauses.push_back( getSQLPart( eLoopParts, m_aSqlIterator, true ) );
680 
681     // overwrite the one part in question here
682     std::unique_ptr< TokenComposer > pComposer;
683     if ( ( _ePart == Where ) || ( _ePart == Having ) )
684         pComposer.reset( new FilterCreator );
685     else
686         pComposer.reset( new OrderCreator );
687     aClauses[ _ePart ] = getComposedClause( m_aElementaryParts[ _ePart ], _rClause,
688         *pComposer, getKeyword( _ePart ) );
689 
690     // construct the complete statement
691     OUStringBuffer aSql(m_aPureSelectSQL);
692     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
693         aSql.append(aClauses[ eLoopParts ]);
694 
695     // set the query
696     setQuery_Impl(aSql.makeStringAndClear());
697 
698     // clear column collections which (might) have changed
699     clearColumns( ParameterColumns );
700     if ( _ePart == Order )
701         clearColumns( OrderColumns );
702     else if ( _ePart == Group )
703         clearColumns( GroupByColumns );
704 
705     // also, since the "additive filter" change, we need to rebuild our "additive" statement
706     aSql = m_aPureSelectSQL;
707     // again, first get all the old additive parts
708     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
709         aClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, true );
710     // then overwrite the one in question
711     aClauses[ _ePart ] = getComposedClause( OUString(), _rClause, *pComposer, getKeyword( _ePart ) );
712     // and parse it, so that m_aAdditiveIterator is up to date
713     for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
714         aSql.append(aClauses[ eLoopParts ]);
715     try
716     {
717         parseAndCheck_throwError( m_aSqlParser, aSql.makeStringAndClear(), m_aAdditiveIterator, *this );
718     }
719     catch( const Exception& )
720     {
721         SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setSingleAdditiveClause: there should be no error anymore for the additive statement!" );
722         // every part of the additive statement should have passed other tests already, and should not
723         // be able to cause any errors ... me thinks
724     }
725 }
726 
setFilter(const OUString & filter)727 void SAL_CALL OSingleSelectQueryComposer::setFilter( const OUString& filter )
728 {
729     setSingleAdditiveClause( Where, filter );
730 }
731 
setOrder(const OUString & order)732 void SAL_CALL OSingleSelectQueryComposer::setOrder( const OUString& order )
733 {
734     setSingleAdditiveClause( Order, order );
735 }
736 
setGroup(const OUString & group)737 void SAL_CALL OSingleSelectQueryComposer::setGroup( const OUString& group )
738 {
739     setSingleAdditiveClause( Group, group );
740 }
741 
setHavingClause(const OUString & filter)742 void SAL_CALL OSingleSelectQueryComposer::setHavingClause( const OUString& filter )
743 {
744     setSingleAdditiveClause( Having, filter );
745 }
746 
747 // XTablesSupplier
getTables()748 Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getTables(  )
749 {
750     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
751 
752     ::osl::MutexGuard aGuard( m_aMutex );
753     if ( !m_pTables )
754     {
755         const OSQLTables& aTables = m_aSqlIterator.getTables();
756         std::vector< OUString> aNames;
757         for (auto const& elem : aTables)
758             aNames.push_back(elem.first);
759 
760         m_pTables.reset( new OPrivateTables(aTables,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,std::move(aNames)) );
761     }
762 
763     return m_pTables.get();
764 }
765 
766 // XColumnsSupplier
getColumns()767 Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getColumns(  )
768 {
769     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
770     ::osl::MutexGuard aGuard( m_aMutex );
771     if ( !!m_aCurrentColumns[SelectColumns] )
772         return m_aCurrentColumns[SelectColumns].get();
773 
774     std::vector< OUString> aNames;
775     ::rtl::Reference< OSQLColumns> aSelectColumns;
776     bool bCase = true;
777     Reference< XNameAccess> xQueryColumns;
778     if ( m_nCommandType == CommandType::QUERY )
779     {
780         Reference<XColumnsSupplier> xSup(m_xConnectionQueries->getByName(m_sCommand),UNO_QUERY);
781         if(xSup.is())
782             xQueryColumns = xSup->getColumns();
783     }
784 
785     do {
786 
787     try
788     {
789         SharedUNOComponent< XStatement, DisposableComponent > xStatement;
790         SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
791 
792         bCase = m_xMetaData->supportsMixedCaseQuotedIdentifiers();
793         aSelectColumns = m_aSqlIterator.getSelectColumns();
794 
795         OUStringBuffer aSQL( m_aPureSelectSQL + STR_WHERE + " ( 0 = 1 )");
796 
797         // preserve the original WHERE clause
798         // #i102234#
799         OUString sOriginalWhereClause = getSQLPart( Where, m_aSqlIterator, false );
800         if ( !sOriginalWhereClause.isEmpty() )
801         {
802             aSQL.append( " AND ( " + sOriginalWhereClause + " ) " );
803         }
804 
805         OUString sGroupBy = getSQLPart( Group, m_aSqlIterator, true );
806         if ( !sGroupBy.isEmpty() )
807             aSQL.append( sGroupBy );
808 
809         OUString sSQL( aSQL.makeStringAndClear() );
810         // normalize the statement so that it doesn't contain any application-level features anymore
811         OUString sError;
812         const std::unique_ptr< OSQLParseNode > pStatementTree( m_aSqlParser.parseTree( sError, sSQL ) );
813         OSL_ENSURE(pStatementTree, "OSingleSelectQueryComposer::getColumns: could not parse the "
814                                    "column retrieval statement!");
815         if (pStatementTree)
816             if ( !pStatementTree->parseNodeToExecutableStatement( sSQL, m_xConnection, m_aSqlParser, nullptr ) )
817                 break;
818 
819         Reference< XResultSetMetaData > xResultSetMeta;
820         Reference< XResultSetMetaDataSupplier > xResMetaDataSup;
821         try
822         {
823             xPreparedStatement.set( m_xConnection->prepareStatement( sSQL ), UNO_QUERY_THROW );
824             xResMetaDataSup.set( xPreparedStatement, UNO_QUERY_THROW );
825             xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
826         }
827         catch( const Exception& ) { }
828 
829         if ( !xResultSetMeta.is() && xPreparedStatement.is() )
830         {
831             try
832             {
833                 //@see issue http://qa.openoffice.org/issues/show_bug.cgi?id=110111
834                 // access returns a different order of column names when executing select * from
835                 // and asking the columns from the metadata.
836                 Reference< XParameters > xParameters( xPreparedStatement, UNO_QUERY_THROW );
837                 Reference< XIndexAccess > xPara = getParameters();
838                 for(sal_Int32 i = 1;i <= xPara->getCount();++i)
839                     xParameters->setNull(i,DataType::VARCHAR);
840                 xResMetaDataSup.set(xPreparedStatement->executeQuery(), UNO_QUERY_THROW );
841                 xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
842             }
843             catch( const Exception& ) { }
844         }
845 
846         if ( !xResultSetMeta.is() )
847         {
848             xStatement.reset( Reference< XStatement >( m_xConnection->createStatement(), UNO_SET_THROW ) );
849             Reference< XPropertySet > xStatementProps( xStatement, UNO_QUERY_THROW );
850             try { xStatementProps->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, Any( false ) ); }
851             catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
852             xResMetaDataSup.set( xStatement->executeQuery( sSQL ), UNO_QUERY_THROW );
853             xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
854 
855             if (xResultSetMeta.is())
856             {
857                 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 );
858             }
859         }
860 
861         if ( aSelectColumns->empty() )
862         {
863             // This is a valid case. If we can syntactically parse the query, but not semantically
864             // (e.g. because it is based on a table we do not know), then there will be no SelectColumns
865             aSelectColumns = ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, m_xMetaData ,xQueryColumns);
866             break;
867         }
868 
869         const ::comphelper::UStringMixEqual aCaseCompare( bCase );
870         std::set< size_t > aUsedSelectColumns;
871         ::connectivity::parse::OParseColumn::StringMap aColumnNames;
872 
873         sal_Int32 nCount = xResultSetMeta->getColumnCount();
874         OSL_ENSURE( static_cast<size_t>(nCount) == aSelectColumns->size(), "OSingleSelectQueryComposer::getColumns: inconsistent column counts, this might result in wrong columns!" );
875         for(sal_Int32 i=1;i<=nCount;++i)
876         {
877             OUString sColumnName = xResultSetMeta->getColumnName(i);
878             OUString sColumnLabel;
879             if ( xQueryColumns.is() && xQueryColumns->hasByName(sColumnName) )
880             {
881                 Reference<XPropertySet> xQueryColumn(xQueryColumns->getByName(sColumnName),UNO_QUERY_THROW);
882                 xQueryColumn->getPropertyValue(PROPERTY_LABEL) >>= sColumnLabel;
883             }
884             else
885                 sColumnLabel = xResultSetMeta->getColumnLabel(i);
886             bool bFound = false;
887             OSQLColumns::Vector::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),sColumnLabel,aCaseCompare);
888             size_t nFoundSelectColumnPos = aFind - aSelectColumns->begin();
889             if ( aFind != aSelectColumns->end() )
890             {
891                 if ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
892                 {   // we found a column name which exists twice
893                     // so we start after the first found
894                     do
895                     {
896                         aFind = ::connectivity::findRealName(++aFind,aSelectColumns->end(),sColumnName,aCaseCompare);
897                         nFoundSelectColumnPos = aFind - aSelectColumns->begin();
898                     }
899                     while   (   ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
900                                 &&  ( aFind != aSelectColumns->end() )
901                             );
902                 }
903                 if ( aFind != aSelectColumns->end() )
904                 {
905                     (*aFind)->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
906                     aUsedSelectColumns.insert( nFoundSelectColumnPos );
907                     aNames.push_back(sColumnName);
908                     bFound = true;
909                 }
910             }
911 
912             if ( bFound )
913                 continue;
914 
915             OSQLColumns::Vector::const_iterator aRealFind = ::connectivity::findRealName(
916                 aSelectColumns->begin(), aSelectColumns->end(), sColumnName, aCaseCompare );
917 
918             if ( i > static_cast< sal_Int32>( aSelectColumns->size() ) )
919             {
920                 aSelectColumns->emplace_back(::connectivity::parse::OParseColumn::createColumnForResultSet( xResultSetMeta, m_xMetaData, i ,aColumnNames)
921                 );
922                 OSL_ENSURE( aSelectColumns->size() == static_cast<size_t>(i), "OSingleSelectQueryComposer::getColumns: inconsistency!" );
923             }
924             else if ( aRealFind == aSelectColumns->end() )
925             {
926                 // we can now only look if we found it under the realname property
927                 // here we have to make the assumption that the position is correct
928                 OSQLColumns::Vector::const_iterator aFind2 = aSelectColumns->begin() + i-1;
929                 Reference<XPropertySet> xProp = *aFind2;
930                 if ( !xProp.is() || !xProp->getPropertySetInfo()->hasPropertyByName( PROPERTY_REALNAME ) )
931                     continue;
932 
933                 rtl::Reference<::connectivity::parse::OParseColumn> pColumn = new ::connectivity::parse::OParseColumn(xProp,bCase);
934                 pColumn->setFunction(::comphelper::getBOOL(xProp->getPropertyValue(u"Function"_ustr)));
935                 pColumn->setAggregateFunction(::comphelper::getBOOL(xProp->getPropertyValue(u"AggregateFunction"_ustr)));
936 
937                 OUString sRealName;
938                 xProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
939                 if ( sColumnName.isEmpty() )
940                     xProp->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
941 
942                 sal_Int32 j = 0;
943                 while ( std::any_of(aNames.begin(),aNames.end(),
944                                     [&aCaseCompare, &sColumnName](const OUString& lhs)
945                                     { return aCaseCompare(lhs, sColumnName); } ) )
946                 {
947                     sColumnName += OUString::number(++j);
948                 }
949 
950                 pColumn->setName(sColumnName);
951                 pColumn->setRealName(sRealName);
952                 pColumn->setTableName(::comphelper::getString(xProp->getPropertyValue(PROPERTY_TABLENAME)));
953 
954                 (*aSelectColumns)[i-1] = pColumn;
955             }
956             else
957                 continue;
958 
959             aUsedSelectColumns.insert( static_cast<size_t>(i - 1) );
960             aNames.push_back( sColumnName );
961         }
962     }
963     catch(const Exception&)
964     {
965     }
966 
967     } while ( false );
968 
969     bool bMissingSomeColumnLabels = !aNames.empty() && aNames.size() != aSelectColumns->size();
970     SAL_WARN_IF(bMissingSomeColumnLabels, "dbaccess", "We have column labels for *some* columns but not all");
971     //^^this happens in the evolution address book where we have real column names of e.g.
972     //first_name, second_name and city. On parsing via
973     //OSQLParseTreeIterator::appendColumns it creates some labels using those real names
974     //but the evo address book gives them proper labels of First Name, Second Name and City
975     //the munge means that here we have e.g. just "City" as a label because it matches
976 
977     //This is all a horrible mess
978     if (bMissingSomeColumnLabels)
979         aNames.clear();
980 
981     if ( aNames.empty() )
982         m_aCurrentColumns[ SelectColumns ] = OPrivateColumns::createWithIntrinsicNames( aSelectColumns, bCase, *this, m_aMutex );
983     else
984         m_aCurrentColumns[ SelectColumns ].reset( new OPrivateColumns( aSelectColumns, bCase, *this, m_aMutex, aNames ) );
985 
986     return m_aCurrentColumns[SelectColumns].get();
987 }
988 
setORCriteria(OSQLParseNode const * pCondition,OSQLParseTreeIterator & _rIterator,std::vector<std::vector<PropertyValue>> & rFilters,const Reference<css::util::XNumberFormatter> & xFormatter) const989 bool OSingleSelectQueryComposer::setORCriteria(OSQLParseNode const * pCondition, OSQLParseTreeIterator& _rIterator,
990                                     std::vector< std::vector < PropertyValue > >& rFilters, const Reference< css::util::XNumberFormatter > & xFormatter) const
991 {
992     // Round brackets around the expression
993     if (pCondition->count() == 3 &&
994         SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
995         SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
996     {
997         return setORCriteria(pCondition->getChild(1), _rIterator, rFilters, xFormatter);
998     }
999     // OR logic expression
1000     // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
1001     else if (SQL_ISRULE(pCondition,search_condition))
1002     {
1003         bool bResult = true;
1004         for (int i = 0; bResult && i < 3; i+=2)
1005         {
1006             // Is the first element a OR logic expression again?
1007             // Then descend recursively ...
1008             if (SQL_ISRULE(pCondition->getChild(i),search_condition))
1009                 bResult = setORCriteria(pCondition->getChild(i), _rIterator, rFilters, xFormatter);
1010             else
1011             {
1012                 rFilters.emplace_back();
1013                 bResult = setANDCriteria(pCondition->getChild(i), _rIterator, rFilters[rFilters.size() - 1], xFormatter);
1014             }
1015         }
1016         return bResult;
1017     }
1018     else
1019     {
1020         rFilters.emplace_back();
1021         return setANDCriteria(pCondition, _rIterator, rFilters[rFilters.size() - 1], xFormatter);
1022     }
1023 }
1024 
setANDCriteria(OSQLParseNode const * pCondition,OSQLParseTreeIterator & _rIterator,std::vector<PropertyValue> & rFilter,const Reference<XNumberFormatter> & xFormatter) const1025 bool OSingleSelectQueryComposer::setANDCriteria( OSQLParseNode const * pCondition,
1026     OSQLParseTreeIterator& _rIterator, std::vector < PropertyValue >& rFilter, const Reference< XNumberFormatter > & xFormatter) const
1027 {
1028     // Round brackets
1029     if (SQL_ISRULE(pCondition,boolean_primary))
1030     {
1031         // this should not occur
1032         SAL_WARN("dbaccess","boolean_primary in And-Criteria");
1033         return false;
1034     }
1035     // The first element is an AND logical expression again
1036     else if ( SQL_ISRULE(pCondition,boolean_term) && pCondition->count() == 3 )
1037     {
1038         return setANDCriteria(pCondition->getChild(0), _rIterator, rFilter, xFormatter) &&
1039                setANDCriteria(pCondition->getChild(2), _rIterator, rFilter, xFormatter);
1040     }
1041     else if (SQL_ISRULE(pCondition, comparison_predicate))
1042     {
1043         return setComparisonPredicate(pCondition,_rIterator,rFilter,xFormatter);
1044     }
1045     else if (SQL_ISRULE(pCondition,like_predicate))
1046     {
1047         return setLikePredicate(pCondition,_rIterator,rFilter,xFormatter);
1048     }
1049     else if (SQL_ISRULE(pCondition,test_for_null) ||
1050              SQL_ISRULE(pCondition,in_predicate) ||
1051              SQL_ISRULE(pCondition,all_or_any_predicate) ||
1052              SQL_ISRULE(pCondition,between_predicate))
1053     {
1054         if (SQL_ISRULE(pCondition->getChild(0), column_ref))
1055         {
1056             PropertyValue aItem;
1057             OUString aValue;
1058             OUString aColumnName;
1059 
1060             pCondition->parseNodeToStr( aValue, m_xConnection );
1061             pCondition->getChild(0)->parseNodeToStr( aColumnName, m_xConnection );
1062 
1063             // don't display the column name
1064             aValue = aValue.copy(aColumnName.getLength());
1065             aValue = aValue.trim();
1066 
1067             aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
1068             aItem.Value <<= aValue;
1069             aItem.Handle = 0; // just to know that this is not one the known ones
1070             if ( SQL_ISRULE(pCondition,like_predicate) )
1071             {
1072                 if ( SQL_ISTOKEN(pCondition->getChild(1)->getChild(0),NOT) )
1073                     aItem.Handle = SQLFilterOperator::NOT_LIKE;
1074                 else
1075                     aItem.Handle = SQLFilterOperator::LIKE;
1076             }
1077             else if (SQL_ISRULE(pCondition,test_for_null))
1078             {
1079                 if (SQL_ISTOKEN(pCondition->getChild(1)->getChild(1),NOT) )
1080                     aItem.Handle = SQLFilterOperator::NOT_SQLNULL;
1081                 else
1082                     aItem.Handle = SQLFilterOperator::SQLNULL;
1083             }
1084             else if (SQL_ISRULE(pCondition,in_predicate))
1085             {
1086                 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: in_predicate not implemented!" );
1087             }
1088             else if (SQL_ISRULE(pCondition,all_or_any_predicate))
1089             {
1090                 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: all_or_any_predicate not implemented!" );
1091             }
1092             else if (SQL_ISRULE(pCondition,between_predicate))
1093             {
1094                 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: between_predicate not implemented!" );
1095             }
1096 
1097             rFilter.push_back(aItem);
1098         }
1099         else
1100             return false;
1101     }
1102     else if (SQL_ISRULE(pCondition,existence_test) ||
1103              SQL_ISRULE(pCondition,unique_test))
1104     {
1105         // this couldn't be handled here, too complex
1106         // as we need a field name
1107         return false;
1108     }
1109     else
1110         return false;
1111 
1112     return true;
1113 }
1114 
getPredicateType(OSQLParseNode const * _pPredicate)1115 sal_Int32 OSingleSelectQueryComposer::getPredicateType(OSQLParseNode const * _pPredicate)
1116 {
1117     sal_Int32 nPredicate = SQLFilterOperator::EQUAL;
1118     switch (_pPredicate->getNodeType())
1119     {
1120         case SQLNodeType::Equal:
1121             nPredicate = SQLFilterOperator::EQUAL;
1122             break;
1123         case SQLNodeType::NotEqual:
1124             nPredicate = SQLFilterOperator::NOT_EQUAL;
1125             break;
1126         case SQLNodeType::Less:
1127             nPredicate = SQLFilterOperator::LESS;
1128             break;
1129         case SQLNodeType::LessEq:
1130             nPredicate = SQLFilterOperator::LESS_EQUAL;
1131             break;
1132         case SQLNodeType::Great:
1133             nPredicate = SQLFilterOperator::GREATER;
1134             break;
1135         case SQLNodeType::GreatEq:
1136             nPredicate = SQLFilterOperator::GREATER_EQUAL;
1137             break;
1138         default:
1139             SAL_WARN("dbaccess","Wrong NodeType!");
1140     }
1141     return nPredicate;
1142 }
1143 
setLikePredicate(OSQLParseNode const * pCondition,OSQLParseTreeIterator const & _rIterator,std::vector<PropertyValue> & rFilter,const Reference<css::util::XNumberFormatter> & xFormatter) const1144 bool OSingleSelectQueryComposer::setLikePredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
1145                                             std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
1146 {
1147     OSL_ENSURE(SQL_ISRULE(pCondition, like_predicate),"setLikePredicate: pCondition is not a LikePredicate");
1148 
1149     assert(pCondition->count() == 2);
1150     OSQLParseNode const *pRowValue = pCondition->getChild(0);
1151     OSQLParseNode const *pPart2 = pCondition->getChild(1);
1152 
1153     PropertyValue aItem;
1154     if ( SQL_ISTOKEN(pPart2->getChild(0),NOT) )
1155         aItem.Handle = SQLFilterOperator::NOT_LIKE;
1156     else
1157         aItem.Handle = SQLFilterOperator::LIKE;
1158 
1159     if (SQL_ISRULE(pRowValue, column_ref))
1160     {
1161         OUString aValue;
1162 
1163         // skip (optional "NOT") and "LIKE"
1164         for (size_t i=2; i < pPart2->count(); i++)
1165         {
1166             pPart2->getChild(i)->parseNodeToPredicateStr(
1167                 aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1168         }
1169 
1170         aItem.Name = getColumnName(pRowValue,_rIterator);
1171         aItem.Value <<= aValue;
1172         rFilter.push_back(aItem);
1173     }
1174     else if (SQL_ISRULE(pRowValue, set_fct_spec ) ||
1175              SQL_ISRULE(pRowValue, general_set_fct))
1176     {
1177         OUString aValue;
1178         OUString aColumnName;
1179 
1180         pPart2->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1181         pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1182         pRowValue->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1183 
1184         aItem.Name = getColumnName(pRowValue,_rIterator);
1185         aItem.Value <<= aValue;
1186         rFilter.push_back(aItem);
1187     }
1188     else // Can only be an expression
1189     {
1190         OUString aName, aValue;
1191 
1192         OSQLParseNode const *pValue = pPart2->getChild(2);
1193 
1194         // Field names
1195         for (size_t i=0;i< pRowValue->count();i++)
1196              pRowValue->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1197 
1198         // Criterion
1199         for(size_t i=0;i< pValue->count();i++)
1200             pValue->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1201         pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1202 
1203         aItem.Name = aName;
1204         aItem.Value <<= aValue;
1205         rFilter.push_back(aItem);
1206     }
1207     return true;
1208 }
1209 
setComparisonPredicate(OSQLParseNode const * pCondition,OSQLParseTreeIterator const & _rIterator,std::vector<PropertyValue> & rFilter,const Reference<css::util::XNumberFormatter> & xFormatter) const1210 bool OSingleSelectQueryComposer::setComparisonPredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
1211                                             std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
1212 {
1213     OSL_ENSURE(SQL_ISRULE(pCondition, comparison_predicate),"setComparisonPredicate: pCondition is not a ComparisonPredicate");
1214     if (SQL_ISRULE(pCondition->getChild(0), column_ref) ||
1215         SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
1216     {
1217         PropertyValue aItem;
1218         OUString aValue;
1219         sal_uInt32 nPos;
1220         if (SQL_ISRULE(pCondition->getChild(0), column_ref))
1221         {
1222             nPos = 0;
1223             size_t i=1;
1224 
1225             aItem.Handle = getPredicateType(pCondition->getChild(i));
1226 
1227             // go forward - don't display the operator
1228             for (i++;i < pCondition->count();i++)
1229                 pCondition->getChild(i)->parseNodeToPredicateStr(
1230                     aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1231         }
1232         else if (SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
1233         {
1234             nPos = pCondition->count()-1;
1235 
1236             sal_Int32 i = pCondition->count() - 2;
1237             switch (pCondition->getChild(i)->getNodeType())
1238             {
1239                 case SQLNodeType::Equal:
1240                     aItem.Handle = SQLFilterOperator::EQUAL;
1241                     break;
1242                 case SQLNodeType::NotEqual:
1243                     aItem.Handle = SQLFilterOperator::NOT_EQUAL;
1244                     break;
1245                 case SQLNodeType::Less:
1246                     // take the opposite as we change the order
1247                     aItem.Handle = SQLFilterOperator::GREATER_EQUAL;
1248                     break;
1249                 case SQLNodeType::LessEq:
1250                     // take the opposite as we change the order
1251                     aItem.Handle = SQLFilterOperator::GREATER;
1252                     break;
1253                 case SQLNodeType::Great:
1254                     // take the opposite as we change the order
1255                     aItem.Handle = SQLFilterOperator::LESS_EQUAL;
1256                     break;
1257                 case SQLNodeType::GreatEq:
1258                     // take the opposite as we change the order
1259                     aItem.Handle = SQLFilterOperator::LESS;
1260                     break;
1261                 default:
1262                     break;
1263             }
1264 
1265             // go backward - don't display the operator
1266             for (i--; i >= 0; i--)
1267                 pCondition->getChild(i)->parseNodeToPredicateStr(
1268                     aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1269         }
1270         else
1271             return false;
1272 
1273         aItem.Name = getColumnName(pCondition->getChild(nPos),_rIterator);
1274         aItem.Value <<= aValue;
1275         rFilter.push_back(aItem);
1276     }
1277     else if (SQL_ISRULE(pCondition->getChild(0), set_fct_spec ) ||
1278              SQL_ISRULE(pCondition->getChild(0), general_set_fct))
1279     {
1280         PropertyValue aItem;
1281         OUString aValue;
1282         OUString aColumnName;
1283 
1284         pCondition->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1285         pCondition->getChild(0)->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1286 
1287         aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
1288         aItem.Value <<= aValue;
1289         aItem.Handle = getPredicateType(pCondition->getChild(1));
1290         rFilter.push_back(aItem);
1291     }
1292     else // Can only be an expression
1293     {
1294         PropertyValue aItem;
1295         OUString aName, aValue;
1296 
1297         OSQLParseNode *pLhs = pCondition->getChild(0);
1298         OSQLParseNode *pRhs = pCondition->getChild(2);
1299 
1300         // Field names
1301         for (size_t i=0;i< pLhs->count();i++)
1302              pLhs->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1303 
1304         // Criterion
1305         aItem.Handle = getPredicateType(pCondition->getChild(1));
1306         for(size_t i=0;i< pRhs->count();i++)
1307             pRhs->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
1308 
1309         aItem.Name = aName;
1310         aItem.Value <<= aValue;
1311         rFilter.push_back(aItem);
1312     }
1313     return true;
1314 }
1315 
1316 // Functions for analysing SQL
getColumnName(::connectivity::OSQLParseNode const * pColumnRef,OSQLParseTreeIterator const & _rIterator)1317 OUString OSingleSelectQueryComposer::getColumnName( ::connectivity::OSQLParseNode const * pColumnRef, OSQLParseTreeIterator const & _rIterator )
1318 {
1319     OUString aTableRange, aColumnName;
1320     _rIterator.getColumnRange(pColumnRef,aColumnName,aTableRange);
1321     return aColumnName;
1322 }
1323 
getFilter()1324 OUString SAL_CALL OSingleSelectQueryComposer::getFilter(  )
1325 {
1326     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1327     ::osl::MutexGuard aGuard( m_aMutex );
1328     return getSQLPart(Where,m_aAdditiveIterator,false);
1329 }
1330 
getOrder()1331 OUString SAL_CALL OSingleSelectQueryComposer::getOrder(  )
1332 {
1333     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1334     ::osl::MutexGuard aGuard( m_aMutex );
1335     return getSQLPart(Order,m_aAdditiveIterator,false);
1336 }
1337 
getGroup()1338 OUString SAL_CALL OSingleSelectQueryComposer::getGroup(  )
1339 {
1340     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1341     ::osl::MutexGuard aGuard( m_aMutex );
1342     return getSQLPart(Group,m_aAdditiveIterator,false);
1343 }
1344 
getHavingClause()1345 OUString OSingleSelectQueryComposer::getHavingClause()
1346 {
1347     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1348     ::osl::MutexGuard aGuard( m_aMutex );
1349     return getSQLPart(Having,m_aAdditiveIterator,false);
1350 }
1351 
getTableAlias(const Reference<XPropertySet> & column) const1352 OUString OSingleSelectQueryComposer::getTableAlias(const Reference< XPropertySet >& column) const
1353 {
1354     OUString sReturn;
1355     if(m_pTables && m_pTables->getCount() > 1)
1356     {
1357         OUString aCatalog,aSchema,aTable,aColumnName;
1358         if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_CATALOGNAME))
1359             column->getPropertyValue(PROPERTY_CATALOGNAME)  >>= aCatalog;
1360         if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_SCHEMANAME))
1361             column->getPropertyValue(PROPERTY_SCHEMANAME)   >>= aSchema;
1362         if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME))
1363             column->getPropertyValue(PROPERTY_TABLENAME)    >>= aTable;
1364         column->getPropertyValue(PROPERTY_NAME)         >>= aColumnName;
1365 
1366         Sequence< OUString> aNames(m_pTables->getElementNames());
1367         const OUString* pBegin     = aNames.begin();
1368         const OUString* const pEnd = aNames.end();
1369 
1370         if(aTable.isEmpty())
1371         { // we haven't found a table name, now we must search every table for this column
1372             for(;pBegin != pEnd;++pBegin)
1373             {
1374                 Reference<XColumnsSupplier> xColumnsSupp;
1375                 m_pTables->getByName(*pBegin) >>= xColumnsSupp;
1376 
1377                 if(xColumnsSupp.is() && xColumnsSupp->getColumns()->hasByName(aColumnName))
1378                 {
1379                     aTable = *pBegin;
1380                     break;
1381                 }
1382             }
1383         }
1384         else
1385         {
1386             OUString aComposedName = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, false, ::dbtools::EComposeRule::InDataManipulation );
1387 
1388             // Is this the right case for the table name?
1389             // Else, look for it with different case, if applicable.
1390 
1391             if(!m_pTables->hasByName(aComposedName))
1392             {
1393                 ::comphelper::UStringMixLess aTmp(m_aAdditiveIterator.getTables().key_comp());
1394                 ::comphelper::UStringMixEqual aComp(aTmp.isCaseSensitive());
1395                 for(;pBegin != pEnd;++pBegin)
1396                 {
1397                     Reference<XPropertySet> xTableProp;
1398                     m_pTables->getByName(*pBegin) >>= xTableProp;
1399                     OSL_ENSURE(xTableProp.is(),"Table isn't a propertyset!");
1400                     if(xTableProp.is())
1401                     {
1402                         OUString aCatalog2,aSchema2,aTable2;
1403                         xTableProp->getPropertyValue(PROPERTY_CATALOGNAME)  >>= aCatalog2;
1404                         xTableProp->getPropertyValue(PROPERTY_SCHEMANAME)   >>= aSchema2;
1405                         xTableProp->getPropertyValue(PROPERTY_NAME)         >>= aTable2;
1406                         if(aComp(aCatalog,aCatalog2) && aComp(aSchema,aSchema2) && aComp(aTable,aTable2))
1407                         {
1408                             aCatalog    = aCatalog2;
1409                             aSchema     = aSchema2;
1410                             aTable      = aTable2;
1411                             break;
1412                         }
1413                     }
1414                 }
1415             }
1416         }
1417         if(pBegin != pEnd)
1418         {
1419             sReturn = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ) + ".";
1420         }
1421     }
1422     return sReturn;
1423 }
1424 
getParameters()1425 Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getParameters(  )
1426 {
1427     // now set the Parameters
1428     if ( !m_aCurrentColumns[ParameterColumns] )
1429     {
1430         ::rtl::Reference< OSQLColumns> aCols = m_aSqlIterator.getParameters();
1431         std::vector< OUString> aNames;
1432         for (auto const& elem : *aCols)
1433             aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
1434         m_aCurrentColumns[ParameterColumns].reset( new OPrivateColumns(aCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
1435     }
1436 
1437     return m_aCurrentColumns[ParameterColumns].get();
1438 }
1439 
clearColumns(const EColumnType _eType)1440 void OSingleSelectQueryComposer::clearColumns( const EColumnType _eType )
1441 {
1442     OPrivateColumns* pColumns = m_aCurrentColumns[ _eType ].get();
1443     if ( pColumns != nullptr )
1444     {
1445         pColumns->disposing();
1446         m_aColumnsCollection.push_back( std::move(m_aCurrentColumns[ _eType ]) );
1447     }
1448 }
1449 
clearCurrentCollections()1450 void OSingleSelectQueryComposer::clearCurrentCollections()
1451 {
1452     for (auto & currentColumn : m_aCurrentColumns)
1453     {
1454         if (currentColumn)
1455         {
1456             currentColumn->disposing();
1457             m_aColumnsCollection.push_back(std::move(currentColumn));
1458         }
1459     }
1460 
1461     if(m_pTables)
1462     {
1463         m_pTables->disposing();
1464         m_aTablesCollection.push_back(std::move(m_pTables));
1465     }
1466 }
1467 
setCurrentColumns(EColumnType _eType,const::rtl::Reference<OSQLColumns> & _rCols)1468 Reference< XIndexAccess > OSingleSelectQueryComposer::setCurrentColumns( EColumnType _eType,
1469     const ::rtl::Reference< OSQLColumns >& _rCols )
1470 {
1471     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1472 
1473     ::osl::MutexGuard aGuard( m_aMutex );
1474     // now set the group columns
1475     if ( !m_aCurrentColumns[_eType] )
1476     {
1477         std::vector< OUString> aNames;
1478         for (auto const& elem : *_rCols)
1479             aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
1480         m_aCurrentColumns[_eType].reset( new OPrivateColumns(_rCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
1481     }
1482 
1483     return m_aCurrentColumns[_eType].get();
1484 }
1485 
getGroupColumns()1486 Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getGroupColumns(  )
1487 {
1488     return setCurrentColumns( GroupByColumns, m_aAdditiveIterator.getGroupColumns() );
1489 }
1490 
getOrderColumns()1491 Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getOrderColumns(  )
1492 {
1493     return setCurrentColumns( OrderColumns, m_aAdditiveIterator.getOrderColumns() );
1494 }
1495 
getQueryWithSubstitution()1496 OUString SAL_CALL OSingleSelectQueryComposer::getQueryWithSubstitution(  )
1497 {
1498     ::osl::MutexGuard aGuard( m_aMutex );
1499     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1500 
1501     OUString sSqlStatement( getQuery() );
1502 
1503     const OSQLParseNode* pStatementNode = m_aSqlIterator.getParseTree();
1504     if ( pStatementNode )
1505     {
1506         SQLException aError;
1507         if ( !pStatementNode->parseNodeToExecutableStatement( sSqlStatement, m_xConnection, m_aSqlParser, &aError ) )
1508             throw aError;
1509     }
1510 
1511     return sSqlStatement;
1512 }
1513 
getStatementPart(TGetParseNode const & _aGetFunctor,OSQLParseTreeIterator & _rIterator)1514 OUString OSingleSelectQueryComposer::getStatementPart( TGetParseNode const & _aGetFunctor, OSQLParseTreeIterator& _rIterator )
1515 {
1516     OUString sResult;
1517 
1518     const OSQLParseNode* pNode = _aGetFunctor( &_rIterator );
1519     if ( pNode )
1520         pNode->parseNodeToStr( sResult, m_xConnection );
1521 
1522     return sResult;
1523 }
1524 
1525 namespace
1526 {
lcl_getDecomposedColumnName(const OUString & rComposedName,std::u16string_view rQuoteString)1527     OUString lcl_getDecomposedColumnName(const OUString& rComposedName, std::u16string_view rQuoteString)
1528     {
1529         const size_t nQuoteLength = rQuoteString.size();
1530         OUString sName = rComposedName.trim();
1531         OUString sColumnName;
1532         sal_Int32 nPos, nRPos = 0;
1533 
1534         for (;;)
1535         {
1536             nPos = sName.indexOf( rQuoteString, nRPos );
1537             if ( nPos >= 0 )
1538             {
1539                 nRPos = sName.indexOf( rQuoteString, nPos + nQuoteLength );
1540                 if ( nRPos > nPos )
1541                 {
1542                     if ( static_cast<sal_Int32>(nRPos + nQuoteLength) < sName.getLength() )
1543                     {
1544                         nRPos += nQuoteLength; // -1 + 1 skip dot
1545                     }
1546                     else
1547                     {
1548                         sColumnName = sName.copy( nPos + nQuoteLength, nRPos - nPos - nQuoteLength );
1549                         break;
1550                     }
1551                 }
1552                 else
1553                     break;
1554             }
1555             else
1556                 break;
1557         }
1558         return sColumnName.isEmpty() ? rComposedName : sColumnName;
1559     }
1560 
lcl_getCondition(const Sequence<Sequence<PropertyValue>> & filter,const OPredicateInputController & i_aPredicateInputController,const Reference<XNameAccess> & i_xSelectColumns,std::u16string_view rQuoteString)1561     OUString lcl_getCondition(const Sequence< Sequence< PropertyValue > >& filter,
1562         const OPredicateInputController& i_aPredicateInputController,
1563         const Reference< XNameAccess >& i_xSelectColumns,
1564         std::u16string_view rQuoteString)
1565     {
1566         OUStringBuffer sRet;
1567         for (auto& rOr : filter)
1568         {
1569             if (rOr.hasElements())
1570             {
1571                 if (!sRet.isEmpty())
1572                     sRet.append(STR_OR);
1573                 sRet.append(L_BRACKET);
1574                 OUStringBuffer sAnd;
1575                 for (auto& rAnd : rOr)
1576                 {
1577                     if (!sAnd.isEmpty())
1578                         sAnd.append(STR_AND);
1579                     sAnd.append(rAnd.Name);
1580                     OUString sValue;
1581                     rAnd.Value >>= sValue;
1582                     const OUString sColumnName = lcl_getDecomposedColumnName( rAnd.Name, rQuoteString );
1583                     if ( i_xSelectColumns.is() && i_xSelectColumns->hasByName(sColumnName) )
1584                     {
1585                         Reference<XPropertySet> xColumn(i_xSelectColumns->getByName(sColumnName),UNO_QUERY);
1586                         sValue = i_aPredicateInputController.getPredicateValueStr(sValue,xColumn);
1587                     }
1588                     else
1589                     {
1590                         sValue = i_aPredicateInputController.getPredicateValueStr(rAnd.Name,sValue);
1591                     }
1592                     lcl_addFilterCriteria_throw(rAnd.Handle, sValue, sAnd);
1593                 }
1594                 sRet.append(OUString::unacquired(sAnd) + R_BRACKET);
1595             }
1596         }
1597         return sRet.makeStringAndClear();
1598     }
1599 }
1600 
setStructuredFilter(const Sequence<Sequence<PropertyValue>> & filter)1601 void SAL_CALL OSingleSelectQueryComposer::setStructuredFilter( const Sequence< Sequence< PropertyValue > >& filter )
1602 {
1603     OPredicateInputController aPredicateInput(m_aContext, m_xConnection, &m_aParseContext);
1604     setFilter(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
1605 }
1606 
setStructuredHavingClause(const Sequence<Sequence<PropertyValue>> & filter)1607 void SAL_CALL OSingleSelectQueryComposer::setStructuredHavingClause( const Sequence< Sequence< PropertyValue > >& filter )
1608 {
1609     OPredicateInputController aPredicateInput(m_aContext, m_xConnection);
1610     setHavingClause(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
1611 }
1612 
setConditionByColumn(const Reference<XPropertySet> & column,bool andCriteria,std::function<bool (OSingleSelectQueryComposer *,const OUString &)> const & _aSetFunctor,sal_Int32 filterOperator)1613 void OSingleSelectQueryComposer::setConditionByColumn( const Reference< XPropertySet >& column, bool andCriteria, std::function<bool(OSingleSelectQueryComposer *, const OUString&)> const & _aSetFunctor, sal_Int32 filterOperator)
1614 {
1615     try
1616     {
1617         ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1618 
1619         if ( !column.is()
1620              || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_VALUE)
1621              || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
1622              || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE))
1623             throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any() );
1624 
1625         sal_Int32 nType = 0;
1626         column->getPropertyValue(PROPERTY_TYPE) >>= nType;
1627         sal_Int32 nSearchable = dbtools::getSearchColumnFlag(m_xConnection,nType);
1628         if(nSearchable == ColumnSearch::NONE)
1629             throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_SEARCHABLE),*this,SQLSTATE_GENERAL,1000,Any() );
1630 
1631         ::osl::MutexGuard aGuard( m_aMutex );
1632 
1633         OUString aName;
1634         column->getPropertyValue(PROPERTY_NAME) >>= aName;
1635 
1636         const Any aValue = column->getPropertyValue(PROPERTY_VALUE);
1637 
1638         OUStringBuffer aSQL;
1639         const OUString aQuote    = m_xMetaData->getIdentifierQuoteString();
1640         getColumns();
1641 
1642         // TODO: if this is called for HAVING, check that the column is a GROUP BY column
1643         //       or that it is an aggregate function
1644 
1645         if ( m_aCurrentColumns[SelectColumns] && m_aCurrentColumns[SelectColumns]->hasByName(aName) )
1646         {
1647             Reference<XPropertySet> xColumn;
1648             m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
1649             OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
1650             OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
1651             OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(u"AggregateFunction"_ustr),"Property AggregateFunction not available!");
1652 
1653             OUString sRealName,sTableName;
1654             xColumn->getPropertyValue(PROPERTY_REALNAME)    >>= sRealName;
1655             xColumn->getPropertyValue(PROPERTY_TABLENAME)   >>= sTableName;
1656             if(sTableName.indexOf('.') != -1)
1657             {
1658                 OUString aCatalog,aSchema,aTable;
1659                 ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
1660                 sTableName = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
1661             }
1662             else
1663                 sTableName = ::dbtools::quoteName(aQuote,sTableName);
1664 
1665             if ( !::comphelper::getBOOL(xColumn->getPropertyValue(u"Function"_ustr)) )
1666             {
1667                 aSQL =  sTableName + "." + ::dbtools::quoteName( aQuote, sRealName );
1668             }
1669             else
1670                 aSQL = sRealName;
1671         }
1672         else
1673         {
1674             aSQL = getTableAlias( column ) + ::dbtools::quoteName( aQuote, aName );
1675         }
1676 
1677         if ( aValue.hasValue() )
1678         {
1679             if(  !m_xTypeConverter.is() )
1680                 m_xTypeConverter.set( Converter::create(m_aContext) );
1681             OSL_ENSURE(m_xTypeConverter.is(),"NO typeconverter!");
1682 
1683             if ( nType != DataType::BOOLEAN && DataType::BIT != nType )
1684             {
1685                 lcl_addFilterCriteria_throw(filterOperator,u"",aSQL);
1686             }
1687 
1688             switch(nType)
1689             {
1690             case DataType::VARCHAR:
1691             case DataType::CHAR:
1692             case DataType::LONGVARCHAR:
1693                 aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
1694                 break;
1695             case DataType::CLOB:
1696                 {
1697                     Reference< XClob > xClob(aValue,UNO_QUERY);
1698                     if ( xClob.is() )
1699                     {
1700                         const ::sal_Int64 nLength = xClob->length();
1701                         if ( sal_Int64(nLength + aSQL.getLength() + STR_LIKE.getLength() ) < sal_Int64(SAL_MAX_INT32) )
1702                         {
1703                             aSQL.append("'" + xClob->getSubString(1,static_cast<sal_Int32>(nLength)) + "'");
1704                         }
1705                     }
1706                     else
1707                     {
1708                         aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
1709                     }
1710                 }
1711                 break;
1712             case DataType::VARBINARY:
1713             case DataType::BINARY:
1714             case DataType::LONGVARBINARY:
1715                 {
1716                     Sequence<sal_Int8> aSeq;
1717                     if(!(aValue >>= aSeq))
1718                         throw SQLException(DBA_RES(RID_STR_NOT_SEQUENCE_INT8),*this,SQLSTATE_GENERAL,1000,Any() );
1719                     if(nSearchable == ColumnSearch::CHAR)
1720                     {
1721                         aSQL.append( "\'" );
1722                     }
1723                     aSQL.append( "0x" );
1724                     for (sal_Int32 byte : aSeq)
1725                         aSQL.append(byte, 16);
1726                     if(nSearchable == ColumnSearch::CHAR)
1727                         aSQL.append( "\'" );
1728                 }
1729                 break;
1730             case DataType::BIT:
1731             case DataType::BOOLEAN:
1732                 {
1733                     bool bValue = false;
1734                     m_xTypeConverter->convertToSimpleType(aValue, TypeClass_BOOLEAN) >>= bValue;
1735 
1736                     OUString sColumnExp = aSQL.makeStringAndClear();
1737                     getBooleanComparisonPredicate( sColumnExp, bValue, m_nBoolCompareMode, aSQL );
1738                 }
1739                 break;
1740             default:
1741                 aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
1742                 break;
1743             }
1744         }
1745         else
1746         {
1747             sal_Int32 nFilterOp = filterOperator;
1748             if ( filterOperator != SQLFilterOperator::SQLNULL && filterOperator != SQLFilterOperator::NOT_SQLNULL )
1749                 nFilterOp = SQLFilterOperator::SQLNULL;
1750             lcl_addFilterCriteria_throw(nFilterOp,u"",aSQL);
1751         }
1752 
1753         // Attach filter
1754         // Construct SELECT without WHERE and ORDER BY
1755         OUString sFilter = getFilter();
1756 
1757         if ( !sFilter.isEmpty() && !aSQL.isEmpty() )
1758         {
1759             sFilter = L_BRACKET + sFilter + R_BRACKET +
1760                 (andCriteria ? std::u16string_view(STR_AND) : std::u16string_view(STR_OR));
1761         }
1762         sFilter += aSQL;
1763 
1764         // add the filter and the sort order
1765         _aSetFunctor(this,sFilter);
1766     }
1767     catch (css::lang::WrappedTargetException & e)
1768     {
1769         if (e.TargetException.isExtractableTo(
1770                 cppu::UnoType<css::sdbc::SQLException>::get()))
1771         {
1772             cppu::throwException(e.TargetException);
1773         }
1774         else
1775         {
1776             throw;
1777         }
1778     }
1779 }
1780 
getStructuredCondition(TGetParseNode const & _aGetFunctor)1781 Sequence< Sequence< PropertyValue > > OSingleSelectQueryComposer::getStructuredCondition( TGetParseNode const & _aGetFunctor )
1782 {
1783     ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
1784 
1785     MutexGuard aGuard(m_aMutex);
1786 
1787     Sequence< Sequence< PropertyValue > > aFilterSeq;
1788     OUString sFilter = getStatementPart( _aGetFunctor, m_aAdditiveIterator );
1789 
1790 
1791     if ( !sFilter.isEmpty() )
1792     {
1793         OUString aSql(m_aPureSelectSQL + STR_WHERE + sFilter);
1794         // build a temporary parse node
1795         const OSQLParseNode* pTempNode = m_aAdditiveIterator.getParseTree();
1796 
1797         OUString aErrorMsg;
1798         std::unique_ptr<OSQLParseNode> pSqlParseNode( m_aSqlParser.parseTree(aErrorMsg,aSql));
1799         if (pSqlParseNode)
1800         {
1801             m_aAdditiveIterator.setParseTree(pSqlParseNode.get());
1802             // normalize the filter
1803             OSQLParseNode* pWhereNode = const_cast<OSQLParseNode*>(m_aAdditiveIterator.getWhereTree());
1804 
1805             OSQLParseNode* pCondition = pWhereNode->getChild(1);
1806         #if OSL_DEBUG_LEVEL > 0
1807             OUString sCondition;
1808             pCondition->parseNodeToStr( sCondition, m_xConnection );
1809         #endif
1810             OSQLParseNode::negateSearchCondition(pCondition);
1811 
1812             pCondition = pWhereNode->getChild(1);
1813         #if OSL_DEBUG_LEVEL > 0
1814             sCondition.clear();
1815             pCondition->parseNodeToStr( sCondition, m_xConnection );
1816         #endif
1817             OSQLParseNode::disjunctiveNormalForm(pCondition);
1818 
1819             pCondition = pWhereNode->getChild(1);
1820         #if OSL_DEBUG_LEVEL > 0
1821             sCondition.clear();
1822             pCondition->parseNodeToStr( sCondition, m_xConnection );
1823         #endif
1824             OSQLParseNode::absorptions(pCondition);
1825 
1826             pCondition = pWhereNode->getChild(1);
1827         #if OSL_DEBUG_LEVEL > 0
1828             sCondition.clear();
1829             pCondition->parseNodeToStr( sCondition, m_xConnection );
1830         #endif
1831             if ( pCondition )
1832             {
1833                 std::vector< std::vector < PropertyValue > > aFilters;
1834                 Reference< XNumberFormatter > xFormatter( NumberFormatter::create(m_aContext), UNO_QUERY_THROW );
1835                 xFormatter->attachNumberFormatsSupplier( m_xNumberFormatsSupplier );
1836 
1837                 if (setORCriteria(pCondition, m_aAdditiveIterator, aFilters, xFormatter))
1838                 {
1839                     aFilterSeq.realloc(aFilters.size());
1840                     Sequence<PropertyValue>* pFilters = aFilterSeq.getArray();
1841                     for (auto const& filter : aFilters)
1842                     {
1843                         pFilters->realloc(filter.size());
1844                         PropertyValue* pFilter = pFilters->getArray();
1845                         for (auto const& elem : filter)
1846                         {
1847                             *pFilter = elem;
1848                             ++pFilter;
1849                         }
1850                         ++pFilters;
1851                     }
1852                 }
1853             }
1854             // restore
1855             m_aAdditiveIterator.setParseTree(pTempNode);
1856         }
1857     }
1858     return aFilterSeq;
1859 }
1860 
getKeyword(SQLPart _ePart)1861 OUString OSingleSelectQueryComposer::getKeyword( SQLPart _ePart )
1862 {
1863     OUString sKeyword;
1864     switch(_ePart)
1865     {
1866         default:
1867             SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getKeyWord: Invalid enum value!" );
1868             [[fallthrough]]; // fallback to WHERE
1869         case Where:
1870             sKeyword = STR_WHERE;
1871             break;
1872         case Group:
1873             sKeyword = STR_GROUP_BY;
1874             break;
1875         case Having:
1876             sKeyword = STR_HAVING;
1877             break;
1878         case Order:
1879             sKeyword = STR_ORDER_BY;
1880             break;
1881     }
1882     return sKeyword;
1883 }
1884 
getSQLPart(SQLPart _ePart,OSQLParseTreeIterator & _rIterator,bool _bWithKeyword)1885 OUString OSingleSelectQueryComposer::getSQLPart( SQLPart _ePart, OSQLParseTreeIterator& _rIterator, bool _bWithKeyword )
1886 {
1887     TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
1888     OUString sKeyword( getKeyword( _ePart ) );
1889     switch(_ePart)
1890     {
1891         case Where:
1892             F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleWhereTree);
1893             break;
1894         case Group:
1895             F_tmp = TGetParseNode (&OSQLParseTreeIterator::getSimpleGroupByTree);
1896             break;
1897         case Having:
1898             F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleHavingTree);
1899             break;
1900         case Order:
1901             F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleOrderTree);
1902             break;
1903         default:
1904             SAL_WARN("dbaccess","Invalid enum value!");
1905     }
1906 
1907     OUString sRet = getStatementPart( F_tmp, _rIterator );
1908     if ( _bWithKeyword && !sRet.isEmpty() )
1909         sRet = sKeyword + sRet;
1910     return sRet;
1911 }
1912 
1913 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1914