// // Preparator.h // // Library: Data/ODBC // Package: ODBC // Module: Preparator // // Definition of the Preparator class. // // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #ifndef Data_ODBC_Preparator_INCLUDED #define Data_ODBC_Preparator_INCLUDED #include "Poco/Data/Constants.h" #include "Poco/Data/ODBC/ODBC.h" #include "Poco/Data/ODBC/Handle.h" #include "Poco/Data/ODBC/ODBCMetaColumn.h" #include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/AbstractPreparator.h" #include "Poco/Data/LOB.h" #include "Poco/Any.h" #include "Poco/DynamicAny.h" #include "Poco/DateTime.h" #include "Poco/SharedPtr.h" #include "Poco/UTFString.h" #include #ifdef POCO_OS_FAMILY_WINDOWS #include #endif #include namespace Poco { namespace Data { class Date; class Time; namespace ODBC { class ODBC_API Preparator : public AbstractPreparator /// Class used for database preparation where we first have to register all data types /// with respective memory output locations before extracting data. /// Extraction works in two-phases: first prepare is called once, then extract n-times. /// In ODBC, SQLBindCol/SQLFetch is the preferred method of data retrieval (SQLGetData is available, /// however with numerous driver implementation dependent limitations and inferior performance). /// In order to fit this functionality into Poco DataConnectors framework, every ODBC SQL statement /// instantiates its own Preparator object. /// This is done once per statement execution (from StatementImpl::bindImpl()). /// /// Preparator object is used to : /// /// 1) Prepare SQL statement. /// 2) Provide and contain the memory locations where retrieved values are placed during recordset iteration. /// 3) Keep count of returned number of columns with their respective datatypes and sizes. /// /// Notes: /// /// - Value datatypes in this interface prepare() calls serve only for the purpose of type distinction. /// - Preparator keeps its own std::vector buffer for fetched data to be later retrieved by Extractor. /// - prepare() methods should not be called when extraction mode is DE_MANUAL /// { public: typedef std::vector CharArray; typedef SharedPtr Ptr; enum DataExtraction { DE_MANUAL, DE_BOUND }; enum DataType { DT_BOOL, DT_BOOL_ARRAY, DT_CHAR, DT_WCHAR, DT_UCHAR, DT_CHAR_ARRAY, DT_WCHAR_ARRAY, DT_UCHAR_ARRAY, DT_DATE, DT_TIME, DT_DATETIME }; Preparator(const StatementHandle& rStmt, const std::string& statement, std::size_t maxFieldSize, DataExtraction dataExtraction = DE_BOUND); /// Creates the Preparator. Preparator(const Preparator& other); /// Copy constructs the Preparator. ~Preparator(); /// Destroys the Preparator. void prepare(std::size_t pos, const Poco::Int8& val); /// Prepares an Int8. void prepare(std::size_t pos, const std::vector& val); /// Prepares an Int8 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an Int8 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an Int8 list. void prepare(std::size_t pos, const Poco::UInt8& val); /// Prepares an UInt8. void prepare(std::size_t pos, const std::vector& val); /// Prepares an UInt8 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an UInt8 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an UInt8 list. void prepare(std::size_t pos, const Poco::Int16& val); /// Prepares an Int16. void prepare(std::size_t pos, const std::vector& val); /// Prepares an Int16 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an Int16 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an Int16 list. void prepare(std::size_t pos, const Poco::UInt16& val); /// Prepares an UInt16. void prepare(std::size_t pos, const std::vector& val); /// Prepares an UInt16 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an UInt16 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an UInt16 list. void prepare(std::size_t pos, const Poco::Int32& val); /// Prepares an Int32. void prepare(std::size_t pos, const std::vector& val); /// Prepares an Int32 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an Int32 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an Int32 list. void prepare(std::size_t pos, const Poco::UInt32& val); /// Prepares an UInt32. void prepare(std::size_t pos, const std::vector& val); /// Prepares an UInt32 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an UInt32 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an UInt32 list. void prepare(std::size_t pos, const Poco::Int64& val); /// Prepares an Int64. void prepare(std::size_t pos, const std::vector& val); /// Prepares an Int64 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an Int64 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an Int64 list. void prepare(std::size_t pos, const Poco::UInt64& val); /// Prepares an UInt64. void prepare(std::size_t pos, const std::vector& val); /// Prepares an UInt64 vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an UInt64 deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an UInt64 list. #ifndef POCO_INT64_IS_LONG void prepare(std::size_t pos, const long& val); /// Prepares a long. void prepare(std::size_t pos, const unsigned long& val); /// Prepares an unsigned long. void prepare(std::size_t pos, const std::vector& val); /// Prepares a long vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a long deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a long list. #endif void prepare(std::size_t pos, const bool& val); /// Prepares a boolean. void prepare(std::size_t pos, const std::vector& val); /// Prepares a boolean vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a boolean deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a boolean list. void prepare(std::size_t pos, const float& val); /// Prepares a float. void prepare(std::size_t pos, const std::vector& val); /// Prepares a float vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a float deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a float list. void prepare(std::size_t pos, const double& val); /// Prepares a double. void prepare(std::size_t pos, const std::vector& val); /// Prepares a double vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a double deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a double list. void prepare(std::size_t pos, const char& val); /// Prepares a single character. void prepare(std::size_t pos, const std::vector& val); /// Prepares a single character vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a single character deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a single character list. void prepare(std::size_t pos, const std::string& val); /// Prepares a string. void prepare(std::size_t pos, const std::vector& val); /// Prepares a string vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a string deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a string list. void prepare(std::size_t pos, const UTF16String& val); /// Prepares a string. void prepare(std::size_t pos, const std::vector& val); /// Prepares a string vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a string deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a string list. void prepare(std::size_t pos, const Poco::Data::BLOB& val); /// Prepares a BLOB. void prepare(std::size_t pos, const std::vector& val); /// Prepares a BLOB vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a BLOB deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a BLOB list. void prepare(std::size_t pos, const Poco::Data::CLOB& val); /// Prepares a CLOB. void prepare(std::size_t pos, const std::vector& val); /// Prepares a CLOB vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a CLOB deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a CLOB list. void prepare(std::size_t pos, const Poco::Data::Date& val); /// Prepares a Date. void prepare(std::size_t pos, const std::vector& val); /// Prepares a Date vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a Date deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a Date list. void prepare(std::size_t pos, const Poco::Data::Time& val); /// Prepares a Time. void prepare(std::size_t pos, const std::vector& val); /// Prepares a Time vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a Time deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a Time list. void prepare(std::size_t pos, const Poco::DateTime& val); /// Prepares a DateTime. void prepare(std::size_t pos, const std::vector& val); /// Prepares a DateTime vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a DateTime deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a DateTime list. void prepare(std::size_t pos, const Poco::Any& val); /// Prepares an Any. void prepare(std::size_t pos, const std::vector& val); /// Prepares an Any vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares an Any deque. void prepare(std::size_t pos, const std::list& val); /// Prepares an Any list. void prepare(std::size_t pos, const Poco::DynamicAny& val); /// Prepares a DynamicAny. void prepare(std::size_t pos, const std::vector& val); /// Prepares a DynamicAny vector. void prepare(std::size_t pos, const std::deque& val); /// Prepares a DynamicAny deque. void prepare(std::size_t pos, const std::list& val); /// Prepares a DynamicAny list. std::size_t columns() const; /// Returns the number of columns. /// Resizes the internal storage iff the size is zero. Poco::Any& operator [] (std::size_t pos); /// Returns reference to column data. Poco::Any& at(std::size_t pos); /// Returns reference to column data. void setMaxFieldSize(std::size_t size); /// Sets maximum supported field size. std::size_t getMaxFieldSize() const; // Returns maximum supported field size. std::size_t maxDataSize(std::size_t pos) const; /// Returns max supported size for column at position pos. /// Returned length for variable length fields is the one /// supported by this implementation, not the underlying DB. std::size_t actualDataSize(std::size_t col, std::size_t row = POCO_DATA_INVALID_ROW) const; /// Returns the returned length for the column and row specified. /// This is usually equal to the column size, except for /// variable length fields (BLOB and variable length strings). /// For null values, the return value is -1 (SQL_NO_DATA) std::size_t bulkSize(std::size_t col = 0) const; /// Returns bulk size. Column argument is optional /// since all columns must be the same size. void setDataExtraction(DataExtraction ext); /// Set data extraction mode. DataExtraction getDataExtraction() const; /// Returns data extraction mode. private: typedef std::vector ValueVec; typedef std::vector LengthVec; typedef std::vector LengthLengthVec; typedef std::map IndexMap; Preparator(); Preparator& operator = (const Preparator&); template void prepareImpl(std::size_t pos, const C* pVal = 0) /// Utility function to prepare Any and DynamicAny. { ODBCMetaColumn col(_rStmt, pos); switch (col.type()) { case MetaColumn::FDT_INT8: if (pVal) return prepareFixedSize(pos, SQL_C_STINYINT, pVal->size()); else return prepareFixedSize(pos, SQL_C_STINYINT); case MetaColumn::FDT_UINT8: if (pVal) return prepareFixedSize(pos, SQL_C_UTINYINT, pVal->size()); else return prepareFixedSize(pos, SQL_C_UTINYINT); case MetaColumn::FDT_INT16: if (pVal) return prepareFixedSize(pos, SQL_C_SSHORT, pVal->size()); else return prepareFixedSize(pos, SQL_C_SSHORT); case MetaColumn::FDT_UINT16: if (pVal) return prepareFixedSize(pos, SQL_C_USHORT, pVal->size()); else return prepareFixedSize(pos, SQL_C_USHORT); case MetaColumn::FDT_INT32: if (pVal) return prepareFixedSize(pos, SQL_C_SLONG, pVal->size()); else return prepareFixedSize(pos, SQL_C_SLONG); case MetaColumn::FDT_UINT32: if (pVal) return prepareFixedSize(pos, SQL_C_ULONG, pVal->size()); else return prepareFixedSize(pos, SQL_C_ULONG); case MetaColumn::FDT_INT64: if (pVal) return prepareFixedSize(pos, SQL_C_SBIGINT, pVal->size()); else return prepareFixedSize(pos, SQL_C_SBIGINT); case MetaColumn::FDT_UINT64: if (pVal) return prepareFixedSize(pos, SQL_C_UBIGINT, pVal->size()); else return prepareFixedSize(pos, SQL_C_UBIGINT); case MetaColumn::FDT_BOOL: if (pVal) return prepareBoolArray(pos, SQL_C_BIT, pVal->size()); else return prepareFixedSize(pos, SQL_C_BIT); case MetaColumn::FDT_FLOAT: if (pVal) return prepareFixedSize(pos, SQL_C_FLOAT, pVal->size()); else return prepareFixedSize(pos, SQL_C_FLOAT); case MetaColumn::FDT_DOUBLE: if (pVal) return prepareFixedSize(pos, SQL_C_DOUBLE, pVal->size()); else return prepareFixedSize(pos, SQL_C_DOUBLE); case MetaColumn::FDT_STRING: if (pVal) return prepareCharArray(pos, SQL_C_CHAR, maxDataSize(pos), pVal->size()); else return prepareVariableLen(pos, SQL_C_CHAR, maxDataSize(pos), DT_CHAR); case MetaColumn::FDT_WSTRING: { typedef UTF16String::value_type CharType; if (pVal) return prepareCharArray(pos, SQL_C_WCHAR, maxDataSize(pos), pVal->size()); else return prepareVariableLen(pos, SQL_C_WCHAR, maxDataSize(pos), DT_WCHAR); } case MetaColumn::FDT_BLOB: { typedef Poco::Data::BLOB::ValueType CharType; if (pVal) return prepareCharArray(pos, SQL_C_BINARY, maxDataSize(pos), pVal->size()); else return prepareVariableLen(pos, SQL_C_BINARY, maxDataSize(pos), DT_UCHAR); } case MetaColumn::FDT_CLOB: { typedef Poco::Data::CLOB::ValueType CharType; if (pVal) return prepareCharArray(pos, SQL_C_BINARY, maxDataSize(pos), pVal->size()); else return prepareVariableLen(pos, SQL_C_BINARY, maxDataSize(pos), DT_CHAR); } case MetaColumn::FDT_DATE: if (pVal) return prepareFixedSize(pos, SQL_C_TYPE_DATE, pVal->size()); else return prepareFixedSize(pos, SQL_C_TYPE_DATE); case MetaColumn::FDT_TIME: if (pVal) return prepareFixedSize