1//
2// StatementImpl.cpp
3//
4// Library: Data
5// Package: DataCore
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/Data/StatementImpl.h"
16#include "Poco/Data/SessionImpl.h"
17#include "Poco/Data/DataException.h"
18#include "Poco/Data/AbstractBinder.h"
19#include "Poco/Data/Extraction.h"
20#include "Poco/Data/LOB.h"
21#include "Poco/Data/Date.h"
22#include "Poco/Data/Time.h"
23#include "Poco/SharedPtr.h"
24#include "Poco/DateTime.h"
25#include "Poco/Exception.h"
26#include "Poco/Data/DataException.h"
27
28
29using Poco::icompare;
30
31
32namespace Poco {
33namespace Data {
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 (!extractions().size() && !isStoredProcedure())
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::Data::AbstractExtractionVec::iterator it = extractions().begin();
262 Poco::Data::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::Data::AbstractExtractionVec::iterator it = extractions().begin();
292 Poco::Data::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
315void StatementImpl::makeExtractors(std::size_t count)
316{
317 // type cast is needed when size_t is 64 bit
318 makeExtractors(count, static_cast<Position::Type>(currentDataSet()));
319}
320
321void StatementImpl::makeExtractors(std::size_t count, const Position& position)
322{
323 for (int i = 0; i < count; ++i)
324 {
325 const MetaColumn& mc = metaColumn(i, position.value());
326 switch (mc.type())
327 {
328 case MetaColumn::FDT_BOOL:
329 addInternalExtract<bool>(mc, position.value()); break;
330 case MetaColumn::FDT_INT8:
331 addInternalExtract<Int8>(mc, position.value()); break;
332 case MetaColumn::FDT_UINT8:
333 addInternalExtract<UInt8>(mc, position.value()); break;
334 case MetaColumn::FDT_INT16:
335 addInternalExtract<Int16>(mc, position.value()); break;
336 case MetaColumn::FDT_UINT16:
337 addInternalExtract<UInt16>(mc, position.value()); break;
338 case MetaColumn::FDT_INT32:
339 addInternalExtract<Int32>(mc, position.value()); break;
340 case MetaColumn::FDT_UINT32:
341 addInternalExtract<UInt32>(mc, position.value()); break;
342 case MetaColumn::FDT_INT64:
343 addInternalExtract<Int64>(mc, position.value()); break;
344 case MetaColumn::FDT_UINT64:
345 addInternalExtract<UInt64>(mc, position.value()); break;
346 case MetaColumn::FDT_FLOAT:
347 addInternalExtract<float>(mc, position.value()); break;
348 case MetaColumn::FDT_DOUBLE:
349 addInternalExtract<double>(mc, position.value()); break;
350 case MetaColumn::FDT_STRING:
351 addInternalExtract<std::string>(mc, position.value()); break;
352 case MetaColumn::FDT_WSTRING:
353 addInternalExtract<Poco::UTF16String>(mc, position.value()); break;
354 case MetaColumn::FDT_BLOB:
355 addInternalExtract<BLOB>(mc, position.value()); break;
356 case MetaColumn::FDT_CLOB:
357 addInternalExtract<CLOB>(mc, position.value()); break;
358 case MetaColumn::FDT_DATE:
359 addInternalExtract<Date>(mc, position.value()); break;
360 case MetaColumn::FDT_TIME:
361 addInternalExtract<Time>(mc, position.value()); break;
362 case MetaColumn::FDT_TIMESTAMP:
363 addInternalExtract<DateTime>(mc, position.value()); break;
364 default:
365 throw Poco::InvalidArgumentException("Data type not supported.");
366 }
367 }
368}
369
370
371const MetaColumn& StatementImpl::metaColumn(const std::string& name) const
372{
373 std::size_t cols = columnsReturned();
374 for (std::size_t i = 0; i < cols; ++i)
375 {
376 const MetaColumn& column = metaColumn(i, currentDataSet());
377 if (0 == icompare(column.name(), name)) return column;
378 }
379
380 throw NotFoundException(format("Invalid column name: %s", name));
381}
382
383
384std::size_t StatementImpl::activateNextDataSet()
385{
386 if (_curDataSet + 1 < dataSetCount()) return ++_curDataSet;
387 else
388 throw NoDataException("End of data sets reached.");
389}
390
391
392std::size_t StatementImpl::activatePreviousDataSet()
393{
394 if (_curDataSet > 0) return --_curDataSet;
395 else
396 throw NoDataException("Beginning of data sets reached.");
397}
398
399
400void StatementImpl::addExtract(AbstractExtraction::Ptr pExtraction)
401{
402 poco_check_ptr (pExtraction);
403 std::size_t pos = pExtraction->position();
404 if (pos >= _extractors.size())
405 _extractors.resize(pos + 1);
406
407 pExtraction->setEmptyStringIsNull(
408 _rSession.getFeature("emptyStringIsNull"));
409
410 pExtraction->setForceEmptyString(
411 _rSession.getFeature("forceEmptyString"));
412
413 _extractors[pos].push_back(pExtraction);
414}
415
416
417void StatementImpl::removeBind(const std::string& name)
418{
419 bool found = false;
420
421 AbstractBindingVec::iterator it = _bindings.begin();
422 for (; it != _bindings.end();)
423 {
424 if ((*it)->name() == name)
425 {
426 it = _bindings.erase(it);
427 found = true;
428 }
429 else ++it;
430 }
431
432 if (!found)
433 throw NotFoundException(name);
434}
435
436
437std::size_t StatementImpl::columnsExtracted(int dataSet) const
438{
439 if (USE_CURRENT_DATA_SET == dataSet) dataSet = static_cast<int>(_curDataSet);
440 if (_columnsExtracted.size() > 0)
441 {
442 poco_assert (dataSet >= 0 && dataSet < _columnsExtracted.size());
443 return _columnsExtracted[dataSet];
444 }
445
446 return 0;
447}
448
449
450std::size_t StatementImpl::rowsExtracted(int dataSet) const
451{
452 if (USE_CURRENT_DATA_SET == dataSet) dataSet = static_cast<int>(_curDataSet);
453 if (extractions().size() > 0)
454 {
455 poco_assert (dataSet >= 0 && dataSet < _extractors.size());
456 if (_extractors[dataSet].size() > 0)
457 return _extractors[dataSet][0]->numOfRowsHandled();
458 }
459
460 return 0;
461}
462
463
464std::size_t StatementImpl::subTotalRowCount(int dataSet) const
465{
466 if (USE_CURRENT_DATA_SET == dataSet) dataSet = static_cast<int>(_curDataSet);
467 if (_subTotalRowCount.size() > 0)
468 {
469 poco_assert (dataSet >= 0 && dataSet < _subTotalRowCount.size());
470 return _subTotalRowCount[dataSet];
471 }
472
473 return 0;
474}
475
476
477void StatementImpl::formatSQL(std::vector<Any>& arguments)
478{
479 std::string sql;
480 Poco::format(sql, _ostr.str(), arguments);
481 _ostr.str("");
482 _ostr << sql;
483}
484
485
486void StatementImpl::insertHint()
487{
488}
489
490} } // namespace Poco::Data
491