1 | // |
2 | // StatementImpl.h |
3 | // |
4 | // Library: Data |
5 | // Package: DataCore |
6 | // Module: StatementImpl |
7 | // |
8 | // Definition of the StatementImpl class. |
9 | // |
10 | // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. |
11 | // and Contributors. |
12 | // |
13 | // SPDX-License-Identifier: BSL-1.0 |
14 | // |
15 | |
16 | |
17 | #ifndef Data_StatementImpl_INCLUDED |
18 | #define Data_StatementImpl_INCLUDED |
19 | |
20 | |
21 | #include "Poco/Data/Data.h" |
22 | #include "Poco/Data/AbstractBinding.h" |
23 | #include "Poco/Data/AbstractExtraction.h" |
24 | #include "Poco/Data/Range.h" |
25 | #include "Poco/Data/Bulk.h" |
26 | #include "Poco/Data/Column.h" |
27 | #include "Poco/Data/Extraction.h" |
28 | #include "Poco/Data/BulkExtraction.h" |
29 | #include "Poco/Data/SessionImpl.h" |
30 | #include "Poco/RefCountedObject.h" |
31 | #include "Poco/String.h" |
32 | #include "Poco/Format.h" |
33 | #include "Poco/Exception.h" |
34 | #include <vector> |
35 | #include <list> |
36 | #include <deque> |
37 | #include <string> |
38 | #include <sstream> |
39 | |
40 | |
41 | namespace Poco { |
42 | namespace Data { |
43 | |
44 | |
45 | class RecordSet; |
46 | |
47 | class Data_API StatementImpl |
48 | /// StatementImpl interface that subclasses must implement to define database dependent query execution. |
49 | /// |
50 | /// StatementImpl's are noncopyable. |
51 | { |
52 | public: |
53 | typedef Poco::SharedPtr<StatementImpl> Ptr; |
54 | |
55 | enum State |
56 | { |
57 | ST_INITIALIZED, |
58 | ST_COMPILED, |
59 | ST_BOUND, |
60 | ST_PAUSED, |
61 | ST_DONE, |
62 | ST_RESET |
63 | }; |
64 | |
65 | enum Storage |
66 | { |
67 | STORAGE_DEQUE_IMPL, |
68 | STORAGE_VECTOR_IMPL, |
69 | STORAGE_LIST_IMPL, |
70 | STORAGE_UNKNOWN_IMPL |
71 | }; |
72 | |
73 | enum BulkType |
74 | { |
75 | BULK_UNDEFINED, |
76 | /// Bulk mode not defined yet. |
77 | BULK_BINDING, |
78 | /// Binding in bulk mode. |
79 | /// If extraction is present in the same statement, |
80 | /// it must also be bulk. |
81 | , |
82 | /// Extraction in bulk mode. |
83 | /// If binding is present in the same statement, |
84 | /// it must also be bulk. |
85 | BULK_FORBIDDEN |
86 | /// Bulk forbidden. |
87 | /// Happens when the statement has already been |
88 | /// configured as non-bulk. |
89 | }; |
90 | |
91 | static const std::string DEQUE; |
92 | static const std::string VECTOR; |
93 | static const std::string LIST; |
94 | static const std::string UNKNOWN; |
95 | |
96 | static const int USE_CURRENT_DATA_SET = -1; |
97 | |
98 | static const std::size_t UNKNOWN_TOTAL_ROW_COUNT; |
99 | |
100 | StatementImpl(SessionImpl& rSession); |
101 | /// Creates the StatementImpl. |
102 | |
103 | virtual ~StatementImpl(); |
104 | /// Destroys the StatementImpl. |
105 | |
106 | template <typename T> |
107 | void add(const T& t) |
108 | /// Appends SQL statement (fragments). |
109 | { |
110 | _ostr << t; |
111 | } |
112 | |
113 | void addBind(AbstractBinding::Ptr pBinding); |
114 | /// Registers the Binding with the StatementImpl. |
115 | |
116 | void removeBind(const std::string& name); |
117 | /// Unregisters all the bindings having specified name with the StatementImpl. |
118 | /// Bindings are released and, if this class was the sole owner, deleted. |
119 | |
120 | void (AbstractExtraction::Ptr ); |
121 | /// Registers objects used for extracting data with the StatementImpl. |
122 | |
123 | void (const Limit& extrLimit); |
124 | /// Changes the extractionLimit to extrLimit. |
125 | /// Per default no limit (EXTRACT_UNLIMITED) is set. |
126 | |
127 | std::string toString() const; |
128 | /// Create a string version of the SQL statement. |
129 | |
130 | std::size_t execute(const bool& reset = true); |
131 | /// Executes a statement. Returns the number of rows |
132 | /// extracted for statements returning data or number of rows |
133 | /// affected for all other statements (insert, update, delete). |
134 | /// If reset is true (default), the underlying bound storage is |
135 | /// reset and reused. In case of containers, this means they are |
136 | /// cleared and resized to accommodate the number of rows returned by |
137 | /// this execution step. When reset is false, data is appended to the |
138 | /// bound containers during multiple execute calls. |
139 | |
140 | void reset(); |
141 | /// Resets the statement, so that we can reuse all bindings and re-execute again. |
142 | |
143 | State getState() const; |
144 | /// Returns the state of the Statement. |
145 | |
146 | void setStorage(Storage storage); |
147 | /// Sets the storage type for this statement; |
148 | |
149 | void setStorage(const std::string& storage); |
150 | /// Sets the storage type for this statement; |
151 | |
152 | Storage getStorage() const; |
153 | /// Returns the storage type for this statement. |
154 | |
155 | std::size_t extractionCount() const; |
156 | /// Returns the number of extraction storage buffers associated |
157 | /// with the statement. |
158 | |
159 | std::size_t dataSetCount() const; |
160 | /// Returns the number of data sets associated with the statement. |
161 | |
162 | std::size_t currentDataSet() const; |
163 | /// Returns the current data set. |
164 | |
165 | protected: |
166 | virtual void insertHint(); |
167 | /// Hints the implementation that it is an insert statement |
168 | |
169 | virtual std::size_t columnsReturned() const = 0; |
170 | /// Returns number of columns returned by query. |
171 | |
172 | virtual int affectedRowCount() const = 0; |
173 | /// Returns the number of affected rows. |
174 | /// Used to find out the number of rows affected by insert, delete or update. |
175 | /// |
176 | /// Some back-ends may return a negative number in certain circumstances (e.g. |
177 | /// some ODBC drivers when this function is called after a select statement |
178 | /// execution). |
179 | |
180 | virtual const MetaColumn& metaColumn(std::size_t pos, size_t dataSet) const = 0; |
181 | /// Returns column meta data. |
182 | |
183 | const MetaColumn& metaColumn(const std::string& name) const; |
184 | /// Returns column meta data. |
185 | |
186 | virtual bool hasNext() = 0; |
187 | /// Returns true if a call to next() will return data. |
188 | /// |
189 | /// Note that the implementation must support |
190 | /// several consecutive calls to hasNext without data getting lost, |
191 | /// ie. hasNext(); hasNext(); next() must be equal to hasNext(); next(); |
192 | |
193 | virtual std::size_t next() = 0; |
194 | /// Retrieves the next row or set of rows from the resultset and |
195 | /// returns the number of rows retrieved. |
196 | /// |
197 | /// Will throw, if the resultset is empty. |
198 | /// Expects the statement to be compiled and bound. |
199 | |
200 | virtual bool canBind() const = 0; |
201 | /// Returns true if another bind is possible. |
202 | |
203 | virtual bool canCompile() const = 0; |
204 | /// Returns true if another compile is possible. |
205 | |
206 | virtual void compileImpl() = 0; |
207 | /// Compiles the statement, doesn't bind yet. |
208 | |
209 | virtual void bindImpl() = 0; |
210 | /// Binds parameters. |
211 | |
212 | virtual AbstractExtraction::ExtractorPtr () = 0; |
213 | /// Returns the concrete extractor used by the statement. |
214 | |
215 | const AbstractExtractionVec& extractions() const; |
216 | /// Returns the const reference to extractions vector. |
217 | |
218 | AbstractExtractionVec& extractions(); |
219 | /// Returns the reference to extractions vector. |
220 | |
221 | void (); |
222 | /// Sets the AbstractExtractor at the extractors. |
223 | |
224 | Limit::SizeT getExtractionLimit(); |
225 | /// Returns the extraction limit value. |
226 | |
227 | const Limit& extractionLimit() const; |
228 | /// Returns the extraction limit. |
229 | |
230 | std::size_t columnsExtracted(int dataSet = USE_CURRENT_DATA_SET) const; |
231 | /// Returns the number of columns that the extractors handle. |
232 | |
233 | std::size_t (int dataSet = USE_CURRENT_DATA_SET) const; |
234 | /// Returns the number of rows extracted for the data set. |
235 | /// Default value (USE_CURRENT_DATA_SET) indicates current data set (if any). |
236 | |
237 | std::size_t subTotalRowCount(int dataSet = USE_CURRENT_DATA_SET) const; |
238 | /// Returns the number of rows extracted so far for the data set. |
239 | /// Default value indicates current data set (if any). |
240 | |
241 | std::size_t totalRowCount() const; |
242 | //@ deprecated |
243 | /// Replaced with subTotalRowCount() and getTotalRowCount(). |
244 | |
245 | std::size_t getTotalRowCount() const; |
246 | /// Returns the total number of rows. |
247 | /// The number of rows reported is independent of filtering. |
248 | /// If the total row count has not been set externally |
249 | /// (either implicitly or explicitly through SQL), the value |
250 | /// returned shall only be accurate if the statement limit |
251 | /// is less than or equal to the total row count. |
252 | |
253 | void setTotalRowCount(std::size_t totalRowCount); |
254 | /// Explicitly sets the total row count. |
255 | |
256 | void (std::size_t count); |
257 | /// Determines the type of the internal extraction container and |
258 | /// calls the extraction creation function (addInternalExtract) |
259 | /// with appropriate data type and container type arguments. |
260 | /// |
261 | /// This function is only called in cases when there is data |
262 | /// returned by query, but no data storage supplied by user. |
263 | /// |
264 | /// The type of the internal container is determined in the |
265 | /// following order: |
266 | /// 1. If statement has the container type set, the type is used. |
267 | /// 2. If statement does not have the container type set, |
268 | /// session is queried for container type setting. If the |
269 | /// session container type setting is found, it is used. |
270 | /// 3. If neither session nor statement have the internal |
271 | /// container type set, std::deque is used. |
272 | /// |
273 | /// Supported internal extraction container types are: |
274 | /// - std::deque (default) |
275 | /// - std::vector |
276 | /// - std::list |
277 | |
278 | void (std::size_t count, const Position& position); |
279 | /// Create extractors for the specified dataset |
280 | |
281 | SessionImpl& session(); |
282 | /// Returns session associated with this statement. |
283 | |
284 | virtual AbstractBinding::BinderPtr binder() = 0; |
285 | /// Returns the concrete binder used by the statement. |
286 | |
287 | const AbstractBindingVec& bindings() const; |
288 | /// Returns the const reference to bindings vector. |
289 | |
290 | AbstractBindingVec& bindings(); |
291 | /// Returns the reference to bindings. |
292 | |
293 | void fixupBinding(); |
294 | /// Sets the AbstractBinder at the bindings. |
295 | |
296 | void resetBinding(); |
297 | /// Resets binding so it can be reused again. |
298 | |
299 | virtual bool isStoredProcedure() const; |
300 | /// Returns true if the statement is stored procedure. |
301 | /// Used as a help to determine whether to automatically create the |
302 | /// internal extractions when no outside extraction is supplied. |
303 | /// The reason for this function is to prevent unnecessary internal |
304 | /// extraction creation in cases (behavior exhibited by some ODBC drivers) |
305 | /// when there is data available from the stored procedure call |
306 | /// statement execution but no external extraction is supplied (as is |
307 | /// usually the case when stored procedures are called). In such cases |
308 | /// no storage is needed because output parameters serve as storage. |
309 | /// At the Data framework level, this function always returns false. |
310 | /// When connector-specific behavior is desired, it should be overriden |
311 | /// by the statement implementation. |
312 | |
313 | std::size_t activateNextDataSet(); |
314 | /// Returns the next data set index, or throws NoDataException if the last |
315 | /// data set was reached. |
316 | |
317 | std::size_t activatePreviousDataSet(); |
318 | /// Returns the previous data set index, or throws NoDataException if the last |
319 | /// data set was reached. |
320 | |
321 | void firstDataSet(); |
322 | /// Activate first data set |
323 | |
324 | bool hasMoreDataSets() const; |
325 | /// Returns true if there are data sets not activated yet. |
326 | |
327 | private: |
328 | |
329 | void compile(); |
330 | /// Compiles the statement. |
331 | |
332 | void bind(); |
333 | /// Binds the statement, if not yet bound. |
334 | |
335 | std::size_t executeWithLimit(); |
336 | /// Executes with an upper limit set. Returns the number of rows |
337 | /// extracted for statements returning data or number of rows |
338 | /// affected for all other statements (insert, update, delete). |
339 | |
340 | std::size_t executeWithoutLimit(); |
341 | /// Executes without an upper limit set. Returns the number of rows |
342 | /// extracted for statements returning data or number of rows |
343 | /// affected for all other statements (insert, update, delete). |
344 | |
345 | void (); |
346 | /// Resets extraction so it can be reused again. |
347 | |
348 | template <class C> |
349 | SharedPtr<InternalExtraction<C> > createExtract(const MetaColumn& mc, size_t position) |
350 | { |
351 | C* pData = new C; |
352 | Column<C>* pCol = new Column<C>(mc, pData); |
353 | return new InternalExtraction<C>(*pData, pCol, Poco::UInt32(position)); |
354 | } |
355 | |
356 | template <class C> |
357 | SharedPtr<InternalBulkExtraction<C> > createBulkExtract(const MetaColumn& mc, size_t position) |
358 | { |
359 | C* pData = new C; |
360 | Column<C>* pCol = new Column<C>(mc, pData); |
361 | return new InternalBulkExtraction<C>(*pData, |
362 | pCol, |
363 | static_cast<Poco::UInt32>(getExtractionLimit()), |
364 | Position(static_cast<Poco::UInt32>(position))); |
365 | } |
366 | |
367 | template <class T> |
368 | void addInternalExtract(const MetaColumn& mc, size_t position) |
369 | /// Creates and adds the internal extraction. |
370 | /// |
371 | /// The decision about internal extraction container is done |
372 | /// in a following way: |
373 | /// |
374 | /// If this statement has _storage member set, that setting |
375 | /// overrides the session setting for storage, otherwise the |
376 | /// session setting is used. |
377 | /// If neither this statement nor the session have the storage |
378 | /// type set, std::deque is the default container type used. |
379 | { |
380 | std::string storage; |
381 | |
382 | switch (_storage) |
383 | { |
384 | case STORAGE_DEQUE_IMPL: |
385 | storage = DEQUE; break; |
386 | case STORAGE_VECTOR_IMPL: |
387 | storage = VECTOR; break; |
388 | case STORAGE_LIST_IMPL: |
389 | storage = LIST; break; |
390 | case STORAGE_UNKNOWN_IMPL: |
391 | storage = AnyCast<std::string>(session().getProperty("storage" )); |
392 | break; |
393 | } |
394 | |
395 | if (storage.empty()) storage = VECTOR; |
396 | |
397 | if (0 == icompare(DEQUE, storage)) |
398 | { |
399 | if (!isBulkExtraction()) |
400 | addExtract(createExtract<std::deque<T> >(mc, position)); |
401 | else |
402 | addExtract(createBulkExtract<std::deque<T> >(mc, position)); |
403 | } |
404 | else if (0 == icompare(VECTOR, storage)) |
405 | { |
406 | if (!isBulkExtraction()) |
407 | addExtract(createExtract<std::vector<T> >(mc, position)); |
408 | else |
409 | addExtract(createBulkExtract<std::vector<T> >(mc, position)); |
410 | } |
411 | else if (0 == icompare(LIST, storage)) |
412 | { |
413 | if (!isBulkExtraction()) |
414 | addExtract(createExtract<std::list<T> >(mc, position)); |
415 | else |
416 | addExtract(createBulkExtract<std::list<T> >(mc, position)); |
417 | } |
418 | } |
419 | |
420 | bool isNull(std::size_t col, std::size_t row) const; |
421 | /// Returns true if the value in [col, row] is null. |
422 | |
423 | void forbidBulk(); |
424 | /// Forbids bulk operations. |
425 | |
426 | void setBulkBinding(); |
427 | /// Sets the bulk binding flag. |
428 | |
429 | void (const Bulk& l); |
430 | /// Sets the bulk extraction flag and extraction limit. |
431 | |
432 | void resetBulk(); |
433 | /// Resets the bulk extraction and binding flag. |
434 | |
435 | bool bulkBindingAllowed() const; |
436 | /// Returns true if statement can be set to bind data in bulk. |
437 | /// Once bulk binding is set for a statement, it can be |
438 | /// neither altered nor mixed with non-bulk mode binding. |
439 | |
440 | bool bulkExtractionAllowed() const; |
441 | /// Returns true if statement can be set to extract data in bulk. |
442 | /// Once bulk extraction is set for a statement, it can be |
443 | /// neither altered nor mixed with non-bulk mode extraction. |
444 | |
445 | bool isBulkBinding() const; |
446 | /// Returns true if statement is set to bind data in bulk. |
447 | |
448 | bool isBulkExtraction() const; |
449 | /// Returns true if statement is set to extract data in bulk. |
450 | |
451 | bool isBulkSupported() const; |
452 | /// Returns true if connector and session support bulk operation. |
453 | |
454 | void formatSQL(std::vector<Any>& arguments); |
455 | /// Formats the SQL string by filling in placeholders with values from supplied vector. |
456 | |
457 | void assignSubTotal(bool reset); |
458 | |
459 | StatementImpl(const StatementImpl& stmt); |
460 | StatementImpl& operator = (const StatementImpl& stmt); |
461 | |
462 | typedef std::vector<std::size_t> CountVec; |
463 | |
464 | State _state; |
465 | Limit _extrLimit; |
466 | std::size_t _lowerLimit; |
467 | std::vector<int> _columnsExtracted; |
468 | SessionImpl& _rSession; |
469 | Storage _storage; |
470 | std::ostringstream _ostr; |
471 | AbstractBindingVec _bindings; |
472 | AbstractExtractionVecVec ; |
473 | std::size_t _curDataSet; |
474 | BulkType _bulkBinding; |
475 | BulkType ; |
476 | CountVec _subTotalRowCount; |
477 | std::size_t _totalRowCount; |
478 | |
479 | friend class Statement; |
480 | friend class RecordSet; |
481 | }; |
482 | |
483 | |
484 | // |
485 | // inlines |
486 | // |
487 | |
488 | |
489 | inline void StatementImpl::addBind(AbstractBinding::Ptr pBinding) |
490 | { |
491 | poco_check_ptr (pBinding); |
492 | _bindings.push_back(pBinding); |
493 | } |
494 | |
495 | |
496 | inline std::string StatementImpl::toString() const |
497 | { |
498 | return _ostr.str(); |
499 | } |
500 | |
501 | |
502 | inline const AbstractBindingVec& StatementImpl::bindings() const |
503 | { |
504 | return _bindings; |
505 | } |
506 | |
507 | |
508 | inline AbstractBindingVec& StatementImpl::bindings() |
509 | { |
510 | return _bindings; |
511 | } |
512 | |
513 | |
514 | inline const AbstractExtractionVec& StatementImpl::() const |
515 | { |
516 | poco_assert (_curDataSet < _extractors.size()); |
517 | return _extractors[_curDataSet]; |
518 | } |
519 | |
520 | |
521 | inline AbstractExtractionVec& StatementImpl::() |
522 | { |
523 | poco_assert (_curDataSet < _extractors.size()); |
524 | return _extractors[_curDataSet]; |
525 | } |
526 | |
527 | |
528 | inline StatementImpl::State StatementImpl::getState() const |
529 | { |
530 | return _state; |
531 | } |
532 | |
533 | |
534 | inline SessionImpl& StatementImpl::session() |
535 | { |
536 | return _rSession; |
537 | } |
538 | |
539 | |
540 | inline void StatementImpl::setStorage(Storage storage) |
541 | { |
542 | _storage = storage; |
543 | } |
544 | |
545 | |
546 | inline StatementImpl::Storage StatementImpl::getStorage() const |
547 | { |
548 | return _storage; |
549 | } |
550 | |
551 | |
552 | inline std::size_t StatementImpl::getTotalRowCount() const |
553 | { |
554 | if (UNKNOWN_TOTAL_ROW_COUNT == _totalRowCount) |
555 | return subTotalRowCount(); |
556 | else |
557 | return _totalRowCount; |
558 | } |
559 | |
560 | |
561 | inline std::size_t StatementImpl::totalRowCount() const |
562 | { |
563 | return getTotalRowCount(); |
564 | } |
565 | |
566 | |
567 | inline void StatementImpl::setTotalRowCount(std::size_t count) |
568 | { |
569 | _totalRowCount = count; |
570 | } |
571 | |
572 | |
573 | inline std::size_t StatementImpl::() const |
574 | { |
575 | return static_cast<std::size_t>(extractions().size()); |
576 | } |
577 | |
578 | |
579 | inline std::size_t StatementImpl::dataSetCount() const |
580 | { |
581 | return static_cast<std::size_t>(_extractors.size()); |
582 | } |
583 | |
584 | |
585 | inline bool StatementImpl::isStoredProcedure() const |
586 | { |
587 | return false; |
588 | } |
589 | |
590 | |
591 | inline bool StatementImpl::isNull(std::size_t col, std::size_t row) const |
592 | { |
593 | try |
594 | { |
595 | return extractions().at(col)->isNull(row); |
596 | } |
597 | catch (std::out_of_range& ex) |
598 | { |
599 | throw RangeException(ex.what()); |
600 | } |
601 | } |
602 | |
603 | |
604 | inline std::size_t StatementImpl::currentDataSet() const |
605 | { |
606 | return _curDataSet; |
607 | } |
608 | |
609 | |
610 | inline Limit::SizeT StatementImpl::() |
611 | { |
612 | return _extrLimit.value(); |
613 | } |
614 | |
615 | |
616 | inline const Limit& StatementImpl::() const |
617 | { |
618 | return _extrLimit; |
619 | } |
620 | |
621 | |
622 | inline void StatementImpl::forbidBulk() |
623 | { |
624 | _bulkBinding = BULK_FORBIDDEN; |
625 | _bulkExtraction = BULK_FORBIDDEN; |
626 | } |
627 | |
628 | |
629 | inline void StatementImpl::setBulkBinding() |
630 | { |
631 | _bulkBinding = BULK_BINDING; |
632 | } |
633 | |
634 | |
635 | inline bool StatementImpl::bulkBindingAllowed() const |
636 | { |
637 | return BULK_UNDEFINED == _bulkBinding || |
638 | BULK_BINDING == _bulkBinding; |
639 | } |
640 | |
641 | |
642 | inline bool StatementImpl::() const |
643 | { |
644 | return BULK_UNDEFINED == _bulkExtraction || |
645 | BULK_EXTRACTION == _bulkExtraction; |
646 | } |
647 | |
648 | |
649 | inline bool StatementImpl::isBulkBinding() const |
650 | { |
651 | return BULK_BINDING == _bulkBinding; |
652 | } |
653 | |
654 | |
655 | inline bool StatementImpl::() const |
656 | { |
657 | return BULK_EXTRACTION == _bulkExtraction; |
658 | } |
659 | |
660 | |
661 | inline void StatementImpl::resetBulk() |
662 | { |
663 | _bulkExtraction = BULK_UNDEFINED; |
664 | _bulkBinding = BULK_UNDEFINED;\ |
665 | setExtractionLimit(Limit(Limit::LIMIT_UNLIMITED, false, false)); |
666 | } |
667 | |
668 | |
669 | inline bool StatementImpl::isBulkSupported() const |
670 | { |
671 | return _rSession.getFeature("bulk" ); |
672 | } |
673 | |
674 | |
675 | inline bool StatementImpl::hasMoreDataSets() const |
676 | { |
677 | return currentDataSet() + 1 < dataSetCount(); |
678 | } |
679 | |
680 | |
681 | inline void StatementImpl::firstDataSet() |
682 | { |
683 | _curDataSet = 0; |
684 | } |
685 | |
686 | |
687 | } } // namespace Poco::Data |
688 | |
689 | |
690 | #endif // Data_StatementImpl_INCLUDED |
691 | |