| 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 | |