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 | |
29 | using Poco::icompare; |
30 | |
31 | |
32 | namespace Poco { |
33 | namespace Data { |
34 | |
35 | |
36 | using namespace Keywords; |
37 | |
38 | |
39 | const std::string StatementImpl::VECTOR = "vector" ; |
40 | const std::string StatementImpl::LIST = "list" ; |
41 | const std::string StatementImpl::DEQUE = "deque" ; |
42 | const std::string StatementImpl::UNKNOWN = "unknown" ; |
43 | |
44 | |
45 | const std::size_t StatementImpl::UNKNOWN_TOTAL_ROW_COUNT = std::numeric_limits<std::size_t>::max(); |
46 | |
47 | |
48 | StatementImpl::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 | |
69 | StatementImpl::~StatementImpl() |
70 | { |
71 | } |
72 | |
73 | |
74 | std::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 | |
113 | void 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 | |
133 | std::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 | |
164 | std::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 | |
186 | void 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 | |
207 | void 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 | |
225 | void StatementImpl::reset() |
226 | { |
227 | resetBinding(); |
228 | resetExtraction(); |
229 | _state = ST_RESET; |
230 | } |
231 | |
232 | |
233 | void StatementImpl::(const Limit& extrLimit) |
234 | { |
235 | if (!extrLimit.isLowerLimit()) |
236 | _extrLimit = extrLimit; |
237 | else |
238 | _lowerLimit = extrLimit.value(); |
239 | } |
240 | |
241 | |
242 | void StatementImpl::(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 | |
253 | void StatementImpl::() |
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 | |
272 | void 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 | |
281 | void 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 | |
289 | void StatementImpl::() |
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 | |
300 | void 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 | |
315 | void StatementImpl::(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 | |
321 | void StatementImpl::(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 | |
371 | const 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 | |
384 | std::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 | |
392 | std::size_t StatementImpl::activatePreviousDataSet() |
393 | { |
394 | if (_curDataSet > 0) return --_curDataSet; |
395 | else |
396 | throw NoDataException("Beginning of data sets reached." ); |
397 | } |
398 | |
399 | |
400 | void StatementImpl::(AbstractExtraction::Ptr ) |
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 | |
417 | void 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 | |
437 | std::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 | |
450 | std::size_t StatementImpl::(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 | |
464 | std::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 | |
477 | void 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 | |
486 | void StatementImpl::insertHint() |
487 | { |
488 | } |
489 | |
490 | } } // namespace Poco::Data |
491 | |