// // SQLExecutor.cpp // // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #include "CppUnit/TestCase.h" #include "SQLExecutor.h" #include "Poco/String.h" #include "Poco/Format.h" #include "Poco/Tuple.h" #include "Poco/Nullable.h" #include "Poco/Any.h" #include "Poco/Dynamic/Var.h" #include "Poco/DateTime.h" #include "Poco/Stopwatch.h" #include "Poco/NumberFormatter.h" #include "Poco/Thread.h" #include "Poco/Logger.h" #include "Poco/Message.h" #include "Poco/RefCountedObject.h" #include "Poco/AutoPtr.h" #include "Poco/SharedPtr.h" #include "Poco/Exception.h" #include "Poco/Data/Date.h" #include "Poco/Data/Time.h" #include "Poco/Data/LOB.h" #include "Poco/Data/StatementImpl.h" #include "Poco/Data/RecordSet.h" #include "Poco/Data/RowIterator.h" #include "Poco/Data/RowFilter.h" #include "Poco/Data/BulkExtraction.h" #include "Poco/Data/BulkBinding.h" #include "Poco/Data/SQLChannel.h" #include "Poco/Data/Transaction.h" #include "Poco/Data/ODBC/Connector.h" #include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/ODBC/Diagnostics.h" #include "Poco/Data/ODBC/Error.h" #include "Poco/Data/ODBC/Preparator.h" #include "Poco/Data/ODBC/ODBCException.h" #include "Poco/Data/ODBC/ODBCStatementImpl.h" #include "Poco/UnicodeConverter.h" #include "Poco/UTFString.h" #include #include #include #include using namespace Poco::Data::Keywords; using Poco::Data::Session; using Poco::Data::Statement; using Poco::Data::RecordSet; using Poco::Data::Column; using Poco::Data::Row; using Poco::Data::RowFilter; using Poco::Data::RowIterator; using Poco::Data::SQLChannel; using Poco::Data::LimitException; using Poco::Data::BindingException; using Poco::Data::CLOB; using Poco::Data::Date; using Poco::Data::Time; using Poco::Data::Transaction; using Poco::Data::NotConnectedException; using Poco::Data::ODBC::Utility; using Poco::Data::ODBC::Preparator; using Poco::Data::ODBC::ConnectionException; using Poco::Data::ODBC::StatementException; using Poco::Data::ODBC::DataTruncatedException; using Poco::Data::ODBC::StatementError; using Poco::format; using Poco::Tuple; using Poco::Nullable; using Poco::Any; using Poco::AnyCast; using Poco::Dynamic::Var; using Poco::DateTime; using Poco::Stopwatch; using Poco::NumberFormatter; using Poco::AutoPtr; using Poco::Thread; using Poco::Logger; using Poco::Message; using Poco::NotFoundException; using Poco::InvalidAccessException; using Poco::InvalidArgumentException; using Poco::NotImplementedException; using Poco::BadCastException; using Poco::RangeException; using Poco::TimeoutException; using Poco::UnicodeConverter; using Poco::UTF16String; using Poco::UTF32String; struct Person { std::string lastName; std::string firstName; std::string address; int age; Person(){age = 0;} Person(const std::string& ln, const std::string& fn, const std::string& adr, int a):lastName(ln), firstName(fn), address(adr), age(a) { } bool operator==(const Person& other) const { return lastName == other.lastName && firstName == other.firstName && address == other.address && age == other.age; } bool operator < (const Person& p) const { if (age < p.age) return true; if (lastName < p.lastName) return true; if (firstName < p.firstName) return true; return (address < p.address); } const std::string& operator () () const /// This method is required so we can extract data to a map! { // we choose the lastName as the key return lastName; } }; struct RefCountedPerson : public Poco::RefCountedObject { std::string lastName; std::string firstName; std::string address; int age; RefCountedPerson(){age = 0;} RefCountedPerson(const std::string& ln, const std::string& fn, const std::string& adr, int a):lastName(ln), firstName(fn), address(adr), age(a) { } bool operator==(const Person& other) const { return lastName == other.lastName && firstName == other.firstName && address == other.address && age == other.age; } bool operator < (const RefCountedPerson& p) const { if (age < p.age) return true; if (lastName < p.lastName) return true; if (firstName < p.firstName) return true; return (address < p.address); } const std::string& operator () () const /// This method is required so we can extract data to a map! { // we choose the lastName as the key return lastName; } private: RefCountedPerson(const RefCountedPerson &); RefCountedPerson& operator = (const RefCountedPerson&); }; namespace Poco { namespace Data { template <> class TypeHandler { public: static void bind(std::size_t pos, const Person& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir = AbstractBinder::PD_IN) { // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3)) poco_assert_dbg (!pBinder.isNull()); pBinder->bind(pos++, obj.lastName, dir); pBinder->bind(pos++, obj.firstName, dir); pBinder->bind(pos++, obj.address, dir); pBinder->bind(pos++, obj.age, dir); } static void prepare(std::size_t pos, const Person& obj, AbstractPreparator::Ptr pPrepare) { // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3)) poco_assert_dbg (!pPrepare.isNull()); pPrepare->prepare(pos++, obj.lastName); pPrepare->prepare(pos++, obj.firstName); pPrepare->prepare(pos++, obj.address); pPrepare->prepare(pos++, obj.age); } static std::size_t size() { return 4; } static void extract(std::size_t pos, Person& obj, const Person& defVal, AbstractExtractor::Ptr pExt) { poco_assert_dbg (!pExt.isNull()); if (!pExt->extract(pos++, obj.lastName)) obj.lastName = defVal.lastName; if (!pExt->extract(pos++, obj.firstName)) obj.firstName = defVal.firstName; if (!pExt->extract(pos++, obj.address)) obj.address = defVal.address; if (!pExt->extract(pos++, obj.age)) obj.age = defVal.age; } private: TypeHandler(const TypeHandler&); TypeHandler& operator=(const TypeHandler&); }; template <> class TypeHandler { public: static void bind(std::size_t pos, const RefCountedPerson& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir = AbstractBinder::PD_IN) { // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3)) poco_assert_dbg (!pBinder.isNull()); pBinder->bind(pos++, obj.lastName, dir); pBinder->bind(pos++, obj.firstName, dir); pBinder->bind(pos++, obj.address, dir); pBinder->bind(pos++, obj.age, dir); } static void prepare(std::size_t pos, RefCountedPerson& obj, AbstractPreparator::Ptr pPrepare) { // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3)) poco_assert_dbg (!pPrepare.isNull()); pPrepare->prepare(pos++, obj.lastName); pPrepare->prepare(pos++, obj.firstName); pPrepare->prepare(pos++, obj.address); pPrepare->prepare(pos++, obj.age); } static std::size_t size() { return 4; } static void extract(std::size_t pos, RefCountedPerson& obj, const RefCountedPerson& defVal, AbstractExtractor::Ptr pExt) { poco_assert_dbg (!pExt.isNull()); if (!pExt->extract(pos++, obj.lastName)) obj.lastName = defVal.lastName; if (!pExt->extract(pos++, obj.firstName)) obj.firstName = defVal.firstName; if (!pExt->extract(pos++, obj.address)) obj.address = defVal.address; if (!pExt->extract(pos++, obj.age)) obj.age = defVal.age; } private: TypeHandler(const TypeHandler&); TypeHandler& operator=(const TypeHandler&); }; } } // namespace Poco::Data const std::string SQLExecutor::MULTI_INSERT = "INSERT INTO Test VALUES ('1', 2, 3.5);" "INSERT INTO Test VALUES ('2', 3, 4.5);" "INSERT INTO Test VALUES ('3', 4, 5.5);" "INSERT INTO Test VALUES ('4', 5, 6.5);" "INSERT INTO Test VALUES ('5', 6, 7.5);"; const std::string SQLExecutor::MULTI_SELECT = "SELECT * FROM Test WHERE First = '1';" "SELECT * FROM Test WHERE First = '2';" "SELECT * FROM Test WHERE First = '3';" "SELECT * FROM Test WHERE First = '4';" "SELECT * FROM Test WHERE First = '5';"; SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession): CppUnit::TestCase(name), _pSession(pSession) { } SQLExecutor::~SQLExecutor() { } void SQLExecutor::bareboneODBCTest(const std::string& dbConnString, const std::string& tableCreateString, SQLExecutor::DataBinding bindMode, SQLExecutor::DataExtraction extractMode, bool doTime, const std::string& blobPlaceholder) { SQLRETURN rc; SQLHENV henv = SQL_NULL_HENV; SQLHDBC hdbc = SQL_NULL_HDBC; SQLHSTMT hstmt = SQL_NULL_HSTMT; // Environment begin rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); poco_odbc_check_env (rc, henv); rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0); poco_odbc_check_env (rc, henv); // Connection begin rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); poco_odbc_check_dbc (rc, hdbc); SQLCHAR connectOutput[1024] = {0}; SQLSMALLINT result; rc = SQLDriverConnect(hdbc , NULL ,(SQLCHAR*) dbConnString.c_str() ,(SQLSMALLINT) SQL_NTS , connectOutput , sizeof(connectOutput) , &result , SQL_DRIVER_NOPROMPT); poco_odbc_check_dbc (rc, hdbc); // retrieve datetime type information for this DBMS rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); poco_odbc_check_stmt (rc, hstmt); rc = SQLGetTypeInfo(hstmt, SQL_TYPE_TIMESTAMP); poco_odbc_check_stmt (rc, hstmt); rc = SQLFetch(hstmt); assertTrue (SQL_SUCCEEDED(rc) || SQL_NO_DATA == rc); SQLULEN dateTimeColSize = 0; SQLSMALLINT dateTimeDecDigits = 0; if (SQL_SUCCEEDED(rc)) { SQLLEN ind = 0; rc = SQLGetData(hstmt, 3, SQL_C_SLONG, &dateTimeColSize, sizeof(SQLINTEGER), &ind); poco_odbc_check_stmt (rc, hstmt); rc = SQLGetData(hstmt, 14, SQL_C_SSHORT, &dateTimeDecDigits, sizeof(SQLSMALLINT), &ind); poco_odbc_check_stmt (rc, hstmt); assertTrue (sizeof(SQL_TIMESTAMP_STRUCT) <= dateTimeColSize); } else if (SQL_NO_DATA == rc) std::cerr << '[' << name() << ']' << " Warning: no SQL_TYPE_TIMESTAMP data type info returned by driver." << std::endl; rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); poco_odbc_check_stmt (rc, hstmt); // Statement begin rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); poco_odbc_check_stmt (rc, hstmt); std::string sql = "DROP TABLE Test"; SQLCHAR* pStr = (SQLCHAR*) sql.c_str(); SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); //no return code check - ignore drop errors // create table and go sql = tableCreateString; pStr = (SQLCHAR*) sql.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); rc = SQLExecute(hstmt); poco_odbc_check_stmt (rc, hstmt); sql = format("INSERT INTO Test VALUES (?,?,%s,?,?,?)", blobPlaceholder); pStr = (SQLCHAR*) sql.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); std::string str[3] = { "11111111111", "222222222222222222222222", "333333333333333333333333333" }; int fourth = 4; float fifth = 1.5; SQL_TIMESTAMP_STRUCT sixth; sixth.year = 1965; sixth.month = 6; sixth.day = 18; sixth.hour = 5; sixth.minute = 34; sixth.second = 58; // Fraction support is limited to milliseconds due to MS SQL Server limitation // see http://support.microsoft.com/kb/263872 sixth.fraction = 997000000; SQLLEN li[3] = { SQL_NTS, SQL_NTS, 0 }; SQLINTEGER size = (SQLINTEGER) str[0].size(); if (SQLExecutor::PB_AT_EXEC == bindMode) li[0] = SQL_LEN_DATA_AT_EXEC(size); rc = SQLBindParameter(hstmt, (SQLUSMALLINT) 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, (SQLUINTEGER) size, 0, (SQLPOINTER) str[0].c_str(), size, &li[0]); poco_odbc_check_stmt (rc, hstmt); size = (SQLINTEGER) str[1].size(); if (SQLExecutor::PB_AT_EXEC == bindMode) li[1] = SQL_LEN_DATA_AT_EXEC(size); else li[1] = SQL_NTS; rc = SQLBindParameter(hstmt, (SQLUSMALLINT) 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, (SQLUINTEGER) size, 0, (SQLPOINTER) str[1].c_str(), size, &li[1]); poco_odbc_check_stmt (rc, hstmt); size = (SQLINTEGER) str[2].size(); if (SQLExecutor::PB_AT_EXEC == bindMode) li[2] = SQL_LEN_DATA_AT_EXEC(size); else li[2] = size; rc = SQLBindParameter(hstmt, (SQLUSMALLINT) 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, (SQLUINTEGER) size, 0, (SQLPOINTER) str[2].data(), size, &li[2]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindParameter(hstmt, (SQLUSMALLINT) 4, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, (SQLPOINTER) &fourth, 0, 0); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindParameter(hstmt, (SQLUSMALLINT) 5, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 0, 1, (SQLPOINTER) &fifth, 0, 0); poco_odbc_check_stmt (rc, hstmt); SQLSMALLINT dataType = 0; SQLULEN parameterSize = 0; SQLSMALLINT decimalDigits = 0; SQLSMALLINT nullable = 0; rc = SQLDescribeParam(hstmt, 6, &dataType, ¶meterSize, &decimalDigits, &nullable); if (SQL_SUCCEEDED(rc)) { if (parameterSize) dateTimeColSize = parameterSize; if (decimalDigits) dateTimeDecDigits = decimalDigits; } else std::cerr << '[' << name() << ']' << " Warning: could not get SQL_TYPE_TIMESTAMP parameter description." << std::endl; rc = SQLBindParameter(hstmt, (SQLUSMALLINT) 6, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, dateTimeColSize, dateTimeDecDigits, (SQLPOINTER) &sixth, 0, 0); poco_odbc_check_stmt (rc, hstmt); rc = SQLExecute(hstmt); assertTrue (SQL_NEED_DATA == rc || SQL_SUCCEEDED(rc)); if (SQL_NEED_DATA == rc) { SQLPOINTER pParam = 0; while (SQL_NEED_DATA == (rc = SQLParamData(hstmt, &pParam))) { SQLINTEGER dataSize = 0; // Data size should be ignored for non-null, // non-variable length fields, but SQLite ODBC // driver insists on it always being the actual // data length if (pParam == (SQLPOINTER) str[0].c_str()) dataSize = (SQLINTEGER) str[0].size(); else if (pParam == (SQLPOINTER) str[1].c_str()) dataSize = (SQLINTEGER) str[1].size(); else if (pParam == (SQLPOINTER) str[2].c_str()) dataSize = (SQLINTEGER) str[2].size(); else if (pParam == (SQLPOINTER) &fourth) dataSize = (SQLINTEGER) sizeof(fourth); else if (pParam == (SQLPOINTER) &fifth) dataSize = (SQLINTEGER) sizeof(fifth); else if (pParam == (SQLPOINTER) &sixth) dataSize = (SQLINTEGER) sizeof(sixth); assertTrue (0 != dataSize); rc = SQLPutData(hstmt, pParam, dataSize); poco_odbc_check_stmt (rc, hstmt); } } poco_odbc_check_stmt (rc, hstmt); sql = "SELECT * FROM Test"; pStr = (SQLCHAR*) sql.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); char chr[3][50] = {{ 0 }}; SQLLEN lengths[6] = { 0 }; fourth = 0; fifth = 0.0f; std::memset(&sixth, 0, sizeof(sixth)); if (SQLExecutor::DE_BOUND == extractMode) { rc = SQLBindCol(hstmt, (SQLUSMALLINT) 1, SQL_C_CHAR, (SQLPOINTER) chr[0], (SQLINTEGER) sizeof(chr[0]), &lengths[0]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindCol(hstmt, (SQLUSMALLINT) 2, SQL_C_CHAR, (SQLPOINTER) chr[1], (SQLINTEGER) sizeof(chr[1]), &lengths[1]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindCol(hstmt, (SQLUSMALLINT) 3, SQL_C_BINARY, (SQLPOINTER) chr[2], (SQLINTEGER) sizeof(chr[2]), &lengths[2]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindCol(hstmt, (SQLUSMALLINT) 4, SQL_C_SLONG, (SQLPOINTER) &fourth, (SQLINTEGER) 0, &lengths[3]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindCol(hstmt, (SQLUSMALLINT) 5, SQL_C_FLOAT, (SQLPOINTER) &fifth, (SQLINTEGER) 0, &lengths[4]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindCol(hstmt, (SQLUSMALLINT) 6, SQL_C_TYPE_TIMESTAMP, (SQLPOINTER) &sixth, (SQLINTEGER) 0, &lengths[5]); poco_odbc_check_stmt (rc, hstmt); } rc = SQLExecute(hstmt); poco_odbc_check_stmt (rc, hstmt); rc = SQLFetch(hstmt); poco_odbc_check_stmt (rc, hstmt); if (SQLExecutor::DE_MANUAL == extractMode) { SQLLEN len = lengths[0] = 0; while (SQL_SUCCESS_WITH_INFO == (rc = SQLGetData(hstmt, (SQLUSMALLINT) 1, SQL_C_CHAR, chr[0] + len, sizeof(chr[0]) - len, &lengths[0]))) { len += lengths[0]; if (!lengths[0] || len >= sizeof(chr[1])) break; } poco_odbc_check_stmt (rc, hstmt); len = lengths[1] = 0; while (SQL_SUCCESS_WITH_INFO == (rc = SQLGetData(hstmt, (SQLUSMALLINT) 2, SQL_C_CHAR, chr[1] + len, sizeof(chr[1]) - len, &lengths[1]))) { len += lengths[1]; if (!lengths[1] || len >= sizeof(chr[1])) break; } poco_odbc_check_stmt (rc, hstmt); len = lengths[2] = 0; while (SQL_SUCCESS_WITH_INFO == (rc = SQLGetData(hstmt, (SQLUSMALLINT) 3, SQL_C_BINARY, chr[2] + len, sizeof(chr[2]) - len, &lengths[2]))) { len += lengths[1]; if (!lengths[2] || len >= sizeof(chr[2])) break; } poco_odbc_check_stmt (rc, hstmt); rc = SQLGetData(hstmt, (SQLUSMALLINT) 4, SQL_C_SLONG, &fourth, 0, &lengths[3]); poco_odbc_check_stmt (rc, hstmt); rc = SQLGetData(hstmt, (SQLUSMALLINT) 5, SQL_C_FLOAT, &fifth, 0, &lengths[4]); poco_odbc_check_stmt (rc, hstmt); rc = SQLGetData(hstmt, (SQLUSMALLINT) 6, SQL_C_TYPE_TIMESTAMP, &sixth, 0, &lengths[5]); poco_odbc_check_stmt (rc, hstmt); } assertTrue (0 == std::strncmp(str[0].c_str(), chr[0], str[0].size())); assertTrue (0 == std::strncmp(str[1].c_str(), chr[1], str[1].size())); assertTrue (0 == std::strncmp(str[2].c_str(), chr[2], str[2].size())); assertTrue (4 == fourth); assertTrue (1.5 == fifth); assertTrue (1965 == sixth.year); assertTrue (6 == sixth.month); assertTrue (18 == sixth.day); if (doTime) { assertTrue (5 == sixth.hour); assertTrue (34 == sixth.minute); if (sixth.fraction) // MySQL rounds fraction { assertTrue (58 == sixth.second); assertTrue (997000000 == sixth.fraction); } else { assertTrue (59 == sixth.second); } } rc = SQLCloseCursor(hstmt); poco_odbc_check_stmt (rc, hstmt); sql = "DROP TABLE Test"; pStr = (SQLCHAR*) sql.c_str(); rc = SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); poco_odbc_check_stmt (rc, hstmt); // Connection end rc = SQLDisconnect(hdbc); poco_odbc_check_dbc (rc, hdbc); rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); poco_odbc_check_dbc (rc, hdbc); // Environment end rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); poco_odbc_check_env (rc, henv); } void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString, const std::string& tableCreateString, SQLExecutor::DataBinding bindMode, SQLExecutor::DataExtraction extractMode, const std::string& insert, const std::string& select) { SQLRETURN rc; SQLHENV henv = SQL_NULL_HENV; SQLHDBC hdbc = SQL_NULL_HDBC; SQLHSTMT hstmt = SQL_NULL_HSTMT; // Environment begin rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); poco_odbc_check_stmt (rc, hstmt); rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0); poco_odbc_check_stmt (rc, hstmt); // Connection begin rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); poco_odbc_check_stmt (rc, hstmt); SQLCHAR connectOutput[512] = {0}; SQLSMALLINT result; rc = SQLDriverConnect(hdbc , NULL ,(SQLCHAR*) dbConnString.c_str() ,(SQLSMALLINT) SQL_NTS , connectOutput , sizeof(connectOutput) , &result , SQL_DRIVER_NOPROMPT); poco_odbc_check_stmt (rc, hstmt); // Statement begin rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); poco_odbc_check_stmt (rc, hstmt); std::string sql = "DROP TABLE Test"; SQLCHAR* pStr = (SQLCHAR*) sql.c_str(); SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); //no return code check - ignore drop errors // create table and go sql = tableCreateString; pStr = (SQLCHAR*) sql.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); rc = SQLExecute(hstmt); poco_odbc_check_stmt (rc, hstmt); // insert multiple rows pStr = (SQLCHAR*) insert.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) insert.length()); poco_odbc_check_stmt (rc, hstmt); rc = SQLExecute(hstmt); poco_odbc_check_stmt (rc, hstmt); do { SQLLEN rowCount = 0; SQLRowCount(hstmt, &rowCount); assertTrue (1 == rowCount); } while (SQL_NO_DATA != SQLMoreResults(hstmt)); // make sure all five rows made it in sql = "select count(*) from Test"; int count = 0; SQLLEN length = 0; pStr = (SQLCHAR*) sql.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); if (SQLExecutor::DE_BOUND == extractMode) { rc = SQLBindCol(hstmt, (SQLUSMALLINT) 1, SQL_C_SLONG, (SQLPOINTER) &count, (SQLINTEGER) 0, &length); poco_odbc_check_stmt (rc, hstmt); } rc = SQLExecute(hstmt); poco_odbc_check_stmt (rc, hstmt); rc = SQLFetch(hstmt); poco_odbc_check_stmt (rc, hstmt); if (SQLExecutor::DE_MANUAL == extractMode) { rc = SQLGetData(hstmt, (SQLUSMALLINT) 1, SQL_C_SLONG, &count, 0, &length); poco_odbc_check_stmt (rc, hstmt); } assertTrue (5 == count); rc = SQLCloseCursor(hstmt); poco_odbc_check_stmt (rc, hstmt); // select multiple rows pStr = (SQLCHAR*) select.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) select.length()); poco_odbc_check_stmt (rc, hstmt); char chr[5] = { 0 }; SQLLEN lengths[3] = { 0 }; int second = 0; float third = 0.0f; if (SQLExecutor::DE_BOUND == extractMode) { rc = SQLBindCol(hstmt, (SQLUSMALLINT) 1, SQL_C_CHAR, (SQLPOINTER) chr, (SQLINTEGER) 4, &lengths[0]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindCol(hstmt, (SQLUSMALLINT) 2, SQL_C_SLONG, (SQLPOINTER) &second, (SQLINTEGER) 0, &lengths[1]); poco_odbc_check_stmt (rc, hstmt); rc = SQLBindCol(hstmt, (SQLUSMALLINT) 3, SQL_C_FLOAT, (SQLPOINTER) &third, (SQLINTEGER) 0, &lengths[2]); poco_odbc_check_stmt (rc, hstmt); } rc = SQLExecute(hstmt); poco_odbc_check_stmt (rc, hstmt); char one = 0x31; int two = 2; float three = 3.5; count = 0; do { rc = SQLFetch(hstmt); poco_odbc_check_stmt (rc, hstmt); if (SQLExecutor::DE_MANUAL == extractMode) { rc = SQLGetData(hstmt, (SQLUSMALLINT) 1, SQL_C_CHAR, chr, 4, &lengths[0]); poco_odbc_check_stmt (rc, hstmt); rc = SQLGetData(hstmt, (SQLUSMALLINT) 2, SQL_C_SLONG, &second, 0, &lengths[1]); poco_odbc_check_stmt (rc, hstmt); rc = SQLGetData(hstmt, (SQLUSMALLINT) 3, SQL_C_FLOAT, &third, 0, &lengths[2]); poco_odbc_check_stmt (rc, hstmt); } assertTrue (one++ == chr[0]); assertTrue (two++ == second); assertTrue (three == third); three += 1.0; ++count; } while (SQL_NO_DATA != SQLMoreResults(hstmt)); assertTrue (5 == count); sql = "DROP TABLE Test"; pStr = (SQLCHAR*) sql.c_str(); rc = SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); poco_odbc_check_stmt (rc, hstmt); // Connection end rc = SQLDisconnect(hdbc); poco_odbc_check_stmt (rc, hstmt); rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); poco_odbc_check_stmt (rc, hstmt); // Environment end rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); poco_odbc_check_stmt (rc, hstmt); } void SQLExecutor::execute(const std::string& sql) { try { session() << sql, now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (sql); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (sql); } } void SQLExecutor::zeroRows() { Statement stmt = (session() << "SELECT * FROM Person WHERE 0 = 1"); assertTrue (0 == stmt.execute()); } void SQLExecutor::simpleAccess() { std::string funct = "simpleAccess()"; std::string lastName = "lastName"; std::string firstName("firstName"); std::string address("Address"); int age = 133132; int count = 0; std::string result; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); try { session() << "SELECT LastName FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (lastName == result); try { session() << "SELECT Age FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == age); } void SQLExecutor::complexType() { std::string funct = "complexType()"; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(p1), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(p2), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person c1; try { session() << "SELECT * FROM Person WHERE LastName = 'LN1'", into(c1), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (c1 == p1); } void SQLExecutor::complexTypeTuple() { std::string funct = "complexTypeTuple()"; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); Tuple t(p1,p2); try { *_pSession << "INSERT INTO Person VALUES(?,?,?,?,?,?,?,?)", use(t), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } Tuple ret; assertTrue (ret != t); try { *_pSession << "SELECT * FROM Person", into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ret == t); } void SQLExecutor::simpleAccessVector() { std::string funct = "simpleAccessVector()"; std::vector lastNames; std::vector firstNames; std::vector addresses; std::vector ages; std::string tableName("Person"); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); firstNames.push_back("FN2"); addresses.push_back("ADDR1"); addresses.push_back("ADDR2"); ages.push_back(1); ages.push_back(2); int count = 0; std::string result; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::vector lastNamesR; std::vector firstNamesR; std::vector addressesR; std::vector agesR; try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ages == agesR); assertTrue (lastNames == lastNamesR); assertTrue (firstNames == firstNamesR); assertTrue (addresses == addressesR); } void SQLExecutor::complexTypeVector() { std::string funct = "complexTypeVector()"; std::vector people; people.push_back(Person("LN1", "FN1", "ADDR1", 1)); people.push_back(Person("LN2", "FN2", "ADDR2", 2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::vector result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result == people); } void SQLExecutor::sharedPtrComplexTypeVector() { std::string funct = "sharedPtrComplexTypeVector()"; std::vector > people; people.push_back(new Person("LN1", "FN1", "ADDR1", 1)); people.push_back(new Person("LN2", "FN2", "ADDR2", 2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::vector result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == result.size()); assertTrue (result[0] == *people[0]); assertTrue (result[1] == *people[1]); } void SQLExecutor::autoPtrComplexTypeVector() { std::string funct = "sharedPtrComplexTypeVector()"; std::vector > people; people.push_back(new RefCountedPerson("LN1", "FN1", "ADDR1", 1)); people.push_back(new RefCountedPerson("LN2", "FN2", "ADDR2", 2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::vector result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == result.size()); assertTrue (result[0].address == people[0]->address); assertTrue (result[0].age == people[0]->age); assertTrue (result[0].firstName == people[0]->firstName); assertTrue (result[0].lastName == people[0]->lastName); assertTrue (result[1].address == people[1]->address); assertTrue (result[1].age == people[1]->age); assertTrue (result[1].firstName == people[1]->firstName); assertTrue (result[1].lastName == people[1]->lastName); } void SQLExecutor::insertVector() { std::string funct = "insertVector()"; std::vector str; str.push_back("s1"); str.push_back("s2"); str.push_back("s3"); str.push_back("s3"); int count = 100; { Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 0); try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 4); } count = 0; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 4); } void SQLExecutor::insertEmptyVector() { std::string funct = "insertEmptyVector()"; std::vector str; try { session() << "INSERT INTO Strings VALUES (?)", use(str), now; fail("empty collections should not work"); } catch (Poco::Exception&) { } } void SQLExecutor::simpleAccessList() { std::string funct = "simpleAccessList()"; std::list lastNames; std::list firstNames; std::list addresses; std::list ages; std::string tableName("Person"); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); firstNames.push_back("FN2"); addresses.push_back("ADDR1"); addresses.push_back("ADDR2"); ages.push_back(1); ages.push_back(2); int count = 0; std::string result; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::list lastNamesR; std::list firstNamesR; std::list addressesR; std::list agesR; try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ages == agesR); assertTrue (lastNames == lastNamesR); assertTrue (firstNames == firstNamesR); assertTrue (addresses == addressesR); } void SQLExecutor::complexTypeList() { std::string funct = "complexTypeList()"; std::list people; people.push_back(Person("LN1", "FN1", "ADDR1", 1)); people.push_back(Person("LN2", "FN2", "ADDR2", 2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::list result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result == people); } void SQLExecutor::insertList() { std::string funct = "insertList()"; std::list str; str.push_back("s1"); str.push_back("s2"); str.push_back("s3"); str.push_back("s3"); int count = 100; { Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 0); try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 4); } count = 0; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 4); } void SQLExecutor::insertEmptyList() { std::string funct = "insertEmptyList()"; std::list str; try { session() << "INSERT INTO Strings VALUES (?)", use(str), now; fail("empty collections should not work"); } catch (Poco::Exception&) { } } void SQLExecutor::simpleAccessDeque() { std::string funct = "simpleAccessDeque()"; std::deque lastNames; std::deque firstNames; std::deque addresses; std::deque ages; std::string tableName("Person"); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); firstNames.push_back("FN2"); addresses.push_back("ADDR1"); addresses.push_back("ADDR2"); ages.push_back(1); ages.push_back(2); int count = 0; std::string result; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::deque lastNamesR; std::deque firstNamesR; std::deque addressesR; std::deque agesR; try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ages == agesR); assertTrue (lastNames == lastNamesR); assertTrue (firstNames == firstNamesR); assertTrue (addresses == addressesR); } void SQLExecutor::complexTypeDeque() { std::string funct = "complexTypeDeque()"; std::deque people; people.push_back(Person("LN1", "FN1", "ADDR1", 1)); people.push_back(Person("LN2", "FN2", "ADDR2", 2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::deque result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result == people); } void SQLExecutor::insertDeque() { std::string funct = "insertDeque()"; std::deque str; str.push_back("s1"); str.push_back("s2"); str.push_back("s3"); str.push_back("s3"); int count = 100; { Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 0); try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 4); } count = 0; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 4); } void SQLExecutor::insertEmptyDeque() { std::string funct = "insertEmptyDeque()"; std::deque str; try { session() << "INSERT INTO Strings VALUES (?)", use(str), now; fail("empty collections should not work"); } catch (Poco::Exception&) { } } void SQLExecutor::affectedRows(const std::string& whereClause) { std::vector str; str.push_back("s1"); str.push_back("s2"); str.push_back("s3"); str.push_back("s3"); int count = 100; Statement stmt1((session() << "INSERT INTO Strings VALUES(?)", use(str))); session() << "SELECT COUNT(*) FROM Strings", into(count), now; assertTrue (count == 0); assertTrue (4 == stmt1.execute()); session() << "SELECT COUNT(*) FROM Strings", into(count), now; assertTrue (count == 4); Statement stmt2(session() << "UPDATE Strings SET str = 's4' WHERE str = 's3'"); assertTrue (2 == stmt2.execute()); Statement stmt3(session() << "DELETE FROM Strings WHERE str = 's1'"); assertTrue (1 == stmt3.execute()); std::string sql; format(sql, "DELETE FROM Strings %s", whereClause); Statement stmt4(session() << sql); assertTrue (3 == stmt4.execute()); } void SQLExecutor::insertSingleBulk() { std::string funct = "insertSingleBulk()"; int x = 0; Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(x))); for (x = 0; x < 100; ++x) { std::size_t i = stmt.execute(); assertTrue (1 == i); } int count = 0; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 100); try { session() << "SELECT SUM(str) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == ((0+99)*100/2)); } void SQLExecutor::floats() { std::string funct = "floats()"; float data = 1.5f; float ret = 0.0f; try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); try { session() << "SELECT str FROM Strings", into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ret == data); } void SQLExecutor::doubles() { std::string funct = "floats()"; double data = 1.5; double ret = 0.0; try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); try { session() << "SELECT str FROM Strings", into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ret == data); } void SQLExecutor::insertSingleBulkVec() { std::string funct = "insertSingleBulkVec()"; std::vector data; for (int x = 0; x < 100; ++x) data.push_back(x); Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(data))); stmt.execute(); int count = 0; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 100); try { session() << "SELECT SUM(str) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == ((0+99)*100/2)); } void SQLExecutor::limits() { std::string funct = "limit()"; std::vector data; for (int x = 0; x < 100; ++x) { data.push_back(x); } try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector retData; try { session() << "SELECT * FROM Strings", into(retData), limit(50), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (retData.size() == 50); for (int x = 0; x < 50; ++x) { assertTrue (data[x] == retData[x]); } } void SQLExecutor::limitZero() { std::string funct = "limitZero()"; std::vector data; for (int x = 0; x < 100; ++x) { data.push_back(x); } try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector retData; try { session() << "SELECT * FROM Strings", into(retData), limit(0), now; }// stupid test, but at least we shouldn't crash catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (retData.size() == 0); } void SQLExecutor::limitOnce() { std::string funct = "limitOnce()"; std::vector data; for (int x = 0; x < 101; ++x) { data.push_back(x); } try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector retData; Statement stmt = (session() << "SELECT * FROM Strings", into(retData), limit(50), now); assertTrue (!stmt.done()); assertTrue (retData.size() == 50); stmt.execute(); assertTrue (!stmt.done()); assertTrue (retData.size() == 100); stmt.execute(); assertTrue (stmt.done()); assertTrue (retData.size() == 101); for (int x = 0; x < 101; ++x) { assertTrue (data[x] == retData[x]); } } void SQLExecutor::limitPrepare() { std::string funct = "limitPrepare()"; std::vector data; for (int x = 0; x < 100; ++x) { data.push_back(x); } try { Statement stmt = (session() << "INSERT INTO Strings VALUES (?)", use(data)); assertTrue (100 == stmt.execute()); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector retData; Statement stmt = (session() << "SELECT * FROM Strings", into(retData), limit(50)); assertTrue (retData.size() == 0); assertTrue (!stmt.done()); try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (!stmt.done()); assertTrue (retData.size() == 50); try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (stmt.done()); assertTrue (retData.size() == 100); try { stmt.execute(); }// will restart execution! catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (!stmt.done()); assertTrue (retData.size() == 150); for (int x = 0; x < 150; ++x) { assertTrue (data[x%100] == retData[x]); } } void SQLExecutor::prepare() { std::string funct = "prepare()"; std::vector data; for (int x = 0; x < 100; x += 2) { data.push_back(x); } { Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(data))); } // stmt should not have been executed when destroyed int count = 100; try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 0); } void SQLExecutor::doBulkPerformance(Poco::UInt32 size) { std::string funct = "doBulk()"; std::vector ints(size, 1); std::vector strings(size, "abc"); std::vector floats(size, .5); std::vector dateTimes(size); Stopwatch sw; try { sw.start(); session() << "INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", use(strings), use(ints), use(floats), use(dateTimes), now; sw.stop(); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } double time = sw.elapsed() / 1000.0; try { session() << "DELETE FROM MiscTest", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { sw.restart(); session() << "INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", use(strings, bulk), use(ints, bulk), use(floats, bulk), use(dateTimes, bulk), now; sw.stop(); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } double bulkTime = sw.elapsed() / 1000.0; double speedup; if (0.0 == bulkTime) { if (0.0 == time) speedup = 1.0; else speedup = time; } else speedup = time / bulkTime; std::cout << "INSERT => Size:" << size << ", Time: " << time << ", Bulk Time: " << bulkTime << " [ms], Speedup: " << speedup << 'x' << std::endl; ints.clear(); strings.clear(); floats.clear(); dateTimes.clear(); try { sw.restart(); session() << "SELECT First, Third, Fourth, Fifth FROM MiscTest", into(strings), into(ints), into(floats), into(dateTimes), now; sw.stop(); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } time = sw.elapsed() / 1000.0; assertTrue (ints.size() == size); ints.clear(); strings.clear(); floats.clear(); dateTimes.clear(); try { sw.restart(); session() << "SELECT First, Third, Fourth, Fifth FROM MiscTest", into(strings, bulk(size)), into(ints, bulk(size)), into(floats, bulk(size)), into(dateTimes, bulk(size)), now; sw.stop(); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } bulkTime = sw.elapsed() / 1000.0; assertTrue (ints.size() == size); if (0.0 == bulkTime) { if (0.0 == time) speedup = 1.0; else speedup = time; } else speedup = time / bulkTime; std::cout << "SELECT => Size:" << size << ", Time: " << time << ", Bulk Time: " << bulkTime << " [ms], Speedup: " << speedup << 'x' << std::endl; } void SQLExecutor::setSimple() { std::string funct = "setSimple()"; std::set lastNames; std::set firstNames; std::set addresses; std::set ages; std::string tableName("Person"); lastNames.insert("LN1"); lastNames.insert("LN2"); firstNames.insert("FN1"); firstNames.insert("FN2"); addresses.insert("ADDR1"); addresses.insert("ADDR2"); ages.insert(1); ages.insert(2); int count = 0; std::string result; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::set lastNamesR; std::set firstNamesR; std::set addressesR; std::set agesR; try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ages == agesR); assertTrue (lastNames == lastNamesR); assertTrue (firstNames == firstNamesR); assertTrue (addresses == addressesR); } void SQLExecutor::setComplex() { std::string funct = "setComplex()"; std::set people; people.insert(Person("LN1", "FN1", "ADDR1", 1)); people.insert(Person("LN2", "FN2", "ADDR2", 2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::set result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result == people); } void SQLExecutor::setComplexUnique() { std::string funct = "setComplexUnique()"; std::vector people; Person p1("LN1", "FN1", "ADDR1", 1); people.push_back(p1); people.push_back(p1); people.push_back(p1); people.push_back(p1); Person p2("LN2", "FN2", "ADDR2", 2); people.push_back(p2); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 5); std::set result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result.size() == 2); assertTrue (*result.begin() == p1); assertTrue (*++result.begin() == p2); } void SQLExecutor::multiSetSimple() { std::string funct = "multiSetSimple()"; std::multiset lastNames; std::multiset firstNames; std::multiset addresses; std::multiset ages; std::string tableName("Person"); lastNames.insert("LN1"); lastNames.insert("LN2"); firstNames.insert("FN1"); firstNames.insert("FN2"); addresses.insert("ADDR1"); addresses.insert("ADDR2"); ages.insert(1); ages.insert(2); int count = 0; std::string result; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::multiset lastNamesR; std::multiset firstNamesR; std::multiset addressesR; std::multiset agesR; try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ages.size() == agesR.size()); assertTrue (lastNames.size() == lastNamesR.size()); assertTrue (firstNames.size() == firstNamesR.size()); assertTrue (addresses.size() == addressesR.size()); } void SQLExecutor::multiSetComplex() { std::string funct = "multiSetComplex()"; std::multiset people; Person p1("LN1", "FN1", "ADDR1", 1); people.insert(p1); people.insert(p1); people.insert(p1); people.insert(p1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(p2); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 5); std::multiset result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result.size() == people.size()); } void SQLExecutor::mapComplex() { std::string funct = "mapComplex()"; std::map people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::map result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result == people); } void SQLExecutor::mapComplexUnique() { std::string funct = "mapComplexUnique()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 5); std::map result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result.size() == 2); } void SQLExecutor::multiMapComplex() { std::string funct = "multiMapComplex()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 5); std::multimap result; try { session() << "SELECT * FROM Person", into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result.size() == people.size()); } void SQLExecutor::selectIntoSingle() { std::string funct = "selectIntoSingle()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; try { session() << "SELECT * FROM Person ORDER BY LastName", into(result), limit(1), now; }// will return 1 object into one single result catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result == p1); } void SQLExecutor::selectIntoSingleStep() { std::string funct = "selectIntoSingleStep()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1)); stmt.execute(); assertTrue (result == p1); assertTrue (!stmt.done()); stmt.execute(); assertTrue (result == p2); assertTrue (stmt.done()); } void SQLExecutor::selectIntoSingleFail() { std::string funct = "selectIntoSingleFail()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), limit(2, true), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; try { session() << "SELECT * FROM Person", into(result), limit(1, true), now; // will fail now fail("hardLimit is set: must fail"); } catch(Poco::Data::LimitException&) { } } void SQLExecutor::lowerLimitOk() { std::string funct = "lowerLimitOk()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; try { session() << "SELECT * FROM Person", into(result), lowerLimit(2), now; // will return 2 objects into one single result but only room for one! fail("Not enough space for results"); } catch(Poco::Exception&) { } } void SQLExecutor::singleSelect() { std::string funct = "singleSelect()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1)); stmt.execute(); assertTrue (result == p1); assertTrue (!stmt.done()); stmt.execute(); assertTrue (result == p2); assertTrue (stmt.done()); } void SQLExecutor::lowerLimitFail() { std::string funct = "lowerLimitFail()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; try { session() << "SELECT * FROM Person", into(result), lowerLimit(3), now; // will fail fail("should fail. not enough data"); } catch(Poco::Exception&) { } } void SQLExecutor::combinedLimits() { std::string funct = "combinedLimits()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::vector result; try { session() << "SELECT * FROM Person", into(result), lowerLimit(2), upperLimit(2), now; }// will return 2 objects catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result.size() == 2); assertTrue (result[0] == p1); assertTrue (result[1] == p2); } void SQLExecutor::ranges() { std::string funct = "range()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); std::vector result; try { session() << "SELECT * FROM Person", into(result), range(2, 2), now; }// will return 2 objects catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (result.size() == 2); assertTrue (result[0] == p1); assertTrue (result[1] == p2); } void SQLExecutor::combinedIllegalLimits() { std::string funct = "combinedIllegalLimits()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; try { session() << "SELECT * FROM Person", into(result), lowerLimit(3), upperLimit(2), now; fail("lower > upper is not allowed"); } catch(LimitException&) { } } void SQLExecutor::illegalRange() { std::string funct = "illegalRange()"; std::multimap people; Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 2); Person result; try { session() << "SELECT * FROM Person", into(result), range(3, 2), now; fail("lower > upper is not allowed"); } catch(LimitException&) { } } void SQLExecutor::emptyDB() { std::string funct = "emptyDB()"; int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 0); Person result; Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1)); stmt.execute(); assertTrue (result.firstName.empty()); assertTrue (stmt.done()); } void SQLExecutor::blob(int bigSize, const std::string& blobPlaceholder) { std::string funct = "blob()"; std::string lastName("lastname"); std::string firstName("firstname"); std::string address("Address"); CLOB img("0123456789", 10); int count = 0; try { session() << format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), use(lastName), use(firstName), use(address), use(img), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); CLOB res; assertTrue (res.size() == 0); try { session() << "SELECT Image FROM Person", into(res), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (res == img); CLOB big; std::vector v(bigSize, 'x'); big.assignRaw(&v[0], v.size()); assertTrue (big.size() == bigSize); try { session() << "DELETE FROM Person", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), use(lastName), use(firstName), use(address), use(big), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT Image FROM Person", into(res), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (res == big); } void SQLExecutor::blobStmt() { std::string funct = "blobStmt()"; std::string lastName("lastname"); std::string firstName("firstname"); std::string address("Address"); CLOB blob("0123456789", 10); int count = 0; Statement ins = (session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(blob)); ins.execute(); try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); CLOB res; poco_assert (res.size() == 0); Statement stmt = (session() << "SELECT Image FROM Person", into(res)); try { stmt.execute(); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } poco_assert (res == blob); } void SQLExecutor::dateTime() { std::string funct = "dateTime()"; std::string lastName("lastname"); std::string firstName("firstname"); std::string address("Address"); DateTime born(1965, 6, 18, 5, 35, 1); int count = 0; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(born), now; } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } assertTrue (count == 1); DateTime res; try { session() << "SELECT Born FROM Person", into(res), now; } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } assertTrue (res == born); Statement stmt = (session() << "SELECT Born FROM Person", now); RecordSet rset(stmt); res = rset["Born"].convert(); assertTrue (res == born); } void SQLExecutor::date() { std::string funct = "date()"; std::string lastName("lastname"); std::string firstName("firstname"); std::string address("Address"); Date bornDate(1965, 6, 18); int count = 0; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(bornDate), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); Date d; Time t; try { session() << "SELECT BornDate FROM Person", into(d), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (d == bornDate); Statement stmt = (session() << "SELECT BornDate FROM Person", now); RecordSet rset(stmt); DateTime dt1 = rset["BornDate"].convert(); Date d2(dt1); assertTrue (d2 == bornDate); } void SQLExecutor::time() { std::string funct = "time()"; std::string lastName("lastname"); std::string firstName("firstname"); std::string address("Address"); Time bornTime (5, 35, 1); int count = 0; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(bornTime), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); Date d; Time t; try { session() << "SELECT BornTime FROM Person", into(t), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (t == bornTime); Statement stmt = (session() << "SELECT BornTime FROM Person", now); RecordSet rset(stmt); DateTime dt2 = rset["BornTime"].convert(); Time t2(dt2); assertTrue (t2 == bornTime); } void SQLExecutor::tuples() { typedef Tuple TupleType; std::string funct = "tuples()"; TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19); try { session() << "INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(t), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } TupleType ret(-10,-11,-12,-13,-14,-15,-16,-17,-18,-19); assertTrue (ret != t); try { session() << "SELECT * FROM Tuples", into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ret == t); } void SQLExecutor::tupleVector() { typedef Tuple TupleType; std::string funct = "tupleVector()"; TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19); Tuple t10(10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29); TupleType t100(100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119); std::vector v; v.push_back(t); v.push_back(t10); v.push_back(t100); try { session() << "INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; try { session() << "SELECT COUNT(*) FROM Tuples", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (v.size() == count); std::vector > ret; try { session() << "SELECT * FROM Tuples", into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (ret == v); } void SQLExecutor::internalExtraction() { std::string funct = "internalExtraction()"; std::vector > v; v.push_back(Tuple(1, 1.5f, "3")); v.push_back(Tuple(2, 2.5f, "4")); v.push_back(Tuple(3, 3.5f, "5")); v.push_back(Tuple(4, 4.5f, "6")); try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { Statement stmt = (session() << "SELECT * FROM Vectors", now); RecordSet rset(stmt); assertTrue (3 == rset.columnCount()); assertTrue (4 == rset.rowCount()); int curVal = 3; do { assertTrue (rset["str0"] == curVal); ++curVal; } while (rset.moveNext()); rset.moveFirst(); assertTrue (rset["str0"] == "3"); rset.moveLast(); assertTrue (rset["str0"] == "6"); RecordSet rset2(rset); assertTrue (3 == rset2.columnCount()); assertTrue (4 == rset2.rowCount()); int i = rset.value(0,0); assertTrue (1 == i); std::string s = rset.value(0,0).convert(); assertTrue ("1" == s); int a = rset.value(0,2); assertTrue (3 == a); try { double d = rset.value(1,1); assertTrue (2.5 == d); } catch (BadCastException&) { float f = rset.value(1,1); assertTrue (2.5 == f); } try { s = rset.value(2, 2); } catch (BadCastException&) { UTF16String us = rset.value(2, 2); Poco::UnicodeConverter::convert(us, s); } assertTrue ("5" == s); i = rset.value("str0", 2); assertTrue (5 == i); const Column >& col = rset.column >(0); Column >::Iterator it = col.begin(); Column >::Iterator end = col.end(); for (int i = 1; it != end; ++it, ++i) assertTrue (*it == i); rset = (session() << "SELECT COUNT(*) AS cnt FROM Vectors", now); //various results for COUNT(*) are received from different drivers try { //this is what most drivers will return int i = rset.value(0,0); assertTrue (4 == i); } catch(BadCastException&) { try { //this is for Oracle double i = rset.value(0,0); assertTrue (4 == int(i)); } catch(BadCastException&) { //this is for PostgreSQL Poco::Int64 big = rset.value(0,0); assertTrue (4 == big); } } s = rset.value("cnt", 0).convert(); assertTrue ("4" == s); try { rset.column >(100); fail ("must fail"); } catch (RangeException&) { } try { rset.value(0,0); fail ("must fail"); } catch (BadCastException&) { } stmt = (session() << "DELETE FROM Vectors", now); rset = stmt; try { rset.column >(0); fail ("must fail"); } catch (RangeException&) { } } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } } void SQLExecutor::filter(const std::string& query, const std::string& intFldName) { std::string funct = "filter()"; std::vector > v; v.push_back(Tuple(1, 1.5f, "3")); v.push_back(Tuple(2, 2.5f, "4")); v.push_back(Tuple(3, 3.5f, "5")); v.push_back(Tuple(4, 4.5f, "6")); try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { Statement stmt = (session() << query, now); RecordSet rset(stmt); assertTrue (rset.totalRowCount() == 4); RowFilter::Ptr pRF = new RowFilter(&rset); assertTrue (pRF->isEmpty()); pRF->add(intFldName, RowFilter::VALUE_EQUAL, 1); assertTrue (!pRF->isEmpty()); Var da; try { da = rset.value(0, 1); fail ("must fail"); } catch (InvalidAccessException&) { da = rset.value(0, 1, false); assertTrue (2 == da); da = rset.value(0, 0); assertTrue (1 == da); } assertTrue (rset.rowCount() == 1); assertTrue (rset.moveFirst()); assertTrue (1 == rset[intFldName]); assertTrue (!rset.moveNext()); pRF->add("flt0", RowFilter::VALUE_LESS_THAN_OR_EQUAL, 3.5f); assertTrue (rset.rowCount() == 3); assertTrue (rset.moveNext()); assertTrue (2.5 == rset["flt0"]); assertTrue (rset.moveNext()); assertTrue (3.5 == rset["flt0"]); assertTrue (!rset.moveNext()); pRF->add("str0", RowFilter::VALUE_EQUAL, 6); assertTrue (rset.rowCount() == 4); assertTrue (rset.moveLast()); assertTrue ("6" == rset["str0"]); pRF->remove("flt0"); assertTrue (rset.rowCount() == 2); assertTrue (rset.moveFirst()); assertTrue ("3" == rset["str0"]); assertTrue (rset.moveNext()); assertTrue ("6" == rset["str0"]); pRF->remove(intFldName); pRF->remove("str0"); assertTrue (pRF->isEmpty()); pRF->add("str0", "!=", 3); assertTrue (rset.rowCount() == 3); RowFilter::Ptr pRF1 = new RowFilter(pRF, RowFilter::OP_AND); pRF1->add(intFldName, "==", 2); assertTrue (rset.rowCount() == 1); pRF1->add(intFldName, "<", 2); assertTrue (rset.rowCount() == 1); pRF1->add(intFldName, ">", 3); assertTrue (rset.rowCount() == 2); pRF->removeFilter(pRF1); pRF->remove("str0"); assertTrue (pRF->isEmpty()); assertTrue (rset.rowCount() == 4); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } } void SQLExecutor::internalBulkExtraction() { std::string funct = "internalBulkExtraction()"; int size = 100; std::vector lastName(size); std::vector firstName(size); std::vector address(size); std::vector age(size); for (int i = 0; i < size; ++i) { lastName[i] = "LN" + NumberFormatter::format(i); firstName[i] = "FN" + NumberFormatter::format(i); address[i] = "Addr" + NumberFormatter::format(i); age[i] = i; } try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName, bulk), use(firstName, bulk), use(address, bulk), use(age, bulk), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now); RecordSet rset(stmt); assertTrue (size == rset.rowCount()); assertTrue ("LN0" == rset["LastName"]); assertTrue (0 == rset["Age"]); rset.moveNext(); assertTrue ("LN1" == rset["LastName"]); assertTrue (1 == rset["Age"]); rset.moveLast(); assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]); assertTrue (size - 1 == rset["Age"]); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now); RecordSet rset(stmt); assertTrue (size == rset.rowCount()); assertTrue ("LN0" == rset["LastName"]); assertTrue (0 == rset["Age"]); rset.moveLast(); assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]); assertTrue (size - 1 == rset["Age"]); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } } void SQLExecutor::internalBulkExtractionUTF16() { std::string funct = "internalBulkExtraction()"; int size = 100; std::vector lastName(size); std::vector firstName(size); std::vector address(size); std::vector age(size); for (int i = 0; i < size; ++i) { lastName[i] = Poco::UnicodeConverter::to("LN" + NumberFormatter::format(i)); firstName[i] = Poco::UnicodeConverter::to("FN" + NumberFormatter::format(i)); address[i] = Poco::UnicodeConverter::to("Addr" + NumberFormatter::format(i)); age[i] = i; } try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName, bulk), use(firstName, bulk), use(address, bulk), use(age, bulk), now; } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } try { Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now); RecordSet rset(stmt); assertTrue (size == rset.rowCount()); assertTrue (Poco::UnicodeConverter::to("LN0") == rset["LastName"]); assertTrue (0 == rset["Age"]); rset.moveNext(); assertTrue (Poco::UnicodeConverter::to("LN1") == rset["LastName"]); assertTrue (1 == rset["Age"]); rset.moveLast(); assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]); assertTrue (size - 1 == rset["Age"]); } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } try { Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now); RecordSet rset(stmt); assertTrue (size == rset.rowCount()); assertTrue ("LN0" == rset["LastName"]); assertTrue (0 == rset["Age"]); rset.moveLast(); assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]); assertTrue (size - 1 == rset["Age"]); } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } } void SQLExecutor::internalStorageType() { std::string funct = "internalStorageType()"; std::vector manips; manips.push_back(list); manips.push_back(deque); manips.push_back(vector); std::vector > v; v.push_back(Tuple(1, 1.5f, "3")); v.push_back(Tuple(2, 2.5f, "4")); v.push_back(Tuple(3, 3.5f, "5")); v.push_back(Tuple(4, 4.5f, "6")); try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { std::vector::iterator it = manips.begin(); std::vector::iterator end = manips.end(); for (; it != end; ++it) { Statement stmt = (session() << "SELECT * FROM Vectors", *it, now); RecordSet rset(stmt); assertTrue (3 == rset.columnCount()); assertTrue (4 == rset.rowCount()); int curVal = 3; do { assertTrue (rset["str0"] == curVal); ++curVal; } while (rset.moveNext()); rset.moveFirst(); assertTrue (rset["str0"] == "3"); rset.moveLast(); assertTrue (rset["str0"] == "6"); try { stmt = (session() << "SELECT * FROM Vectors", now, *it); fail ("must fail"); } catch(InvalidAccessException&){} try { stmt = (session() << "SELECT * FROM Vectors", into(v), now, *it); fail ("must fail"); } catch(InvalidAccessException&){} try { stmt = (session() << "SELECT * FROM Vectors", into(v), *it, now); fail ("must fail"); } catch(InvalidAccessException&){} } } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } } void SQLExecutor::notNulls(const std::string& sqlState) { try { session() << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; fail ("must fail"); }catch (StatementException& se) { //double check if we're failing for the right reason //default sqlState value is "23502"; some drivers report "HY???" codes if (se.diagnostics().fields().size()) { std::string st = se.diagnostics().sqlState(0); if (sqlState != st) std::cerr << '[' << name() << ']' << " Warning: expected SQL state [" << sqlState << "], received [" << se.diagnostics().sqlState(0) << "] instead." << std::endl; } } } void SQLExecutor::nulls() { std::string funct = "nulls()"; try { session() << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } RecordSet rs(session(), "SELECT * FROM NullTest"); assertTrue (1 == rs.rowCount()); rs.moveFirst(); assertTrue (rs.isNull("i")); assertTrue (rs["i"] != 0); assertTrue (rs.isNull("r")); assertTrue (rs.isNull("v")); assertTrue (rs["v"] != ""); assertTrue (rs.nvl("i") == 0); assertTrue (rs.nvl("i", -1) == -1); assertTrue (rs.nvl("r") == double()); assertTrue (rs.nvl("r", -1.5) == -1.5); assertTrue (rs.nvl("v") == ""); assertTrue (rs.nvl("v", "123") == "123"); try { session() << "DELETE FROM NullTest", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int i = 1; double f = 1.5; std::string s = "123"; try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(f), use(s), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } rs = (session() << "SELECT * FROM NullTest", now); assertTrue (1 == rs.rowCount()); rs.moveFirst(); assertTrue (!rs.isNull("i")); assertTrue (rs["i"] == 1); assertTrue (!rs.isNull("v")); assertTrue (!rs.isNull("r")); assertTrue (rs["v"] == "123"); assertTrue (rs.nvl("i") == 1); assertTrue (rs.nvl("i", -1) == 1); assertTrue (rs.nvl("r") == 1.5); assertTrue (rs.nvl("r", -1.5) == 1.5); assertTrue (rs.nvl("v") == "123"); assertTrue (rs.nvl("v", "456") == "123"); try { session() << "UPDATE NullTest SET v = ? WHERE i = ?", use(null), use(i), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } i = 2; f = 3.4; try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(null), use(null), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } rs = (session() << "SELECT i, r, v FROM NullTest ORDER BY i ASC", now); assertTrue (2 == rs.rowCount()); rs.moveFirst(); assertTrue (!rs.isNull("i")); assertTrue (rs["i"] == 1); assertTrue (!rs.isNull("r")); assertTrue (rs.isNull("v")); assertTrue (rs["v"] != ""); assertTrue (rs.moveNext()); assertTrue (!rs.isNull("i")); assertTrue (rs["i"] == 2); assertTrue (rs.isNull("r")); assertTrue (rs.isNull("v")); assertTrue (rs["v"] != ""); try { session() << "DELETE FROM NullTest", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "INSERT INTO NullTest (v) VALUES (?)", bind(""), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } bool esin = session().getFeature("emptyStringIsNull"); session().setFeature("emptyStringIsNull", true); try { session().setFeature("forceEmptyString", true); fail ("must fail"); } catch (InvalidAccessException&) { } bool fes = session().getFeature("forceEmptyString"); session().setFeature("forceEmptyString", false); RecordSet rs1(session(), "SELECT v FROM NullTest"); assertTrue (1 == rs1.rowCount()); rs1.moveFirst(); assertTrue (rs1.isNull("v")); assertTrue (!(rs["v"] == "")); session().setFeature("emptyStringIsNull", false); session().setFeature("forceEmptyString", true); RecordSet rs2(session(), "SELECT v FROM NullTest"); assertTrue (1 == rs2.rowCount()); rs2.moveFirst(); assertTrue (!rs2.isNull("v")); assertTrue ((rs2["v"] == "")); try { session().setFeature("emptyStringIsNull", true); fail ("must fail"); } catch (InvalidAccessException&) { } session().setFeature("emptyStringIsNull", esin); session().setFeature("forceEmptyString", fes); } void SQLExecutor::rowIterator() { std::string funct = "rowIterator()"; std::vector > v; v.push_back(Tuple(1, 1.5f, "3")); v.push_back(Tuple(2, 2.5f, "4")); v.push_back(Tuple(3, 3.5f, "5")); v.push_back(Tuple(4, 4.5f, "6")); try { session() << "DELETE FROM Vectors", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } RecordSet rset0(session(), "SELECT * FROM Vectors"); assertTrue (rset0.begin() == rset0.end()); try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } RecordSet rset(session(), "SELECT * FROM Vectors"); std::ostringstream osLoop; RecordSet::Iterator it = rset.begin(); RecordSet::Iterator end = rset.end(); for (int i = 1; it != end; ++it, ++i) { assertTrue (it->get(0) == i); osLoop << *it; } assertTrue (!osLoop.str().empty()); std::ostringstream osCopy; std::copy(rset.begin(), rset.end(), std::ostream_iterator(osCopy)); assertTrue (osLoop.str() == osCopy.str()); RowFilter::Ptr pRF = new RowFilter(&rset); assertTrue (pRF->isEmpty()); pRF->add("str0", RowFilter::VALUE_EQUAL, "3"); assertTrue (!pRF->isEmpty()); it = rset.begin(); end = rset.end(); for (int i = 1; it != end; ++it, ++i) { assertTrue (it->get(0) == i); assertTrue (1 == i); } } void SQLExecutor::stdVectorBool() { std::string funct = "stdVectorBool()"; bool b = false; try { session() << "INSERT INTO BoolTest VALUES (?)", use(b), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } b = true; session() << "SELECT * FROM BoolTest", into(b), now; assertTrue (false == b); session() << "DELETE FROM BoolTest", now; b = true; try { session() << "INSERT INTO BoolTest VALUES (?)", use(b), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } b = false; session() << "SELECT * FROM BoolTest", into(b), now; assertTrue (true == b); session() << "DELETE FROM BoolTest", now; std::vector v; v.push_back(true); v.push_back(false); v.push_back(false); v.push_back(true); try { session() << "INSERT INTO BoolTest VALUES (?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } v.clear(); session() << "SELECT * FROM BoolTest", into(v), now; assertTrue (4 == v.size()); std::vector::iterator it = v.begin(); std::vector::iterator end = v.end(); int t = 0; for (; it != end; ++it) t += *it ? 1 : 0; assertTrue (2 == t); try { session() << "SELECT * FROM BoolTest WHERE b = ?", out(v), now; fail("must fail"); } catch (BindingException&) { } try { session() << "SELECT * FROM BoolTest WHERE b = ?", io(v), now; fail("must fail"); } catch (BindingException&) { } RecordSet rset(session(), "SELECT * FROM BoolTest"); t = 0; for (int i = 0; i < 4; ++i) t += rset.value(0, i) ? 1 : 0; assertTrue (2 == t); } void SQLExecutor::asynchronous(int rowCount) { Session tmp = session(); std::vector data(rowCount); Statement stmt = (tmp << "INSERT INTO Strings VALUES(?)", use(data)); Statement::Result result = stmt.executeAsync(); assertTrue (!stmt.isAsync()); result.wait(); Statement stmt1 = (tmp << "SELECT * FROM Strings", into(data), async, now); assertTrue (stmt1.isAsync()); assertTrue (stmt1.wait() == rowCount); // +++ if this part of the test case fails, increase the rowCount until achieved // that first execute is still executing when the second one is called stmt1.execute(); try { stmt1.execute(); fail ("execute() must fail"); } catch (InvalidAccessException&) { stmt1.wait(); stmt1.execute(); stmt1.wait(); } // --- stmt = tmp << "SELECT * FROM Strings", into(data), async, now; assertTrue (stmt.isAsync()); stmt.wait(); assertTrue (stmt.execute() == 0); // +++ if this part of the test case fails, increase the rowCount until achieved // that first execute is still executing when the second one is called try { result = stmt.executeAsync(); fail ("executeAsync() must fail"); } catch (InvalidAccessException&) { assertTrue (stmt.isAsync()); stmt.wait(); result = stmt.executeAsync(); } // --- assertTrue (stmt.wait() == rowCount); assertTrue (result.data() == rowCount); stmt.setAsync(false); assertTrue (!stmt.isAsync()); assertTrue (stmt.execute() == rowCount); stmt = tmp << "SELECT * FROM Strings", into(data), sync, now; assertTrue (!stmt.isAsync()); assertTrue (stmt.wait() == 0); assertTrue (stmt.execute() == rowCount); result = stmt.executeAsync(); assertTrue (!stmt.isAsync()); result.wait(); assertTrue (result.data() == rowCount); assertTrue (0 == rowCount % 10); int step = (int) (rowCount/10); data.clear(); Statement stmt2 = (tmp << "SELECT * FROM Strings", into(data), async, limit(step)); assertTrue (data.size() == 0); assertTrue (!stmt2.done()); std::size_t rows = 0; for (int i = 0; !stmt2.done(); i += step) { stmt2.execute(); rows = stmt2.wait(); assertTrue (step == rows); assertTrue (step + i == data.size()); } assertTrue (stmt2.done()); assertTrue (rowCount == data.size()); stmt2 = tmp << "SELECT * FROM Strings", reset; assertTrue (!stmt2.isAsync()); assertTrue ("deque" == stmt2.getStorage()); assertTrue (stmt2.execute() == rowCount); } void SQLExecutor::any() { Any i = 42; Any f = 42.5; std::string ss("42"); Any s = ss; #ifdef POCO_ODBC_UNICODE UTF16String us; Poco::UnicodeConverter::convert(ss, us); s = us; #endif Session tmp = session(); tmp << "INSERT INTO Anys VALUES (?, ?, ?)", use(i), use(f), use(s), now; int count = 0; tmp << "SELECT COUNT(*) FROM Anys", into(count), now; assertTrue (1 == count); i = 0; f = 0.0; s = std::string(""); tmp << "SELECT * FROM Anys", into(i), into(f), into(s), now; assertTrue (AnyCast(i) == 42); assertTrue (AnyCast(f) == 42.5); #ifdef POCO_ODBC_UNICODE // drivers may behave differently here try { assertTrue (AnyCast(s) == us); } catch (BadCastException&) { assertTrue (AnyCast(s) == "42"); } #else assertTrue (AnyCast(s) == "42"); #endif } void SQLExecutor::dynamicAny() { Var i = 42; Var f = 42.5; Var s = "42"; Session tmp = session(); tmp << "INSERT INTO Anys VALUES (?, ?, ?)", use(i), use(f), use(s), now; int count = 0; tmp << "SELECT COUNT(*) FROM Anys", into(count), now; assertTrue (1 == count); i = 0; f = 0.0; s = std::string(""); tmp << "SELECT * FROM Anys", into(i), into(f), into(s), now; assertTrue (42 == i); assertTrue (42.5 == f); assertTrue ("42" == s); } void SQLExecutor::multipleResults(const std::string& sql) { typedef Tuple Person; std::vector people; people.push_back(Person("Simpson", "Homer", "Springfield", 42)); people.push_back(Person("Simpson", "Marge", "Springfield", 38)); people.push_back(Person("Simpson", "Bart", "Springfield", 10)); people.push_back(Person("Simpson", "Lisa", "Springfield", 8)); people.push_back(Person("Simpson", "Maggie", "Springfield", 3)); session() << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now; Person pHomer; int aHomer = 42, aLisa = 8; Poco::UInt32 aBart = 0; Poco::UInt32 pos1 = 1; int pos2 = 2; std::vector people2; Statement stmt(session()); stmt << sql, into(pHomer, from(0)), use(aHomer) , into(aBart, pos1) , into(people2, from(pos2)), use(aLisa), use(aHomer); assertTrue (4 == stmt.execute()); assertTrue (Person("Simpson", "Homer", "Springfield", 42) == pHomer); assertTrue (10 == aBart); assertTrue (2 == people2.size()); assertTrue (Person("Simpson", "Lisa", "Springfield", 8) == people2[0]); assertTrue (Person("Simpson", "Homer", "Springfield", 42) == people2[1]); } void SQLExecutor::sqlChannel(const std::string& connect) { try { AutoPtr pChannel = new SQLChannel(Poco::Data::ODBC::Connector::KEY, connect, "TestSQLChannel"); pChannel->setProperty("keep", "2 seconds"); Message msgInf("InformationSource", "a Informational async message", Message::PRIO_INFORMATION); pChannel->log(msgInf); Message msgWarn("WarningSource", "b Warning async message", Message::PRIO_WARNING); pChannel->log(msgWarn); pChannel->wait(); pChannel->setProperty("async", "false"); Message msgInfS("InformationSource", "c Informational sync message", Message::PRIO_INFORMATION); pChannel->log(msgInfS); Message msgWarnS("WarningSource", "d Warning sync message", Message::PRIO_WARNING); pChannel->log(msgWarnS); RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text"); assertTrue (4 == rs.rowCount()); assertTrue ("InformationSource" == rs["Source"]); assertTrue ("a Informational async message" == rs["Text"]); rs.moveNext(); assertTrue ("WarningSource" == rs["Source"]); assertTrue ("b Warning async message" == rs["Text"]); rs.moveNext(); assertTrue ("InformationSource" == rs["Source"]); assertTrue ("c Informational sync message" == rs["Text"]); rs.moveNext(); assertTrue ("WarningSource" == rs["Source"]); assertTrue ("d Warning sync message" == rs["Text"]); Thread::sleep(3000); Message msgInfA("InformationSource", "e Informational sync message", Message::PRIO_INFORMATION); pChannel->log(msgInfA); Message msgWarnA("WarningSource", "f Warning sync message", Message::PRIO_WARNING); pChannel->log(msgWarnA); RecordSet rs1(session(), "SELECT * FROM T_POCO_LOG_ARCHIVE"); assertTrue (4 == rs1.rowCount()); pChannel->setProperty("keep", ""); assertTrue ("forever" == pChannel->getProperty("keep")); RecordSet rs2(session(), "SELECT * FROM T_POCO_LOG ORDER by Text"); assertTrue (2 == rs2.rowCount()); assertTrue ("InformationSource" == rs2["Source"]); assertTrue ("e Informational sync message" == rs2["Text"]); rs2.moveNext(); assertTrue ("WarningSource" == rs2["Source"]); assertTrue ("f Warning sync message" == rs2["Text"]); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("sqlChannel()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("sqlChannel()"); } } void SQLExecutor::sqlLogger(const std::string& connect) { try { Logger& root = Logger::root(); root.setChannel(new SQLChannel(Poco::Data::ODBC::Connector::KEY, connect, "TestSQLChannel")); root.setLevel(Message::PRIO_INFORMATION); root.information("a Informational message"); root.warning("b Warning message"); root.debug("Debug message"); Thread::sleep(100); RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text"); assertTrue (2 == rs.rowCount()); assertTrue ("TestSQLChannel" == rs["Source"]); assertTrue ("a Informational message" == rs["Text"]); rs.moveNext(); assertTrue ("TestSQLChannel" == rs["Source"]); assertTrue ("b Warning message" == rs["Text"]); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("sqlLogger()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("sqlLogger()"); } } void SQLExecutor::setTransactionIsolation(Session& session, Poco::UInt32 ti) { if (session.hasTransactionIsolation(ti)) { std::string funct = "setTransactionIsolation()"; try { Transaction t(session, false); t.setIsolation(ti); assertTrue (ti == t.getIsolation()); assertTrue (t.isIsolation(ti)); assertTrue (ti == session.getTransactionIsolation()); assertTrue (session.isTransactionIsolation(ti)); } catch(Poco::Exception& e){ std::cout << funct << ':' << e.displayText() << std::endl;} } else { std::cerr << '[' << name() << ']' << " Warning, transaction isolation not supported: "; switch (ti) { case Session::TRANSACTION_READ_COMMITTED: std::cerr << "READ COMMITTED"; break; case Session::TRANSACTION_READ_UNCOMMITTED: std::cerr << "READ UNCOMMITTED"; break; case Session::TRANSACTION_REPEATABLE_READ: std::cerr << "REPEATABLE READ"; break; case Session::TRANSACTION_SERIALIZABLE: std::cerr << "SERIALIZABLE"; break; default: std::cerr << "UNKNOWN"; break; } std::cerr << std::endl; } } void SQLExecutor::sessionTransaction(const std::string& connect) { if (!session().canTransact()) { std::cout << "Session not capable of transactions." << std::endl; return; } Session local("odbc", connect); local.setFeature("autoCommit", true); std::string funct = "transaction()"; std::vector lastNames; std::vector firstNames; std::vector addresses; std::vector ages; std::string tableName("Person"); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); firstNames.push_back("FN2"); addresses.push_back("ADDR1"); addresses.push_back("ADDR2"); ages.push_back(1); ages.push_back(2); int count = 0, locCount = 0; std::string result; bool autoCommit = session().getFeature("autoCommit"); session().setFeature("autoCommit", true); assertTrue (!session().isTransaction()); session().setFeature("autoCommit", false); assertTrue (!session().isTransaction()); setTransactionIsolation(session(), Session::TRANSACTION_READ_UNCOMMITTED); setTransactionIsolation(session(), Session::TRANSACTION_REPEATABLE_READ); setTransactionIsolation(session(), Session::TRANSACTION_SERIALIZABLE); setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED); session().begin(); assertTrue (session().isTransaction()); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (session().isTransaction()); Statement stmt = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == count); assertTrue (session().isTransaction()); session().rollback(); assertTrue (!session().isTransaction()); stmt.wait(); assertTrue (0 == locCount); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); assertTrue (!session().isTransaction()); session().begin(); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (session().isTransaction()); Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); session().commit(); assertTrue (!session().isTransaction()); stmt1.wait(); assertTrue (2 == locCount); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == count); session().setFeature("autoCommit", autoCommit); } void SQLExecutor::transaction(const std::string& connect) { if (!session().canTransact()) { std::cout << "Session not transaction-capable." << std::endl; return; } Session local("odbc", connect); local.setFeature("autoCommit", true); setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED); if (local.hasTransactionIsolation(Session::TRANSACTION_READ_UNCOMMITTED)) setTransactionIsolation(local, Session::TRANSACTION_READ_UNCOMMITTED); else if (local.hasTransactionIsolation(Session::TRANSACTION_READ_COMMITTED)) setTransactionIsolation(local, Session::TRANSACTION_READ_COMMITTED); std::string funct = "transaction()"; std::vector lastNames; std::vector firstNames; std::vector addresses; std::vector ages; std::string tableName("Person"); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); firstNames.push_back("FN2"); addresses.push_back("ADDR1"); addresses.push_back("ADDR2"); ages.push_back(1); ages.push_back(2); int count = 0, locCount = 0; std::string result; bool autoCommit = session().getFeature("autoCommit"); session().setFeature("autoCommit", true); assertTrue (!session().isTransaction()); session().setFeature("autoCommit", false); assertTrue (!session().isTransaction()); session().setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED); { Transaction trans(session()); assertTrue (trans.isActive()); assertTrue (session().isTransaction()); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (session().isTransaction()); assertTrue (trans.isActive()); try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == count); assertTrue (session().isTransaction()); assertTrue (trans.isActive()); } assertTrue (!session().isTransaction()); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); assertTrue (!session().isTransaction()); { Transaction trans(session()); try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); assertTrue (session().isTransaction()); assertTrue (trans.isActive()); trans.commit(); assertTrue (!session().isTransaction()); assertTrue (!trans.isActive()); stmt1.wait(); assertTrue (2 == locCount); } try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == count); try { session() << "DELETE FROM Person", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } Statement stmt1 = (local << "SELECT count(*) FROM Person", into(locCount), async, now); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); try { stmt1.wait(5000); if (local.getTransactionIsolation() == Session::TRANSACTION_READ_UNCOMMITTED) assertTrue (0 == locCount); } catch (TimeoutException&) { std::cerr << '[' << name() << ']' << " Warning: async query timed out." << std::endl; } session().commit(); // repeat for those that don't support uncommitted read isolation if (local.getTransactionIsolation() == Session::TRANSACTION_READ_COMMITTED) { stmt1.wait(); local << "SELECT count(*) FROM Person", into(locCount), now; assertTrue (0 == locCount); } std::string sql1 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[0], firstNames[0], addresses[0], ages[0]); std::string sql2 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[1], firstNames[1], addresses[1], ages[1]); std::vector sql; sql.push_back(sql1); sql.push_back(sql2); Transaction trans(session()); trans.execute(sql1, false); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (1 == count); trans.execute(sql2, false); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == count); Statement stmt2 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); trans.rollback(); stmt2.wait(); assertTrue (0 == locCount); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); trans.execute(sql); Statement stmt3 = (local << "SELECT COUNT(*) FROM Person", into(locCount), now); assertTrue (2 == locCount); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (2 == count); session().setFeature("autoCommit", autoCommit); } struct TestCommitTransactor { void operator () (Session& session) const { session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now; } }; struct TestRollbackTransactor { void operator () (Session& session) const { session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now; throw Poco::Exception("test"); } }; void SQLExecutor::transactor() { std::string funct = "transaction()"; int count = 0; bool autoCommit = session().getFeature("autoCommit"); session().setFeature("autoCommit", false); session().setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED); TestCommitTransactor ct; Transaction t1(session(), ct); try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (1 == count); try { session() << "DELETE FROM Person", now; session().commit();} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); try { TestRollbackTransactor rt; Transaction t(session(), rt); fail ("must fail"); } catch (Poco::Exception&) { } try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); try { TestRollbackTransactor rt; Transaction t(session()); t.transact(rt); fail ("must fail"); } catch (Poco::Exception&) { } try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); try { TestRollbackTransactor rt; Transaction t(session(), false); t.transact(rt); fail ("must fail"); } catch (Poco::Exception&) { } try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); try { TestRollbackTransactor rt; Transaction t(session(), true); t.transact(rt); fail ("must fail"); } catch (Poco::Exception&) { } try { session() << "SELECT count(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (0 == count); session().setFeature("autoCommit", autoCommit); } void SQLExecutor::nullable() { try { session() << "INSERT INTO NullableTest VALUES(NULL, NULL, NULL, NULL)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("nullable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("nullable()"); } Nullable i = 1; Nullable f = 1.5; Nullable s = std::string("abc"); Nullable d = DateTime(); assertTrue (!i.isNull()); assertTrue (!f.isNull()); assertTrue (!s.isNull()); assertTrue (!d.isNull()); session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM NullableTest", into(s), into(i), into(f), into(d), now; assertTrue (i.isNull()); assertTrue (f.isNull()); assertTrue (s.isNull()); assertTrue (d.isNull()); RecordSet rs(session(), "SELECT * FROM NullableTest"); rs.moveFirst(); assertTrue (rs.isNull("EmptyString")); assertTrue (rs.isNull("EmptyInteger")); assertTrue (rs.isNull("EmptyFloat")); assertTrue (rs.isNull("EmptyDateTime")); Var di = 1; Var df = 1.5; Var ds = "abc"; Var dd = DateTime(); assertTrue (!di.isEmpty()); assertTrue (!df.isEmpty()); assertTrue (!ds.isEmpty()); assertTrue (!dd.isEmpty()); Statement stmt = (session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM NullableTest", into(ds), into(di), into(df), into(dd), now); assertTrue (di.isEmpty()); assertTrue (df.isEmpty()); assertTrue (ds.isEmpty()); assertTrue (dd.isEmpty()); } void SQLExecutor::reconnect() { std::string funct = "reconnect()"; std::string lastName = "lastName"; std::string firstName("firstName"); std::string address("Address"); int age = 133132; int count = 0; std::string result; try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == 1); assertTrue (session().isConnected()); session().close(); assertTrue (!session().isConnected()); try { session() << "SELECT LastName FROM Person", into(result), now; fail ("must fail"); } catch(NotConnectedException&){ } assertTrue (!session().isConnected()); session().open(); assertTrue (session().isConnected()); try { session() << "SELECT Age FROM Person", into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assertTrue (count == age); assertTrue (session().isConnected()); } void SQLExecutor::unicode(const std::string& dbConnString) { const unsigned char supp[] = { 0x41, 0x42, 0xf0, 0x90, 0x82, 0xa4, 0xf0, 0xaf, 0xa6, 0xa0, 0xf0, 0xaf, 0xa8, 0x9d, 0x00 }; std::string text((const char*) supp); UTF16String wtext; Poco::UnicodeConverter::convert(text, wtext); session() << "INSERT INTO UnicodeTable VALUES (?)", use(wtext), now; wtext.clear(); text.clear(); session() << "SELECT str FROM UnicodeTable", into(wtext), now; Poco::UnicodeConverter::convert(wtext, text); assertTrue (text == std::string((const char*)supp)); }