1//
2// StatementImpl.cpp
3//
4// Library: SQL
5// Package: SQLCore
6// Module: StatementImpl
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/SQL/StatementImpl.h"
16#include "Poco/SQL/SessionImpl.h"
17#include "Poco/SQL/SQLException.h"
18#include "Poco/SQL/AbstractBinder.h"
19#include "Poco/SQL/Extraction.h"
20#include "Poco/SQL/LOB.h"
21#include "Poco/SQL/Date.h"
22#include "Poco/SQL/Time.h"
23#include "Poco/SharedPtr.h"
24#include "Poco/DateTime.h"
25#include "Poco/Exception.h"
26#include "Poco/SQL/SQLException.h"
27
28
29using Poco::icompare;
30
31
32namespace Poco {
33namespace SQL {
34
35
36using namespace Keywords;
37
38
39const std::string StatementImpl::VECTOR = "vector";
40const std::string StatementImpl::LIST = "list";
41const std::string StatementImpl::DEQUE = "deque";
42const std::string StatementImpl::UNKNOWN = "unknown";
43
44
45const std::size_t StatementImpl::UNKNOWN_TOTAL_ROW_COUNT = std::numeric_limits<std::size_t>::max();
46
47
48StatementImpl::StatementImpl(SessionImpl& rSession):
49 _state(ST_INITIALIZED),
50 _extrLimit(upperLimit(Limit::LIMIT_UNLIMITED, false)),
51 _lowerLimit(0),
52 _rSession(rSession),
53 _storage(STORAGE_UNKNOWN_IMPL),
54 _ostr(),
55 _curDataSet(0),
56 _bulkBinding(BULK_UNDEFINED),
57 _bulkExtraction(BULK_UNDEFINED),
58 _totalRowCount(UNKNOWN_TOTAL_ROW_COUNT)
59{
60 if (!_rSession.isConnected())
61 throw NotConnectedException(_rSession.connectionString());
62
63 _extractors.resize(1);
64 _columnsExtracted.resize(1, 0);
65 _subTotalRowCount.resize(1, 0);
66}
67
68
69StatementImpl::~StatementImpl()
70{
71}
72
73
74std::size_t StatementImpl::execute(const bool& rReset)
75{
76 if (rReset) resetExtraction();
77
78 if (!_rSession.isConnected())
79 {
80 _state = ST_DONE;
81 throw NotConnectedException(_rSession.connectionString());
82 }
83
84 std::size_t lim = 0;
85 if (_lowerLimit > _extrLimit.value())
86 throw LimitException("Illegal Statement state. Upper limit must not be smaller than the lower limit.");
87
88 do
89 {
90 compile();
91 if (_extrLimit.value() == Limit::LIMIT_UNLIMITED)
92 {
93 lim += executeWithoutLimit();
94 assignSubTotal(true);
95 }
96 else
97 {
98 lim += executeWithLimit();
99 assignSubTotal(false);
100 }
101 } while (canCompile());
102
103 if (_extrLimit.value() == Limit::LIMIT_UNLIMITED)
104 _state = ST_DONE;
105
106 if (lim < _lowerLimit)
107 throw LimitException("Did not receive enough data.");
108
109 return lim;
110}
111
112
113void StatementImpl::assignSubTotal(bool doReset)
114{
115 if (_extractors.size() == _subTotalRowCount.size())
116 {
117 CountVec::iterator it = _subTotalRowCount.begin();
118 CountVec::iterator end = _subTotalRowCount.end();
119 for (size_t counter = 0; it != end; ++it, ++counter)
120 {
121 if (_extractors[counter].size())
122 {
123 if (doReset)
124 *it = CountVec::value_type(_extractors[counter][0]->numOfRowsHandled());
125 else
126 *it += CountVec::value_type(_extractors[counter][0]->numOfRowsHandled());
127 }
128 }
129 }
130}
131
132
133std::size_t StatementImpl::executeWithLimit()
134{
135 poco_assert (_state != ST_DONE);
136 std::size_t count = 0;
137 std::size_t limit = _extrLimit.value();
138
139 do
140 {
141 bind();
142 while (count < limit && hasNext())
143 count += next();
144 } while (count < limit && canBind());
145
146 if (!canBind() && (!hasNext() || limit == 0))
147 _state = ST_DONE;
148 else if (limit == count && _extrLimit.isHardLimit() && hasNext())
149 throw LimitException("HardLimit reached (retrieved more data than requested).");
150 else
151 _state = ST_PAUSED;
152
153 int affectedRows = affectedRowCount();
154 if (count == 0)
155 {
156 if (affectedRows > 0)
157 return affectedRows;
158 }
159
160 return count;
161}
162
163
164std::size_t StatementImpl::executeWithoutLimit()
165{
166 poco_assert (_state != ST_DONE);
167 std::size_t count = 0;
168
169 do
170 {
171 bind();
172 while (hasNext()) count += next();
173 } while (canBind());
174
175 int affectedRows = affectedRowCount();
176 if (count == 0)
177 {
178 if (affectedRows > 0)
179 return affectedRows;
180 }
181
182 return count;
183}
184
185
186void StatementImpl::compile()
187{
188 if (_state == ST_INITIALIZED ||
189 _state == ST_RESET ||
190 _state == ST_BOUND)
191 {
192 compileImpl();
193 _state = ST_COMPILED;
194
195 if (canMakeExtractors())
196 {
197 std::size_t cols = columnsReturned();
198 if (cols) makeExtractors(cols);
199 }
200
201 fixupExtraction();
202 fixupBinding();
203 }
204}
205
206
207void StatementImpl::bind()
208{
209 if (_state == ST_COMPILED)
210 {
211 bindImpl();
212 _state = ST_BOUND;
213 }
214 else if (_state == ST_BOUND)
215 {
216 if (!hasNext())
217 {
218 if (canBind()) bindImpl();
219 else _state = ST_DONE;
220 }
221 }
222}
223
224
225void StatementImpl::reset()
226{
227 resetBinding();
228 resetExtraction();
229 _state = ST_RESET;
230}
231
232
233void StatementImpl::setExtractionLimit(const Limit& extrLimit)
234{
235 if (!extrLimit.isLowerLimit())
236 _extrLimit = extrLimit;
237 else
238 _lowerLimit = extrLimit.value();
239}
240
241
242void StatementImpl::setBulkExtraction(const Bulk& b)
243{
244 Limit::SizeT limit = getExtractionLimit();
245 if (Limit::LIMIT_UNLIMITED != limit && b.size() != limit)
246 throw InvalidArgumentException("Can not set limit for statement.");
247
248 setExtractionLimit(b.limit());
249 _bulkExtraction = BULK_EXTRACTION;
250}
251
252
253void StatementImpl::fixupExtraction()
254{
255 if (_curDataSet >= _columnsExtracted.size())
256 {
257 _columnsExtracted.resize(_curDataSet + 1, 0);
258 _subTotalRowCount.resize(_curDataSet + 1, 0);
259 }
260
261 Poco::SQL::AbstractExtractionVec::iterator it = extractions().begin();
262 Poco::SQL::AbstractExtractionVec::iterator itEnd = extractions().end();
263 for (; it != itEnd; ++it)
264 {
265 (*it)->setExtractor(extractor());
266 (*it)->setLimit(_extrLimit.value()),
267 _columnsExtracted[_curDataSet] += (int)(*it)->numOfColumnsHandled();
268 }
269}
270
271
272void StatementImpl::fixupBinding()
273{
274 // no need to call binder().reset(); here will be called before each bind anyway
275 AbstractBindingVec::iterator it = bindings().begin();
276 AbstractBindingVec::iterator itEnd = bindings().end();
277 for (; it != itEnd; ++it) (*it)->setBinder(binder());
278}
279
280
281void StatementImpl::resetBinding()
282{
283 AbstractBindingVec::iterator it = bindings().begin();
284 AbstractBindingVec::iterator itEnd = bindings().end();
285 for (; it != itEnd; ++it) (*it)->reset();
286}
287
288
289void StatementImpl::resetExtraction()
290{
291 Poco::SQL::AbstractExtractionVec::iterator it = extractions().begin();
292 Poco::SQL::AbstractExtractionVec::iterator itEnd = extractions().end();
293 for (; it != itEnd; ++it) (*it)->reset();
294
295 poco_assert (_curDataSet < _columnsExtracted.size());
296 _columnsExtracted[_curDataSet] = 0;
297}
298
299
300void StatementImpl::setStorage(const std::string& storage)
301{
302 if (0 == icompare(DEQUE, storage))
303 _storage = STORAGE_DEQUE_IMPL;
304 else if (0 == icompare(VECTOR, storage))
305 _storage = STORAGE_VECTOR_IMPL;
306 else if (0 == icompare(LIST, storage))
307 _storage = STORAGE_LIST_IMPL;
308 else if (0 == icompare(UNKNOWN, storage))
309 _storage = STORAGE_UNKNOWN_IMPL;
310 else
311 throw NotFoundException();
312}
313
314
315bool StatementImpl::canMakeExtractors()
316{
317 return extractions().empty() && !isStoredProcedure();
318}
319
320
321void StatementImpl::makeExtractors(std::size_t count)
322{
323 // type cast is needed when size_t is 64 bit
324 makeExtractors(count, static_cast<Position::Type>(currentDataSet()));
325}
326
327void StatementImpl::makeExtractors(std::size_t count, const Position& position)
328{
329 for (int i = 0; i < count; ++i)
330 {
331 const MetaColumn& mc = metaColumn(i, position.value());
332 switch (mc.type())
333 {
334 case MetaColumn::FDT_BOOL:
335 addInternalExtract<bool>(mc, position.value()); break;
336 case MetaColumn::FDT_INT8:
337 addInternalExtract<Int8>(mc, position.value()); break;
338 case MetaColumn::FDT_UINT8:
339 addInternalExtract<UInt8>(mc, position.value()); break;
340 case MetaColumn::FDT_INT16:
341 addInternalExtract<Int16>(mc, position.value()); break;
342 case MetaColumn::FDT_UINT16:
343 addInternalExtract<UInt16>(mc, position.value()); break;
344 case MetaColumn::FDT_INT32:
345 addInternalExtract<Int32>(mc, position.value()); break;
346 case MetaColumn::FDT_UINT32:
347 addInternalExtract<UInt32>(mc, position.value()); break;
348 case MetaColumn::FDT_INT64:
349 addInternalExtract<Int64>(mc, position.value()); break;
350 case MetaColumn::FDT_UINT64:
351 addInternalExtract<UInt64>(mc, position.value()); break;
352 case MetaColumn::FDT_FLOAT:
353 addInternalExtract<float>(mc, position.value()); break;
354 case MetaColumn::FDT_DOUBLE:
355 addInternalExtract<double>(mc, position.value()); break;
356 case MetaColumn::FDT_STRING:
357 addInternalExtract<std::string>(mc, position.value()); break;
358 case MetaColumn::FDT_WSTRING:
359 addInternalExtract<Poco::UTF16String>(mc, position.value()); break;
360 case MetaColumn::FDT_BLOB:
361 addInternalExtract<BLOB>(mc, position.value()); break;
362 case MetaColumn::FDT_CLOB:
363 addInternalExtract<CLOB>(mc, position.value()); break;
364 case MetaColumn::FDT_DATE:
365 addInternalExtract<Date>(mc, position.value()); break;
366 case MetaColumn::FDT_TIME:
367 addInternalExtract<Time>(mc, position.value()); break;
368 case MetaColumn::FDT_TIMESTAMP:
369 addInternalExtract<DateTime>(mc, position.value()); break;
370 default:
371 throw Poco::InvalidArgumentException("Data type not supported.");
372 }
373 }
374}
375
376
377const MetaColumn& StatementImpl::metaColumn(const std::string& name) const
378{
379 std::size_t cols = columnsReturned();
380 for (std::size_t i = 0; i < cols; ++i)
381 {
382 const MetaColumn& column = metaColumn(i, currentDataSet());
383 if (0 == icompare(column.name(), name)) return column;
384 }
385
386 throw NotFoundException(format("Invalid column name: %s", name));
387}
388
389
390std::size_t StatementImpl::activateNextDataSet()
391{
392 if (_curDataSet + 1 < dataSetCount()) return ++_curDataSet;
393 else
394 throw NoSQLException("End of data sets reached.");
395}
396
397
398std::size_t StatementImpl::activatePreviousDataSet()
399{
400 if (_curDataSet > 0) return --_curDataSet;
401 else
402 throw NoSQLException("Beginning of data sets reached.");
403}
404
405
406void StatementImpl::addExtract(AbstractExtraction::Ptr pExtraction)
407{
408 poco_check_ptr (pExtraction);
409 std::size_t pos = pExtraction->position();
410 if (pos >= _extractors.size())
411 _extractors.resize(pos + 1);
412
413 pExtraction->setEmptyStringIsNull(
414 _rSession.getFeature("emptyStringIsNull"));
415
416 pExtraction->setForceEmptyString(
417 _rSession.getFeature("forceEmptyString"));
418
419 _extractors[pos].push_back(pExtraction);
420}
421
422
423void StatementImpl::removeBind(const std::string& name)
424{
425 bool found = false;
426
427 AbstractBindingVec::iterator it = _bindings.begin();
428 for (; it != _bindings.end();)
429 {
430 if ((*it)->name() == name)
431 {
432 it = _bindings.erase(it);
433 found = true;
434 }
435 else ++it;
436 }
437
438 if (!found)
439 throw NotFoundException(name);
440}
441
442
443std::size_t StatementImpl::columnsExtracted(int dataSet) const
444{
445 if (USE_CURRENT_DATA_SET == dataSet) dataSet = static_cast<int>(_curDataSet);
446 if (_columnsExtracted.size() > 0)
447 {
448 poco_assert (dataSet >= 0 && dataSet < _columnsExtracted.size());
449 return _columnsExtracted[dataSet];
450 }
451
452 return 0;
453}
454
455
456std::size_t StatementImpl::rowsExtracted(int dataSet) const
457{
458 if (USE_CURRENT_DATA_SET == dataSet) dataSet = static_cast<int>(_curDataSet);
459 if (extractions().size() > 0)
460 {
461 poco_assert (dataSet >= 0 && dataSet < _extractors.size());
462 if (_extractors[dataSet].size() > 0)
463 return _extractors[dataSet][0]->numOfRowsHandled();
464 }
465
466 return 0;
467}
468
469
470std::size_t StatementImpl::subTotalRowCount(int dataSet) const
471{
472 if (USE_CURRENT_DATA_SET == dataSet) dataSet = static_cast<int>(_curDataSet);
473 if (_subTotalRowCount.size() > 0)
474 {
475 poco_assert (dataSet >= 0 && dataSet < _subTotalRowCount.size());
476 return _subTotalRowCount[dataSet];
477 }
478
479 return 0;
480}
481
482
483void StatementImpl::formatSQL(std::vector<Any>& arguments)
484{
485 std::string sql;
486 Poco::format(sql, _ostr.str(), arguments);
487 _ostr.str("");
488 _ostr << sql;
489}
490
491
492void StatementImpl::insertHint()
493{
494}
495
496} } // namespace Poco::SQL
497