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 | |
29 | using Poco::icompare; |
30 | |
31 | |
32 | namespace Poco { |
33 | namespace SQL { |
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 (canMakeExtractors()) |
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::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 | |
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::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 | |
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 | bool StatementImpl::() |
316 | { |
317 | return extractions().empty() && !isStoredProcedure(); |
318 | } |
319 | |
320 | |
321 | void StatementImpl::(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 | |
327 | void StatementImpl::(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 | |
377 | const 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 | |
390 | std::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 | |
398 | std::size_t StatementImpl::activatePreviousDataSet() |
399 | { |
400 | if (_curDataSet > 0) return --_curDataSet; |
401 | else |
402 | throw NoSQLException("Beginning of data sets reached." ); |
403 | } |
404 | |
405 | |
406 | void StatementImpl::(AbstractExtraction::Ptr ) |
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 | |
423 | void 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 | |
443 | std::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 | |
456 | std::size_t StatementImpl::(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 | |
470 | std::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 | |
483 | void 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 | |
492 | void StatementImpl::insertHint() |
493 | { |
494 | } |
495 | |
496 | } } // namespace Poco::SQL |
497 | |