1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
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
;
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 "
88 #define STR_LIKE OUString(" LIKE ")
95 /** parses the given statement, using the given parser, returns a parse node representing
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
)
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
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
) );
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
);
159 _pRootNode
->getChild(3)->getChild(0)->getChild(1)->parseNodeToStr( sSQL
, _rxConnection
);
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
);
179 case SQLFilterOperator::NOT_EQUAL
:
180 o_sRet
.append(" <> " ).append( i_sValue
);
182 case SQLFilterOperator::LESS
:
183 o_sRet
.append(" < " ).append( i_sValue
);
185 case SQLFilterOperator::GREATER
:
186 o_sRet
.append(" > " ).append( i_sValue
);
188 case SQLFilterOperator::LESS_EQUAL
:
189 o_sRet
.append(" <= " ).append( i_sValue
);
191 case SQLFilterOperator::GREATER_EQUAL
:
192 o_sRet
.append(" >= " ).append( i_sValue
);
194 case SQLFilterOperator::LIKE
:
195 o_sRet
.append(" LIKE " ).append( i_sValue
);
197 case SQLFilterOperator::NOT_LIKE
:
198 o_sRet
.append(" NOT LIKE " ).append( i_sValue
);
200 case SQLFilterOperator::SQLNULL
:
201 o_sRet
.append(" IS NULL");
203 case SQLFilterOperator::NOT_SQLNULL
:
204 o_sRet
.append(" IS NOT NULL");
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");
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();
260 OSingleSelectQueryComposer::~OSingleSelectQueryComposer()
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
)
324 switch(_nCommandType
)
326 case CommandType::COMMAND
:
327 setElementaryQuery(Command
);
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
)
341 if ( e
.TargetException
>>= e2
)
346 DBG_UNHANDLED_EXCEPTION("dbaccess");
349 sSQL
.append(dbtools::composeTableNameForSelect(m_xConnection
,xTable
));
353 OUString
sMessage( DBA_RES( RID_STR_TABLE_DOES_NOT_EXIST
) );
354 throwGenericSQLException(sMessage
.replaceAll( "$table$", Command
),*this);
357 case CommandType::QUERY
:
358 if ( m_xConnectionQueries
->hasByName(Command
) )
361 Reference
<XPropertySet
> xQuery(m_xConnectionQueries
->getByName(Command
),UNO_QUERY
);
363 xQuery
->getPropertyValue(PROPERTY_COMMAND
) >>= sCommand
;
364 sSQL
.append(sCommand
);
368 OUString
sMessage( DBA_RES( RID_STR_QUERY_DOES_NOT_EXIST
) );
369 throwGenericSQLException(sMessage
.replaceAll( "$table$", Command
),*this);
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
)
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
);
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
);
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
;
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
)
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
);
484 aNewName
= sTableName
+ "." + ::dbtools::quoteName(aQuote
,sRealName
);
488 aNewName
= ::dbtools::quoteName(aQuote
,aName
);
491 aNewName
= getTableAlias(column
) + ::dbtools::quoteName(aQuote
,aName
);
495 OUString
OSingleSelectQueryComposer::impl_getColumnNameOrderBy_throw(const Reference
< XPropertySet
>& column
)
497 ::connectivity::checkDisposed(OSubComponent::rBHelper
.bDisposed
);
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
) );
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()) )
541 sOrder
+= sColumnName
;
542 if ( !(ascending
|| sColumnName
.isEmpty()) )
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
613 OUString
getComposedClause( const OUString
& _rElementaryClause
, const OUString
& _rAdditionalClause
,
614 TokenComposer
& _rComposer
, const OUString
& _rKeyword
)
617 _rComposer
.append( _rElementaryClause
);
618 _rComposer
.append( _rAdditionalClause
);
619 OUString sComposed
= _rComposer
.getComposedAndClear();
620 if ( !sComposed
.isEmpty() )
621 sComposed
= _rKeyword
+ 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
)
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
);
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
]);
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
);
708 Reference
< XNameAccess
> SAL_CALL
OSingleSelectQueryComposer::getTables( )
710 ::connectivity::checkDisposed(OSubComponent::rBHelper
.bDisposed
);
712 ::osl::MutexGuard
aGuard( m_aMutex
);
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();
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
;
737 Reference
< XNameAccess
> xQueryColumns
;
738 if ( m_nCommandType
== CommandType::QUERY
)
740 Reference
<XColumnsSupplier
> xSup(m_xConnectionQueries
->getByName(m_sCommand
),UNO_QUERY
);
742 xQueryColumns
= xSup
->getColumns();
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
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
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!");
776 if ( !pStatementTree
->parseNodeToExecutableStatement( sSQL
, m_xConnection
, m_aSqlParser
, nullptr ) )
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
);
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
;
845 sColumnLabel
= xResultSetMeta
->getColumnLabel(i
);
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
);
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
) )
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")));
898 xProp
->getPropertyValue(PROPERTY_REALNAME
) >>= sRealName
;
899 if ( sColumnName
.isEmpty() )
900 xProp
->getPropertyValue(PROPERTY_NAME
) >>= sColumnName
;
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
;
919 aUsedSelectColumns
.insert( static_cast<size_t>(i
- 1) );
920 aNames
.push_back( sColumnName
);
923 catch(const Exception
&)
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
)
941 if ( aNames
.empty() )
942 m_aCurrentColumns
[ SelectColumns
] = OPrivateColumns::createWithIntrinsicNames( aSelectColumns
, bCase
, *this, m_aMutex
);
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
))
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
);
972 rFilters
.emplace_back();
973 bResult
= setANDCriteria(pCondition
->getChild(i
), _rIterator
, rFilters
[rFilters
.size() - 1], xFormatter
);
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
989 if (SQL_ISRULE(pCondition
,boolean_primary
))
991 // this should not occur
992 SAL_WARN("dbaccess","boolean_primary in And-Criteria");
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
;
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
;
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
;
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
);
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
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
;
1083 case SQLNodeType::NotEqual
:
1084 nPredicate
= SQLFilterOperator::NOT_EQUAL
;
1086 case SQLNodeType::Less
:
1087 nPredicate
= SQLFilterOperator::LESS
;
1089 case SQLNodeType::LessEq
:
1090 nPredicate
= SQLFilterOperator::LESS_EQUAL
;
1092 case SQLNodeType::Great
:
1093 nPredicate
= SQLFilterOperator::GREATER
;
1095 case SQLNodeType::GreatEq
:
1096 nPredicate
= SQLFilterOperator::GREATER_EQUAL
;
1099 SAL_WARN("dbaccess","Wrong NodeType!");
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
;
1117 aItem
.Handle
= SQLFilterOperator::LIKE
;
1119 if (SQL_ISRULE(pRowValue
, column_ref
))
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
))
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);
1155 for (size_t i
=0;i
< pRowValue
->count();i
++)
1156 pRowValue
->getChild(i
)->parseNodeToPredicateStr( aName
, m_xConnection
, xFormatter
, m_aLocale
, m_sDecimalSep
);
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
);
1164 aItem
.Value
<<= aValue
;
1165 rFilter
.push_back(aItem
);
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
;
1180 if (SQL_ISRULE(pCondition
->getChild(0), column_ref
))
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
;
1202 case SQLNodeType::NotEqual
:
1203 aItem
.Handle
= SQLFilterOperator::NOT_EQUAL
;
1205 case SQLNodeType::Less
:
1206 // take the opposite as we change the order
1207 aItem
.Handle
= SQLFilterOperator::GREATER_EQUAL
;
1209 case SQLNodeType::LessEq
:
1210 // take the opposite as we change the order
1211 aItem
.Handle
= SQLFilterOperator::GREATER
;
1213 case SQLNodeType::Great
:
1214 // take the opposite as we change the order
1215 aItem
.Handle
= SQLFilterOperator::LESS_EQUAL
;
1217 case SQLNodeType::GreatEq
:
1218 // take the opposite as we change the order
1219 aItem
.Handle
= SQLFilterOperator::LESS
;
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
);
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
;
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);
1261 for (size_t i
=0;i
< pLhs
->count();i
++)
1262 pLhs
->getChild(i
)->parseNodeToPredicateStr( aName
, m_xConnection
, xFormatter
, m_aLocale
, m_sDecimalSep
);
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
);
1270 aItem
.Value
<<= aValue
;
1271 rFilter
.push_back(aItem
);
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
);
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
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
))
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!");
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
;
1379 sReturn
= ::dbtools::composeTableName( m_xMetaData
, aCatalog
, aSchema
, aTable
, true, ::dbtools::EComposeRule::InDataManipulation
) + ".";
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
)
1416 currentColumn
->disposing();
1417 m_aColumnsCollection
.push_back(std::move(currentColumn
));
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
) )
1471 return sSqlStatement
;
1474 OUString
OSingleSelectQueryComposer::getStatementPart( TGetParseNode
const & _aGetFunctor
, OSQLParseTreeIterator
& _rIterator
)
1478 const OSQLParseNode
* pNode
= _aGetFunctor( &_rIterator
);
1480 pNode
->parseNodeToStr( sResult
, m_xConnection
);
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;
1496 nPos
= sName
.indexOf( rQuoteString
, nRPos
);
1499 nRPos
= sName
.indexOf( rQuoteString
, nPos
+ nQuoteLength
);
1502 if ( nRPos
+ nQuoteLength
< sName
.getLength() )
1504 nRPos
+= nQuoteLength
; // -1 + 1 skip dot
1508 sColumnName
= sName
.copy( nPos
+ nQuoteLength
, nRPos
- nPos
- nQuoteLength
);
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
);
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
);
1549 sValue
= i_aPredicateInputController
.getPredicateValueStr(pAndIter
->Name
,sValue
);
1551 lcl_addFilterCriteria_throw(pAndIter
->Handle
,sValue
,sRet
);
1553 if ( pAndIter
!= pAndEnd
)
1554 sRet
.append(STR_AND
);
1556 sRet
.append(R_BRACKET
);
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
);
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
);
1599 column
->getPropertyValue(PROPERTY_NAME
) >>= aName
;
1601 const Any aValue
= column
->getPropertyValue(PROPERTY_VALUE
);
1603 OUStringBuffer aSQL
;
1604 const OUString aQuote
= m_xMetaData
->getIdentifierQuoteString();
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
);
1628 sTableName
= ::dbtools::quoteName(aQuote
,sTableName
);
1630 if ( !::comphelper::getBOOL(xColumn
->getPropertyValue("Function")) )
1632 aSQL
= sTableName
+ "." + ::dbtools::quoteName( aQuote
, sRealName
);
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
);
1655 case DataType::VARCHAR
:
1656 case DataType::CHAR
:
1657 case DataType::LONGVARCHAR
:
1658 aSQL
.append( DBTypeConversion::toSQLString( nType
, aValue
, m_xTypeConverter
) );
1660 case DataType::CLOB
:
1662 Reference
< XClob
> xClob(aValue
,UNO_QUERY
);
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("'");
1673 aSQL
.append( DBTypeConversion::toSQLString( nType
, aValue
, m_xTypeConverter
) );
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( "\'" );
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
);
1710 aSQL
.append( DBTypeConversion::toSQLString( nType
, aValue
, m_xTypeConverter
) );
1716 sal_Int32 nFilterOp
= filterOperator
;
1717 if ( filterOperator
!= SQLFilterOperator::SQLNULL
&& filterOperator
!= SQLFilterOperator::NOT_SQLNULL
)
1718 nFilterOp
= SQLFilterOperator::SQLNULL
;
1719 lcl_addFilterCriteria_throw(nFilterOp
,"",aSQL
);
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
));
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
);
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();
1767 std::unique_ptr
<OSQLParseNode
> pSqlParseNode( m_aSqlParser
.parseTree(aErrorMsg
,aSql
));
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
);
1779 OSQLParseNode::negateSearchCondition(pCondition
);
1781 pCondition
= pWhereNode
->getChild(1);
1782 #if OSL_DEBUG_LEVEL > 0
1784 pCondition
->parseNodeToStr( sCondition
, m_xConnection
);
1786 OSQLParseNode::disjunctiveNormalForm(pCondition
);
1788 pCondition
= pWhereNode
->getChild(1);
1789 #if OSL_DEBUG_LEVEL > 0
1791 pCondition
->parseNodeToStr( sCondition
, m_xConnection
);
1793 OSQLParseNode::absorptions(pCondition
);
1795 pCondition
= pWhereNode
->getChild(1);
1796 #if OSL_DEBUG_LEVEL > 0
1798 pCondition
->parseNodeToStr( sCondition
, m_xConnection
);
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
)
1824 m_aAdditiveIterator
.setParseTree(pTempNode
);
1830 OUString
OSingleSelectQueryComposer::getKeyword( SQLPart _ePart
)
1836 SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getKeyWord: Invalid enum value!" );
1837 [[fallthrough
]]; // fallback to WHERE
1839 sKeyword
= STR_WHERE
;
1842 sKeyword
= STR_GROUP_BY
;
1845 sKeyword
= STR_HAVING
;
1848 sKeyword
= STR_ORDER_BY
;
1854 OUString
OSingleSelectQueryComposer::getSQLPart( SQLPart _ePart
, OSQLParseTreeIterator
& _rIterator
, bool _bWithKeyword
)
1856 TGetParseNode
F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree
);
1857 OUString
sKeyword( getKeyword( _ePart
) );
1861 F_tmp
= TGetParseNode(&OSQLParseTreeIterator::getSimpleWhereTree
);
1864 F_tmp
= TGetParseNode (&OSQLParseTreeIterator::getSimpleGroupByTree
);
1867 F_tmp
= TGetParseNode(&OSQLParseTreeIterator::getSimpleHavingTree
);
1870 F_tmp
= TGetParseNode(&OSQLParseTreeIterator::getSimpleOrderTree
);
1873 SAL_WARN("dbaccess","Invalid enum value!");
1876 OUString sRet
= getStatementPart( F_tmp
, _rIterator
);
1877 if ( _bWithKeyword
&& !sRet
.isEmpty() )
1878 sRet
= sKeyword
+ sRet
;
1882 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */