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