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
41namespace Poco {
42namespace Data {
43
44
45class RecordSet;
46
47class Data_API StatementImpl
48 /// StatementImpl interface that subclasses must implement to define database dependent query execution.
49 ///
50 /// StatementImpl's are noncopyable.
51{
52public:
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 BULK_EXTRACTION,
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 addExtract(AbstractExtraction::Ptr pExtraction);
121 /// Registers objects used for extracting data with the StatementImpl.
122
123 void setExtractionLimit(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
165protected:
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 extractor() = 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 fixupExtraction();
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 rowsExtracted(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 makeExtractors(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 makeExtractors(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
327private:
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 resetExtraction();
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 setBulkExtraction(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 _extractors;
473 std::size_t _curDataSet;
474 BulkType _bulkBinding;
475 BulkType _bulkExtraction;
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
489inline void StatementImpl::addBind(AbstractBinding::Ptr pBinding)
490{
491 poco_check_ptr (pBinding);
492 _bindings.push_back(pBinding);
493}
494
495
496inline std::string StatementImpl::toString() const
497{
498 return _ostr.str();
499}
500
501
502inline const AbstractBindingVec& StatementImpl::bindings() const
503{
504 return _bindings;
505}
506
507
508inline AbstractBindingVec& StatementImpl::bindings()
509{
510 return _bindings;
511}
512
513
514inline const AbstractExtractionVec& StatementImpl::extractions() const
515{
516 poco_assert (_curDataSet < _extractors.size());
517 return _extractors[_curDataSet];
518}
519
520
521inline AbstractExtractionVec& StatementImpl::extractions()
522{
523 poco_assert (_curDataSet < _extractors.size());
524 return _extractors[_curDataSet];
525}
526
527
528inline StatementImpl::State StatementImpl::getState() const
529{
530 return _state;
531}
532
533
534inline SessionImpl& StatementImpl::session()
535{
536 return _rSession;
537}
538
539
540inline void StatementImpl::setStorage(Storage storage)
541{
542 _storage = storage;
543}
544
545
546inline StatementImpl::Storage StatementImpl::getStorage() const
547{
548 return _storage;
549}
550
551
552inline 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
561inline std::size_t StatementImpl::totalRowCount() const
562{
563 return getTotalRowCount();
564}
565
566
567inline void StatementImpl::setTotalRowCount(std::size_t count)
568{
569 _totalRowCount = count;
570}
571
572
573inline std::size_t StatementImpl::extractionCount() const
574{
575 return static_cast<std::size_t>(extractions().size());
576}
577
578
579inline std::size_t StatementImpl::dataSetCount() const
580{
581 return static_cast<std::size_t>(_extractors.size());
582}
583
584
585inline bool StatementImpl::isStoredProcedure() const
586{
587 return false;
588}
589
590
591inline 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
604inline std::size_t StatementImpl::currentDataSet() const
605{
606 return _curDataSet;
607}
608
609
610inline Limit::SizeT StatementImpl::getExtractionLimit()
611{
612 return _extrLimit.value();
613}
614
615
616inline const Limit& StatementImpl::extractionLimit() const
617{
618 return _extrLimit;
619}
620
621
622inline void StatementImpl::forbidBulk()
623{
624 _bulkBinding = BULK_FORBIDDEN;
625 _bulkExtraction = BULK_FORBIDDEN;
626}
627
628
629inline void StatementImpl::setBulkBinding()
630{
631 _bulkBinding = BULK_BINDING;
632}
633
634
635inline bool StatementImpl::bulkBindingAllowed() const
636{
637 return BULK_UNDEFINED == _bulkBinding ||
638 BULK_BINDING == _bulkBinding;
639}
640
641
642inline bool StatementImpl::bulkExtractionAllowed() const
643{
644 return BULK_UNDEFINED == _bulkExtraction ||
645 BULK_EXTRACTION == _bulkExtraction;
646}
647
648
649inline bool StatementImpl::isBulkBinding() const
650{
651 return BULK_BINDING == _bulkBinding;
652}
653
654
655inline bool StatementImpl::isBulkExtraction() const
656{
657 return BULK_EXTRACTION == _bulkExtraction;
658}
659
660
661inline void StatementImpl::resetBulk()
662{
663 _bulkExtraction = BULK_UNDEFINED;
664 _bulkBinding = BULK_UNDEFINED;\
665 setExtractionLimit(Limit(Limit::LIMIT_UNLIMITED, false, false));
666}
667
668
669inline bool StatementImpl::isBulkSupported() const
670{
671 return _rSession.getFeature("bulk");
672}
673
674
675inline bool StatementImpl::hasMoreDataSets() const
676{
677 return currentDataSet() + 1 < dataSetCount();
678}
679
680
681inline void StatementImpl::firstDataSet()
682{
683 _curDataSet = 0;
684}
685
686
687} } // namespace Poco::Data
688
689
690#endif // Data_StatementImpl_INCLUDED
691