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 <sal/config.h>
21 
22 #include <o3tl/safeint.hxx>
23 #include <osl/diagnose.h>
24 #include <file/FStatement.hxx>
25 #include <file/FConnection.hxx>
26 #include <sqlbison.hxx>
27 #include <file/FDriver.hxx>
28 #include <file/FResultSet.hxx>
29 #include <sal/log.hxx>
30 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
31 #include <com/sun/star/sdbc/ResultSetType.hpp>
32 #include <com/sun/star/sdbc/FetchDirection.hpp>
33 #include <com/sun/star/lang/DisposedException.hpp>
34 #include <comphelper/sequence.hxx>
35 #include <cppuhelper/typeprovider.hxx>
36 #include <comphelper/types.hxx>
37 #include <connectivity/dbexception.hxx>
38 #include <strings.hrc>
39 #include <algorithm>
40 
41 namespace connectivity::file
42 {
43 
44 
45 using namespace dbtools;
46 using namespace com::sun::star::uno;
47 using namespace com::sun::star::lang;
48 using namespace com::sun::star::beans;
49 using namespace com::sun::star::sdbc;
50 using namespace com::sun::star::sdbcx;
51 using namespace com::sun::star::container;
52 
OStatement_Base(OConnection * _pConnection)53 OStatement_Base::OStatement_Base(OConnection* _pConnection )
54     :OStatement_BASE(m_aMutex)
55     ,::comphelper::OPropertyContainer(OStatement_BASE::rBHelper)
56     ,m_xDBMetaData(_pConnection->getMetaData())
57     ,m_aParser( _pConnection->getDriver()->getComponentContext() )
58     ,m_aSQLIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser )
59     ,m_pConnection(_pConnection)
60     ,m_pParseTree(nullptr)
61     ,m_nMaxFieldSize(0)
62     ,m_nMaxRows(0)
63     ,m_nQueryTimeOut(0)
64     ,m_nFetchSize(0)
65     ,m_nResultSetType(ResultSetType::FORWARD_ONLY)
66     ,m_nFetchDirection(FetchDirection::FORWARD)
67     ,m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE)
68     ,m_bEscapeProcessing(true)
69 {
70     sal_Int32 nAttrib = 0;
71 
72     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),      PROPERTY_ID_CURSORNAME,         nAttrib,&m_aCursorName,     ::cppu::UnoType<OUString>::get());
73     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),    PROPERTY_ID_MAXFIELDSIZE,       nAttrib,&m_nMaxFieldSize,       ::cppu::UnoType<sal_Int32>::get());
74     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),         PROPERTY_ID_MAXROWS,            nAttrib,&m_nMaxRows,        ::cppu::UnoType<sal_Int32>::get());
75     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),    PROPERTY_ID_QUERYTIMEOUT,       nAttrib,&m_nQueryTimeOut,   ::cppu::UnoType<sal_Int32>::get());
76     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),       PROPERTY_ID_FETCHSIZE,          nAttrib,&m_nFetchSize,      ::cppu::UnoType<sal_Int32>::get());
77     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),   PROPERTY_ID_RESULTSETTYPE,      nAttrib,&m_nResultSetType,  ::cppu::UnoType<sal_Int32>::get());
78     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),  PROPERTY_ID_FETCHDIRECTION,     nAttrib,&m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
79     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),PROPERTY_ID_ESCAPEPROCESSING,   nAttrib,&m_bEscapeProcessing,cppu::UnoType<bool>::get());
80 
81     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),        PROPERTY_ID_RESULTSETCONCURRENCY,   nAttrib,&m_nResultSetConcurrency,       ::cppu::UnoType<sal_Int32>::get());
82 }
83 
~OStatement_Base()84 OStatement_Base::~OStatement_Base()
85 {
86     osl_atomic_increment( &m_refCount );
87     disposing();
88 }
89 
disposeResultSet()90 void OStatement_Base::disposeResultSet()
91 {
92     SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::disposeResultSet" );
93     // free the cursor if alive
94     Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
95     assert(xComp.is() || !m_xResultSet.get().is());
96     if (xComp.is())
97         xComp->dispose();
98     m_xResultSet.clear();
99 }
100 
disposing()101 void OStatement_BASE2::disposing()
102 {
103     ::osl::MutexGuard aGuard(m_aMutex);
104 
105     disposeResultSet();
106 
107     if(m_pSQLAnalyzer)
108         m_pSQLAnalyzer->dispose();
109 
110     if(m_aRow.is())
111     {
112         m_aRow->clear();
113         m_aRow = nullptr;
114     }
115 
116     m_aSQLIterator.dispose();
117 
118     m_pTable.clear();
119 
120     m_pConnection.clear();
121 
122     if ( m_pParseTree )
123     {
124         delete m_pParseTree;
125         m_pParseTree = nullptr;
126     }
127 
128     OStatement_Base::disposing();
129 }
130 
acquire()131 void SAL_CALL OStatement_Base::acquire() noexcept
132 {
133     OStatement_BASE::acquire();
134 }
135 
release()136 void SAL_CALL OStatement_BASE2::release() noexcept
137 {
138     OStatement_BASE::release();
139 }
140 
queryInterface(const Type & rType)141 Any SAL_CALL OStatement_Base::queryInterface( const Type & rType )
142 {
143     const Any aRet = OStatement_BASE::queryInterface(rType);
144     return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
145 }
146 
getTypes()147 Sequence< Type > SAL_CALL OStatement_Base::getTypes(  )
148 {
149     ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
150                                     cppu::UnoType<css::beans::XFastPropertySet>::get(),
151                                     cppu::UnoType<css::beans::XPropertySet>::get());
152 
153     return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE::getTypes());
154 }
155 
156 
cancel()157 void SAL_CALL OStatement_Base::cancel(  )
158 {
159 }
160 
close()161 void SAL_CALL OStatement_Base::close()
162 {
163     {
164         ::osl::MutexGuard aGuard( m_aMutex );
165         checkDisposed(OStatement_BASE::rBHelper.bDisposed);
166     }
167     dispose();
168 }
169 
closeResultSet()170 void OStatement_Base::closeResultSet()
171 {
172     SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::clearMyResultSet " );
173     ::osl::MutexGuard aGuard( m_aMutex );
174     checkDisposed(OStatement_BASE::rBHelper.bDisposed);
175 
176     Reference< XCloseable > xCloseable(m_xResultSet.get(), UNO_QUERY);
177     assert(xCloseable.is() || !m_xResultSet.get().is());
178     if (xCloseable.is())
179     {
180         try
181         {
182             xCloseable->close();
183         }
184         catch( const DisposedException& ) { }
185     }
186 
187     m_xResultSet.clear();
188 }
189 
getWarnings()190 Any SAL_CALL OStatement_Base::getWarnings(  )
191 {
192     ::osl::MutexGuard aGuard( m_aMutex );
193     checkDisposed(OStatement_BASE::rBHelper.bDisposed);
194 
195     return makeAny(m_aLastWarning);
196 }
197 
clearWarnings()198 void SAL_CALL OStatement_Base::clearWarnings(  )
199 {
200     ::osl::MutexGuard aGuard( m_aMutex );
201     checkDisposed(OStatement_BASE::rBHelper.bDisposed);
202 
203     m_aLastWarning = SQLWarning();
204 }
205 
createArrayHelper() const206 ::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const
207 {
208     Sequence< Property > aProps;
209     describeProperties(aProps);
210     return new ::cppu::OPropertyArrayHelper(aProps);
211 }
212 
213 
getInfoHelper()214 ::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper()
215 {
216     return *getArrayHelper();
217 }
218 
createResultSet()219 rtl::Reference<OResultSet> OStatement::createResultSet()
220 {
221     return new OResultSet(this,m_aSQLIterator);
222 }
223 
224 IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbc.driver.file.Statement","com.sun.star.sdbc.Statement");
225 
acquire()226 void SAL_CALL OStatement::acquire() noexcept
227 {
228     OStatement_BASE2::acquire();
229 }
230 
release()231 void SAL_CALL OStatement::release() noexcept
232 {
233     OStatement_BASE2::release();
234 }
235 
236 
execute(const OUString & sql)237 sal_Bool SAL_CALL OStatement::execute( const OUString& sql )
238 {
239     ::osl::MutexGuard aGuard( m_aMutex );
240 
241     executeQuery(sql);
242 
243     return m_aSQLIterator.getStatementType() == OSQLStatementType::Select;
244 }
245 
246 
executeQuery(const OUString & sql)247 Reference< XResultSet > SAL_CALL OStatement::executeQuery( const OUString& sql )
248 {
249     ::osl::MutexGuard aGuard( m_aMutex );
250     checkDisposed(OStatement_BASE::rBHelper.bDisposed);
251 
252     construct(sql);
253     Reference< XResultSet > xRS;
254     rtl::Reference<OResultSet> pResult = createResultSet();
255     xRS = pResult;
256     initializeResultSet(pResult.get());
257     m_xResultSet = xRS;
258 
259     pResult->OpenImpl();
260 
261     return xRS;
262 }
263 
getConnection()264 Reference< XConnection > SAL_CALL OStatement::getConnection(  )
265 {
266     return m_pConnection;
267 }
268 
executeUpdate(const OUString & sql)269 sal_Int32 SAL_CALL OStatement::executeUpdate( const OUString& sql )
270 {
271     ::osl::MutexGuard aGuard( m_aMutex );
272     checkDisposed(OStatement_BASE::rBHelper.bDisposed);
273 
274 
275     construct(sql);
276     rtl::Reference<OResultSet> pResult = createResultSet();
277     initializeResultSet(pResult.get());
278     pResult->OpenImpl();
279 
280     return pResult->getRowCountResult();
281 }
282 
283 
disposing()284 void SAL_CALL OStatement_Base::disposing()
285 {
286     if(m_aEvaluateRow.is())
287     {
288         m_aEvaluateRow->clear();
289         m_aEvaluateRow = nullptr;
290     }
291     OStatement_BASE::disposing();
292 }
293 
getPropertySetInfo()294 Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo(  )
295 {
296     return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
297 }
298 
queryInterface(const Type & rType)299 Any SAL_CALL OStatement::queryInterface( const Type & rType )
300 {
301     Any aRet = OStatement_XStatement::queryInterface( rType);
302     return aRet.hasValue() ? aRet : OStatement_BASE2::queryInterface( rType);
303 }
304 
analyzeSQL()305 void OStatement_Base::analyzeSQL()
306 {
307     OSL_ENSURE(m_pSQLAnalyzer,"OResultSet::analyzeSQL: Analyzer isn't set!");
308     // start analysing the statement
309     m_pSQLAnalyzer->setOrigColumns(m_xColNames);
310     m_pSQLAnalyzer->start(m_pParseTree);
311 
312     const OSQLParseNode* pOrderbyClause = m_aSQLIterator.getOrderTree();
313     if(!pOrderbyClause)
314         return;
315 
316     OSQLParseNode * pOrderingSpecCommalist = pOrderbyClause->getChild(2);
317     OSL_ENSURE(SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OResultSet: Error in Parse Tree");
318 
319     for (size_t m = 0; m < pOrderingSpecCommalist->count(); m++)
320     {
321         OSQLParseNode * pOrderingSpec = pOrderingSpecCommalist->getChild(m);
322         OSL_ENSURE(SQL_ISRULE(pOrderingSpec,ordering_spec),"OResultSet: Error in Parse Tree");
323         OSL_ENSURE(pOrderingSpec->count() == 2,"OResultSet: Error in Parse Tree");
324 
325         OSQLParseNode * pColumnRef = pOrderingSpec->getChild(0);
326         if(!SQL_ISRULE(pColumnRef,column_ref))
327         {
328             throw SQLException();
329         }
330         OSQLParseNode * pAscendingDescending = pOrderingSpec->getChild(1);
331         setOrderbyColumn(pColumnRef,pAscendingDescending);
332     }
333 }
334 
setOrderbyColumn(OSQLParseNode const * pColumnRef,OSQLParseNode const * pAscendingDescending)335 void OStatement_Base::setOrderbyColumn( OSQLParseNode const * pColumnRef,
336                                         OSQLParseNode const * pAscendingDescending)
337 {
338     OUString aColumnName;
339     if (pColumnRef->count() == 1)
340         aColumnName = pColumnRef->getChild(0)->getTokenValue();
341     else if (pColumnRef->count() == 3)
342     {
343         pColumnRef->getChild(2)->parseNodeToStr( aColumnName, getOwnConnection(), nullptr, false, false );
344     }
345     else
346     {
347         throw SQLException();
348     }
349 
350     Reference<XColumnLocate> xColLocate(m_xColNames,UNO_QUERY);
351     if(!xColLocate.is())
352         return;
353     // Everything tested and we have the name of the Column.
354     // What number is the Column?
355     ::rtl::Reference<OSQLColumns> aSelectColumns = m_aSQLIterator.getSelectColumns();
356     ::comphelper::UStringMixEqual aCase;
357     OSQLColumns::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),aColumnName,aCase);
358     if ( aFind == aSelectColumns->end() )
359         throw SQLException();
360     m_aOrderbyColumnNumber.push_back((aFind - aSelectColumns->begin()) + 1);
361 
362     // Ascending or Descending?
363     m_aOrderbyAscending.push_back(SQL_ISTOKEN(pAscendingDescending,DESC) ? TAscendingOrder::DESC : TAscendingOrder::ASC);
364 }
365 
construct(const OUString & sql)366 void OStatement_Base::construct(const OUString& sql)
367 {
368     OUString aErr;
369     m_pParseTree = m_aParser.parseTree(aErr,sql).release();
370     if(!m_pParseTree)
371         throw SQLException(aErr,*this,OUString(),0,Any());
372 
373     m_aSQLIterator.setParseTree(m_pParseTree);
374     m_aSQLIterator.traverseAll();
375     const OSQLTables& rTabs = m_aSQLIterator.getTables();
376 
377     // sanity checks
378     if ( rTabs.empty() )
379         // no tables -> nothing to operate on -> error
380         m_pConnection->throwGenericSQLException(STR_QUERY_NO_TABLE,*this);
381 
382     if ( rTabs.size() > 1 || m_aSQLIterator.hasErrors() )
383         // more than one table -> can't operate on them -> error
384         m_pConnection->throwGenericSQLException(STR_QUERY_MORE_TABLES,*this);
385 
386     if ( (m_aSQLIterator.getStatementType() == OSQLStatementType::Select) && m_aSQLIterator.getSelectColumns()->empty() )
387         // SELECT statement without columns -> error
388         m_pConnection->throwGenericSQLException(STR_QUERY_NO_COLUMN,*this);
389 
390     switch(m_aSQLIterator.getStatementType())
391     {
392         case OSQLStatementType::CreateTable:
393         case OSQLStatementType::OdbcCall:
394         case OSQLStatementType::Unknown:
395             m_pConnection->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,*this);
396             break;
397         case OSQLStatementType::Select:
398             if(SQL_ISRULE(m_aSQLIterator.getParseTree(), union_statement))
399             {
400                 m_pConnection->throwGenericSQLException(STR_QUERY_TOO_COMPLEX, *this);
401             }
402             assert(SQL_ISRULE(m_aSQLIterator.getParseTree(), select_statement));
403             break;
404         default:
405             break;
406     }
407 
408     // at this moment we support only one table per select statement
409     Reference< css::lang::XUnoTunnel> xTunnel(rTabs.begin()->second,UNO_QUERY);
410     if(xTunnel.is())
411     {
412         m_pTable = reinterpret_cast<OFileTable*>(xTunnel->getSomething(OFileTable::getUnoTunnelId()));
413     }
414     OSL_ENSURE(m_pTable.is(),"No table!");
415     if ( m_pTable.is() )
416         m_xColNames     = m_pTable->getColumns();
417     Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
418     // set the binding of the resultrow
419     m_aRow          = new OValueRefVector(xNames->getCount());
420     (*m_aRow)[0]->setBound(true);
421     std::for_each(m_aRow->begin()+1,m_aRow->end(),TSetRefBound(false));
422 
423     // set the binding of the resultrow
424     m_aEvaluateRow  = new OValueRefVector(xNames->getCount());
425 
426     (*m_aEvaluateRow)[0]->setBound(true);
427     std::for_each(m_aEvaluateRow->begin()+1,m_aEvaluateRow->end(),TSetRefBound(false));
428 
429     // set the select row
430     m_aSelectRow = new OValueRefVector(m_aSQLIterator.getSelectColumns()->size());
431     std::for_each(m_aSelectRow->begin(),m_aSelectRow->end(),TSetRefBound(true));
432 
433     // create the column mapping
434     createColumnMapping();
435 
436     m_pSQLAnalyzer.reset( new OSQLAnalyzer(m_pConnection.get()) );
437 
438     analyzeSQL();
439 }
440 
createColumnMapping()441 void OStatement_Base::createColumnMapping()
442 {
443     // initialize the column index map (mapping select columns to table columns)
444     ::rtl::Reference<connectivity::OSQLColumns> xColumns = m_aSQLIterator.getSelectColumns();
445     m_aColMapping.resize(xColumns->size() + 1);
446     for (sal_Int32 i=0; i<static_cast<sal_Int32>(m_aColMapping.size()); ++i)
447         m_aColMapping[i] = i;
448 
449     Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
450     // now check which columns are bound
451     OResultSet::setBoundedColumns(m_aRow,m_aSelectRow,xColumns,xNames,true,m_xDBMetaData,m_aColMapping);
452 }
453 
initializeResultSet(OResultSet * _pResult)454 void OStatement_Base::initializeResultSet(OResultSet* _pResult)
455 {
456     GetAssignValues();
457 
458     _pResult->setSqlAnalyzer(m_pSQLAnalyzer.get());
459     _pResult->setOrderByColumns(m_aOrderbyColumnNumber);
460     _pResult->setOrderByAscending(m_aOrderbyAscending);
461     _pResult->setBindingRow(m_aRow);
462     _pResult->setColumnMapping(m_aColMapping);
463     _pResult->setEvaluationRow(m_aEvaluateRow);
464     _pResult->setAssignValues(m_aAssignValues);
465     _pResult->setSelectRow(m_aSelectRow);
466 
467     m_pSQLAnalyzer->bindSelectRow(m_aRow);
468     m_pSQLAnalyzer->bindEvaluationRow(m_aEvaluateRow);    // Set values in the code of the Compiler
469 }
470 
GetAssignValues()471 void OStatement_Base::GetAssignValues()
472 {
473     if (m_pParseTree == nullptr)
474     {
475         ::dbtools::throwFunctionSequenceException(*this);
476         return;
477     }
478 
479     if (SQL_ISRULE(m_pParseTree,select_statement))
480         // no values have to be set for SELECT
481         return;
482     else if (SQL_ISRULE(m_pParseTree,insert_statement))
483     {
484         // Create Row for the values to be set (Reference through new)
485         if(m_aAssignValues.is())
486             m_aAssignValues->clear();
487         sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount();
488         m_aAssignValues = new OAssignValues(nCount);
489         // unbound all
490         std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false));
491 
492         m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER);
493 
494         // List of Column-Names, that exist in the column_commalist (separated by ;):
495         std::vector<OUString> aColumnNameList;
496 
497         OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree");
498 
499         OSQLParseNode * pOptColumnCommalist = m_pParseTree->getChild(3);
500         OSL_ENSURE(pOptColumnCommalist != nullptr,"OResultSet: Error in Parse Tree");
501         OSL_ENSURE(SQL_ISRULE(pOptColumnCommalist,opt_column_commalist),"OResultSet: Error in Parse Tree");
502         if (pOptColumnCommalist->count() == 0)
503         {
504             const Sequence< OUString>& aNames = m_xColNames->getElementNames();
505             const OUString* pBegin = aNames.getConstArray();
506             const OUString* pEnd = pBegin + aNames.getLength();
507             for (; pBegin != pEnd; ++pBegin)
508                 aColumnNameList.push_back(*pBegin);
509         }
510         else
511         {
512             OSL_ENSURE(pOptColumnCommalist->count() == 3,"OResultSet: Error in Parse Tree");
513 
514             OSQLParseNode * pColumnCommalist = pOptColumnCommalist->getChild(1);
515             OSL_ENSURE(pColumnCommalist != nullptr,"OResultSet: Error in Parse Tree");
516             OSL_ENSURE(SQL_ISRULE(pColumnCommalist,column_commalist),"OResultSet: Error in Parse Tree");
517             OSL_ENSURE(pColumnCommalist->count() > 0,"OResultSet: Error in Parse Tree");
518 
519             // All Columns in the column_commalist ...
520             for (size_t i = 0; i < pColumnCommalist->count(); i++)
521             {
522                 OSQLParseNode * pCol = pColumnCommalist->getChild(i);
523                 OSL_ENSURE(pCol != nullptr,"OResultSet: Error in Parse Tree");
524                 aColumnNameList.push_back(pCol->getTokenValue());
525             }
526         }
527         if ( aColumnNameList.empty() )
528             throwFunctionSequenceException(*this);
529 
530         // Values ...
531         OSQLParseNode * pValuesOrQuerySpec = m_pParseTree->getChild(4);
532         OSL_ENSURE(pValuesOrQuerySpec != nullptr,"OResultSet: pValuesOrQuerySpec must not be NULL!");
533         OSL_ENSURE(SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec),"OResultSet: ! SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec)");
534         OSL_ENSURE(pValuesOrQuerySpec->count() > 0,"OResultSet: pValuesOrQuerySpec->count() <= 0");
535 
536         // just "VALUES" is allowed ...
537         if (! SQL_ISTOKEN(pValuesOrQuerySpec->getChild(0),VALUES))
538             throwFunctionSequenceException(*this);
539 
540         OSL_ENSURE(pValuesOrQuerySpec->count() == 4,"OResultSet: pValuesOrQuerySpec->count() != 4");
541 
542         // List of values
543         OSQLParseNode * pInsertAtomCommalist = pValuesOrQuerySpec->getChild(2);
544         OSL_ENSURE(pInsertAtomCommalist != nullptr,"OResultSet: pInsertAtomCommalist must not be NULL!");
545         OSL_ENSURE(pInsertAtomCommalist->count() > 0,"OResultSet: pInsertAtomCommalist <= 0");
546 
547         sal_Int32 nIndex=0;
548         for (size_t i = 0; i < pInsertAtomCommalist->count(); i++)
549         {
550             OSQLParseNode * pRow_Value_Const = pInsertAtomCommalist->getChild(i); // row_value_constructor
551             OSL_ENSURE(pRow_Value_Const != nullptr,"OResultSet: pRow_Value_Const must not be NULL!");
552             if(SQL_ISRULE(pRow_Value_Const,parameter))
553             {
554                 ParseAssignValues(aColumnNameList,pRow_Value_Const,nIndex++); // only one Columnname allowed per loop
555             }
556             else if(pRow_Value_Const->isToken())
557                 ParseAssignValues(aColumnNameList,pRow_Value_Const,i);
558             else
559             {
560                 if(pRow_Value_Const->count() == aColumnNameList.size())
561                 {
562                     for (size_t j = 0; j < pRow_Value_Const->count(); ++j)
563                         ParseAssignValues(aColumnNameList,pRow_Value_Const->getChild(j),nIndex++);
564                 }
565                 else
566                     throwFunctionSequenceException(*this);
567             }
568         }
569     }
570     else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
571     {
572         if(m_aAssignValues.is())
573             m_aAssignValues->clear();
574         sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount();
575         m_aAssignValues = new OAssignValues(nCount);
576         // unbound all
577         std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false));
578 
579         m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER);
580 
581         OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree");
582 
583         OSQLParseNode * pAssignmentCommalist = m_pParseTree->getChild(3);
584         OSL_ENSURE(pAssignmentCommalist != nullptr,"OResultSet: pAssignmentCommalist == NULL");
585         OSL_ENSURE(SQL_ISRULE(pAssignmentCommalist,assignment_commalist),"OResultSet: Error in Parse Tree");
586         OSL_ENSURE(pAssignmentCommalist->count() > 0,"OResultSet: pAssignmentCommalist->count() <= 0");
587 
588         // work on all assignments (commalist) ...
589         std::vector< OUString> aList(1);
590         for (size_t i = 0; i < pAssignmentCommalist->count(); i++)
591         {
592             OSQLParseNode * pAssignment = pAssignmentCommalist->getChild(i);
593             OSL_ENSURE(pAssignment != nullptr,"OResultSet: pAssignment == NULL");
594             OSL_ENSURE(SQL_ISRULE(pAssignment,assignment),"OResultSet: Error in Parse Tree");
595             OSL_ENSURE(pAssignment->count() == 3,"OResultSet: pAssignment->count() != 3");
596 
597             OSQLParseNode * pCol = pAssignment->getChild(0);
598             OSL_ENSURE(pCol != nullptr,"OResultSet: pCol == NULL");
599 
600             OSQLParseNode * pComp = pAssignment->getChild(1);
601             OSL_ENSURE(pComp != nullptr,"OResultSet: pComp == NULL");
602             OSL_ENSURE(pComp->getNodeType() == SQLNodeType::Equal,"OResultSet: pComp->getNodeType() != SQLNodeType::Comparison");
603             if (pComp->getTokenValue().toChar() != '=')
604             {
605                 throwFunctionSequenceException(*this);
606             }
607 
608             OSQLParseNode * pVal = pAssignment->getChild(2);
609             OSL_ENSURE(pVal != nullptr,"OResultSet: pVal == NULL");
610             aList[0] = pCol->getTokenValue();
611             ParseAssignValues(aList,pVal,0);
612         }
613 
614     }
615 }
616 
ParseAssignValues(const std::vector<OUString> & aColumnNameList,OSQLParseNode * pRow_Value_Constructor_Elem,sal_Int32 nIndex)617 void OStatement_Base::ParseAssignValues(const std::vector< OUString>& aColumnNameList,OSQLParseNode* pRow_Value_Constructor_Elem, sal_Int32 nIndex)
618 {
619     OSL_ENSURE(o3tl::make_unsigned(nIndex) <= aColumnNameList.size(),"SdbFileCursor::ParseAssignValues: nIndex > aColumnNameList.GetTokenCount()");
620     OUString aColumnName(aColumnNameList[nIndex]);
621     OSL_ENSURE(aColumnName.getLength() > 0,"OResultSet: Column-Name not found");
622     OSL_ENSURE(pRow_Value_Constructor_Elem != nullptr,"OResultSet: pRow_Value_Constructor_Elem must not be NULL!");
623 
624     if (pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::String ||
625         pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::IntNum ||
626         pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::ApproxNum)
627     {
628         // set value:
629         SetAssignValue(aColumnName, pRow_Value_Constructor_Elem->getTokenValue());
630     }
631     else if (SQL_ISTOKEN(pRow_Value_Constructor_Elem,NULL))
632     {
633         // set NULL
634         SetAssignValue(aColumnName, OUString(), true);
635     }
636     else if (SQL_ISRULE(pRow_Value_Constructor_Elem,parameter))
637         parseParamterElem(aColumnName,pRow_Value_Constructor_Elem);
638     else
639     {
640         throwFunctionSequenceException(*this);
641     }
642 }
643 
SetAssignValue(const OUString & aColumnName,const OUString & aValue,bool bSetNull,sal_uInt32 nParameter)644 void OStatement_Base::SetAssignValue(const OUString& aColumnName,
645                                      const OUString& aValue,
646                                      bool bSetNull,
647                                      sal_uInt32 nParameter)
648 {
649     Reference<XPropertySet> xCol;
650     m_xColNames->getByName(aColumnName) >>= xCol;
651     sal_Int32 nId = Reference<XColumnLocate>(m_xColNames,UNO_QUERY_THROW)->findColumn(aColumnName);
652     // does this column actually exist in the file?
653 
654     if (!xCol.is())
655     {
656         // This Column doesn't exist!
657         throwFunctionSequenceException(*this);
658     }
659 
660 
661     // Everything tested and we have the names of the Column.
662     // Now allocate one Value, set the value and tie the value to the Row.
663     if (bSetNull)
664         (*m_aAssignValues)[nId]->setNull();
665     else
666     {
667         switch (::comphelper::getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))))
668         {
669             // put criteria depending on the Type as String or double in the variable
670         case DataType::CHAR:
671         case DataType::VARCHAR:
672         case DataType::LONGVARCHAR:
673             *(*m_aAssignValues)[nId] = ORowSetValue(aValue);
674             //Characterset is already converted, since the entire statement was converted
675             break;
676 
677         case DataType::BIT:
678             if (aValue.equalsIgnoreAsciiCase("TRUE")  || aValue[0] == '1')
679                 *(*m_aAssignValues)[nId] = true;
680             else if (aValue.equalsIgnoreAsciiCase("FALSE") || aValue[0] == '0')
681                 *(*m_aAssignValues)[nId] = false;
682             else
683                 throwFunctionSequenceException(*this);
684             break;
685         case DataType::TINYINT:
686         case DataType::SMALLINT:
687         case DataType::INTEGER:
688         case DataType::DECIMAL:
689         case DataType::NUMERIC:
690         case DataType::REAL:
691         case DataType::DOUBLE:
692         case DataType::DATE:
693         case DataType::TIME:
694         case DataType::TIMESTAMP:
695             *(*m_aAssignValues)[nId] = ORowSetValue(aValue);
696             break;
697         default:
698             throwFunctionSequenceException(*this);
699         }
700     }
701 
702     // save Parameter-No. (as User Data)
703     // SQL_NO_PARAMETER = no Parameter.
704     m_aAssignValues->setParameterIndex(nId,nParameter);
705     if(nParameter != SQL_NO_PARAMETER)
706         m_aParameterIndexes[nParameter] = nId;
707 }
708 
parseParamterElem(const OUString &,OSQLParseNode *)709 void OStatement_Base::parseParamterElem(const OUString& /*_sColumnName*/,OSQLParseNode* /*pRow_Value_Constructor_Elem*/)
710 {
711     // do nothing here
712 }
713 
714 }// namespace
715 
716 
717 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
718