From 86084cb7b2c5d5a34874d130fefd1a46f1a11788 Mon Sep 17 00:00:00 2001 From: Aleksandar Fabijanic Date: Fri, 22 Dec 2023 09:27:34 +0100 Subject: [PATCH] feat(Data::AbstractSessionImpl): add autoCommit property and tests #4261 (#4262) * fix(Data::AbstracSessionImpl): protect autocommit feature handlers #4261 * chore(CI): re-enable mysql * MySQL SessionImpl: make sure autocommit mode is on when session is openend or reset. * PostgreSQL SessionImpl: reuse autocommit flag of AbstractSessionImpl. * Github workflow: re-activated linux-gcc-make-postgres * Fixed indentation in ci.yml * Fix for DataTest SQLExecutor: use connector * Data::Session: when parser is not used and autocommit mode is off, assume any SQL statement begins a transaction. * PostgreSQL: don't use SQL parser (it currently cannot handle placeholders). * PostgreSQL: added test sessionTransactionNoAutoCommit * PostgreSQL test suite: removed reference to generic SQLExecutor * PostgreSQL: fixes for sessionTransactionNoAutoCommit. * MySQL: added test sessionPoolAndUnicode (from #2801) * Fixed #define in sql-parser * Data generic testsuite: support numbered placeholders * PostgreSQL test suite: added missing include directory to Makefile. * Attempt to fix PostgreSQL Makefiles * PostgreSQL testsuite: added include path to Makefile * PostgreSQL testsuite: added PocoDataTest library to Makefile * DataTest SQLExecutor::formatSQL: don't use string_view * PostgreSQL test suite: delegated most tests to Poco::Data::Test * Makefile: added dependencies on Data-Tests * Weaken assumptions about async in generic transaction tests * Makefile: added dependency for Prometheus samples * Fix deadlock in DataTest SQLExecutor * PostgreSQL tests SQLExecutor: cleanup * feat(Data::AbstractSessionImpl): add autoCommit property and tests #4261 * Brought MySQL backend in line with _autoCommit flag of AbstractSessionImpl. --------- Co-authored-by: Friedrich Wilckens Co-authored-by: Friedrich Wilckens --- .github/workflows/ci.yml | 96 +- .../include/Poco/Data/MySQL/SessionHandle.h | 3 + Data/MySQL/src/SessionHandle.cpp | 7 + Data/MySQL/src/SessionImpl.cpp | 18 +- Data/MySQL/testsuite/src/MySQLTest.cpp | 11 +- Data/MySQL/testsuite/src/MySQLTest.h | 1 + Data/MySQL/testsuite/src/SQLExecutor.cpp | 35 +- Data/MySQL/testsuite/src/SQLExecutor.h | 3 +- Data/PostgreSQL/Makefile | 5 +- .../Poco/Data/PostgreSQL/SessionHandle.h | 9 +- .../Poco/Data/PostgreSQL/SessionImpl.h | 2 +- Data/PostgreSQL/src/SessionHandle.cpp | 16 +- Data/PostgreSQL/src/SessionImpl.cpp | 14 +- Data/PostgreSQL/testsuite/Makefile | 5 +- .../testsuite/src/PostgreSQLTest.cpp | 10 + .../PostgreSQL/testsuite/src/PostgreSQLTest.h | 2 +- Data/PostgreSQL/testsuite/src/SQLExecutor.cpp | 1182 +---------------- Data/PostgreSQL/testsuite/src/SQLExecutor.h | 4 + Data/include/Poco/Data/AbstractSessionImpl.h | 34 +- Data/src/Statement.cpp | 13 +- .../include/Poco/Data/Test/SQLExecutor.h | 6 +- Data/testsuite/DataTest/src/SQLExecutor.cpp | 229 ++-- Data/testsuite/src/DataTest.cpp | 53 + Data/testsuite/src/SessionImpl.cpp | 16 +- Data/testsuite/src/SessionImpl.h | 5 - Foundation/include/Poco/Foundation.h | 2 +- Foundation/nonexistent.txt | 0 27 files changed, 441 insertions(+), 1340 deletions(-) create mode 100644 Foundation/nonexistent.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 368495d02..f8e615bfd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -420,55 +420,55 @@ jobs: # cd cmake-build; # ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(Redis)|(MongoDB)" -C Debug -# linux-gcc-make-mysql: -# runs-on: ubuntu-22.04 -# services: -# mysql: -# image: mysql:8.1.0 -# env: -# MYSQL_ALLOW_EMPTY_PASSWORD: yes -# MYSQL_USER: pocotest -# MYSQL_PASSWORD: pocotest -# MYSQL_DATABASE: pocotest -# ports: -# - 3306:3306 -# steps: -# - uses: actions/checkout@v3 -# - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev mysql-client -# - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/PostgreSQL,Data/SQLite,Data/ODBC,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: >- -# sudo -s -# EXCLUDE_TESTS="ActiveRecord ApacheConnector CppParser CppUnit Crypto Data Data/PostgreSQL Data/ODBC Data/SQLite Encodings Foundation JSON JWT MongoDB Net NetSSL_OpenSSL NetSSL_Win PDF PageCompiler PocoDoc ProGen Prometheus Redis SevenZip Util XML Zip" -# ./ci/runtests.sh + linux-gcc-make-mysql: + runs-on: ubuntu-22.04 + services: + mysql: + image: mysql:8.1.0 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_USER: pocotest + MYSQL_PASSWORD: pocotest + MYSQL_DATABASE: pocotest + ports: + - 3306:3306 + steps: + - uses: actions/checkout@v3 + - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev mysql-client + - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/PostgreSQL,Data/SQLite,Data/ODBC,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install + - uses: ./.github/actions/retry-action + with: + timeout_minutes: 90 + max_attempts: 3 + retry_on: any + command: >- + sudo -s + EXCLUDE_TESTS="ActiveRecord ApacheConnector CppParser CppUnit Crypto Data Data/PostgreSQL Data/ODBC Data/SQLite Encodings Foundation JSON JWT MongoDB Net NetSSL_OpenSSL NetSSL_Win PDF PageCompiler PocoDoc ProGen Prometheus Redis SevenZip Util XML Zip" + ./ci/runtests.sh -# TODO tests sometimes failling on testTransaction and testReconnect -# linux-gcc-make-postgres: -# runs-on: ubuntu-22.04 -# services: -# postgres: -# image: postgres:16.0 -# env: -# POSTGRES_PASSWORD: postgres -# ports: -# - 5432:5432 -# steps: -# - uses: actions/checkout@v3 -# - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev odbc-postgresql -# - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/MySQL,Data/ODBC,Data/SQLite,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: >- -# sudo -s -# EXCLUDE_TESTS="ActiveRecord ApacheConnector CppParser CppUnit Crypto Data Data/ODBC Data/MySQL Data/SQLite Encodings Foundation JSON JWT MongoDB Net NetSSL_OpenSSL NetSSL_Win PDF PageCompiler PocoDoc ProGen Prometheus Redis SevenZip Util XML Zip" -# ./ci/runtests.sh +# TODO tests sometimes failing on testTransaction and testReconnect + linux-gcc-make-postgres: + runs-on: ubuntu-22.04 + services: + postgres: + image: postgres:16.0 + env: + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + steps: + - uses: actions/checkout@v3 + - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev odbc-postgresql + - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/MySQL,Data/ODBC,Data/SQLite,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install + - uses: ./.github/actions/retry-action + with: + timeout_minutes: 90 + max_attempts: 3 + retry_on: any + command: >- + sudo -s + EXCLUDE_TESTS="ActiveRecord ApacheConnector CppParser CppUnit Crypto Data Data/ODBC Data/MySQL Data/SQLite Encodings Foundation JSON JWT MongoDB Net NetSSL_OpenSSL NetSSL_Win PDF PageCompiler PocoDoc ProGen Prometheus Redis SevenZip Util XML Zip" + ./ci/runtests.sh linux-gcc-make-redis: runs-on: ubuntu-22.04 diff --git a/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h b/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h index 4f65ae5c0..ebfb73e9c 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h +++ b/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h @@ -67,6 +67,9 @@ public: void rollback(); /// Rollback transaction + void autoCommit(bool val); + /// Set autocommit mode + void reset(); /// Reset connection with dababase and clears session state, but without disconnecting diff --git a/Data/MySQL/src/SessionHandle.cpp b/Data/MySQL/src/SessionHandle.cpp index 5e9ab21b2..ce28a7cfb 100644 --- a/Data/MySQL/src/SessionHandle.cpp +++ b/Data/MySQL/src/SessionHandle.cpp @@ -181,6 +181,13 @@ void SessionHandle::rollback() } +void SessionHandle::autoCommit(bool val) +{ + if (mysql_autocommit(_pHandle, val) != 0) + throw TransactionException("Setting autocommit mode failed.", _pHandle); +} + + void SessionHandle::reset() { #if ((defined (MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID >= 50700)) || ((defined (MARIADB_PACKAGE_VERSION_ID)) && (MARIADB_PACKAGE_VERSION_ID >= 30000)) diff --git a/Data/MySQL/src/SessionImpl.cpp b/Data/MySQL/src/SessionImpl.cpp index dab3ada08..0dcf40a75 100644 --- a/Data/MySQL/src/SessionImpl.cpp +++ b/Data/MySQL/src/SessionImpl.cpp @@ -173,6 +173,9 @@ void SessionImpl::open(const std::string& connect) &SessionImpl::autoCommit, &SessionImpl::isAutoCommit); + // autocommit is initially on when a session is opened + AbstractSessionImpl::setAutoCommit("", true); + _connected = true; } @@ -215,18 +218,18 @@ void SessionImpl::rollback() } -void SessionImpl::autoCommit(const std::string&, bool val) +void SessionImpl::autoCommit(const std::string& s, bool val) { - StatementExecutor ex(_handle); - ex.prepare(Poco::format("SET autocommit=%d", val ? 1 : 0)); - ex.execute(); + if (val != getAutoCommit(s)) { + _handle.autoCommit(val); + AbstractSessionImpl::setAutoCommit(s, val); + } } -bool SessionImpl::isAutoCommit(const std::string&) const +bool SessionImpl::isAutoCommit(const std::string& s) const { - int ac = 0; - return 1 == getSetting("autocommit", ac); + return AbstractSessionImpl::getAutoCommit(s); } @@ -306,6 +309,7 @@ void SessionImpl::reset() if (_connected && _reset) { _handle.reset(); + AbstractSessionImpl::setAutoCommit("", true); } } diff --git a/Data/MySQL/testsuite/src/MySQLTest.cpp b/Data/MySQL/testsuite/src/MySQLTest.cpp index 2a286d35e..3ba3b153d 100644 --- a/Data/MySQL/testsuite/src/MySQLTest.cpp +++ b/Data/MySQL/testsuite/src/MySQLTest.cpp @@ -727,6 +727,15 @@ void MySQLTest::testTupleWithNullable() } +void MySQLTest::testSessionPoolAndUnicode() +{ + if (!_pSession) fail ("Test not available."); + + recreateStringsTable(); + _pExecutor->sessionPoolAndUnicode(_dbConnString); +} + + void MySQLTest::dropTable(const std::string& tableName) { try { *_pSession << format("DROP TABLE IF EXISTS %s", tableName), now; } @@ -993,6 +1002,6 @@ CppUnit::Test* MySQLTest::suite() CppUnit_addTest(pSuite, MySQLTest, testSessionTransaction); CppUnit_addTest(pSuite, MySQLTest, testTransaction); CppUnit_addTest(pSuite, MySQLTest, testReconnect); - + CppUnit_addTest(pSuite, MySQLTest, testSessionPoolAndUnicode); return pSuite; } diff --git a/Data/MySQL/testsuite/src/MySQLTest.h b/Data/MySQL/testsuite/src/MySQLTest.h index 9a2568b3d..5a1780b0c 100644 --- a/Data/MySQL/testsuite/src/MySQLTest.h +++ b/Data/MySQL/testsuite/src/MySQLTest.h @@ -107,6 +107,7 @@ public: void testTransaction(); void testReconnect(); + void testSessionPoolAndUnicode(); void setUp(); void tearDown(); diff --git a/Data/MySQL/testsuite/src/SQLExecutor.cpp b/Data/MySQL/testsuite/src/SQLExecutor.cpp index 10594be45..3803223af 100644 --- a/Data/MySQL/testsuite/src/SQLExecutor.cpp +++ b/Data/MySQL/testsuite/src/SQLExecutor.cpp @@ -21,6 +21,7 @@ #include "Poco/Data/Time.h" #include "Poco/Data/StatementImpl.h" #include "Poco/Data/RecordSet.h" +#include "Poco/Data/SessionPool.h" #include "Poco/Data/Transaction.h" #include "Poco/Data/MySQL/Connector.h" #include "Poco/Data/MySQL/MySQLException.h" @@ -1372,7 +1373,7 @@ void SQLExecutor::timestamp() std::string firstName("Simpson"); std::string address("Springfield"); DateTime birthday(1980, 4, 1, 5, 45, 12, 354, 879); - + int count = 0; try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(birthday), now; } catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } @@ -1381,14 +1382,14 @@ void SQLExecutor::timestamp() catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } assertTrue (count == 1); - + DateTime bd; assertTrue (bd != birthday); try { *_pSession << "SELECT Birthday FROM Person", into(bd), now; } catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } assertTrue (bd == birthday); - + std::cout << std::endl << RecordSet(*_pSession, "SELECT * FROM Person"); } @@ -2066,3 +2067,31 @@ void SQLExecutor::reconnect() assertTrue (count == age); assertTrue (_pSession->isConnected()); } + + +void SQLExecutor::sessionPoolAndUnicode(const std::string& connString) +{ + std::string funct = "unicode()"; + std::string text = "ěščřžťďůň"; + std::string text2; + + // Test uses session from SessionPool instead of _pSession to prove session + // obtained and returned into pool is valid. + + // Min/Max 1 session - ensures that when get() is called, same session should be returned + Poco::SharedPtr sp = new Poco::Data::SessionPool(MySQL::Connector::KEY, connString, 1, 1); + + { + Poco::Data::Session session = sp->get(); + try { session << "INSERT INTO Strings VALUES (?)", use(text), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + } // parentheses to ensure session is returned into pool + + Poco::Data::Session session2 = sp->get(); + try { session2 << "SELECT str FROM Strings", into(text2), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + assertTrue (text == text2); +} diff --git a/Data/MySQL/testsuite/src/SQLExecutor.h b/Data/MySQL/testsuite/src/SQLExecutor.h index ba300212e..511baee47 100644 --- a/Data/MySQL/testsuite/src/SQLExecutor.h +++ b/Data/MySQL/testsuite/src/SQLExecutor.h @@ -88,7 +88,7 @@ public: void longText(); #ifdef POCO_MYSQL_JSON void json(); -#endif +#endif void unsignedInts(); void floats(); void doubles(); @@ -103,6 +103,7 @@ public: void transaction(const std::string& connect); void reconnect(); + void sessionPoolAndUnicode(const std::string& connString); private: void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti); diff --git a/Data/PostgreSQL/Makefile b/Data/PostgreSQL/Makefile index 2f9f8bd9d..6cd726679 100644 --- a/Data/PostgreSQL/Makefile +++ b/Data/PostgreSQL/Makefile @@ -12,10 +12,13 @@ objects = Extractor BinaryExtractor Binder SessionImpl Connector \ PostgreSQLStatementImpl PostgreSQLException \ SessionHandle StatementExecutor PostgreSQLTypes Utility + +target_includes = $(POCO_BASE)/Data/testsuite/include ifndef POCO_DATA_NO_SQL_PARSER - target_includes = $(POCO_BASE)/Data/src + target_includes += $(POCO_BASE)/Data/src endif + target = PocoDataPostgreSQL target_version = $(LIBVERSION) target_libs = PocoData PocoFoundation diff --git a/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionHandle.h b/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionHandle.h index 2feee7776..42fd670c6 100644 --- a/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionHandle.h +++ b/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionHandle.h @@ -118,7 +118,7 @@ public: bool isAutoCommit() const; /// is the connection in auto commit mode? - void setAutoCommit(bool aShouldAutoCommit = true); + void autoCommit(bool val); /// is the connection in auto commit mode? bool isAsynchronousCommit() const; @@ -193,7 +193,6 @@ private: PGconn* _pConnection; std::string _connectionString; bool _inTransaction; - bool _isAutoCommit; bool _isAsynchronousCommit; Poco::UInt32 _tranactionIsolationLevel; std::vector _preparedStatementsToBeDeallocated; @@ -306,12 +305,6 @@ inline bool SessionHandle::isTransaction() const } -inline bool SessionHandle::isAutoCommit() const -{ - return _isAutoCommit; -} - - inline bool SessionHandle::isAsynchronousCommit() const { return _isAsynchronousCommit; diff --git a/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionImpl.h b/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionImpl.h index ea68342db..87cfd1965 100644 --- a/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionImpl.h +++ b/Data/PostgreSQL/include/Poco/Data/PostgreSQL/SessionImpl.h @@ -99,7 +99,7 @@ public: /// Returns true iff the transaction isolation level corresponds /// to the supplied bitmask. - void setAutoCommit(const std::string&, bool aValue); + void autoCommit(const std::string&, bool aValue); /// Sets autocommit property for the session. bool isAutoCommit(const std::string& aName = std::string()) const; diff --git a/Data/PostgreSQL/src/SessionHandle.cpp b/Data/PostgreSQL/src/SessionHandle.cpp index 270566f4c..f8d215a8a 100644 --- a/Data/PostgreSQL/src/SessionHandle.cpp +++ b/Data/PostgreSQL/src/SessionHandle.cpp @@ -36,7 +36,6 @@ const std::string SessionHandle::POSTGRESQL_SERIALIZABLE = "SERIALIZABLE"; SessionHandle::SessionHandle(): _pConnection(0), _inTransaction(false), - _isAutoCommit(true), _isAsynchronousCommit(false), _tranactionIsolationLevel(Session::TRANSACTION_READ_COMMITTED) { @@ -157,7 +156,6 @@ void SessionHandle::disconnect() _connectionString = std::string(); _inTransaction= false; - _isAutoCommit = true; _isAsynchronousCommit = false; _tranactionIsolationLevel = Session::TRANSACTION_READ_COMMITTED; } @@ -280,21 +278,13 @@ void SessionHandle::rollback() } -void SessionHandle::setAutoCommit(bool aShouldAutoCommit) +void SessionHandle::autoCommit(bool val) { // There is no PostgreSQL API call to switch autocommit (unchained) mode off. - if (aShouldAutoCommit == _isAutoCommit) + if (isTransaction()) { - return; + throw Poco::InvalidAccessException(); } - - if (aShouldAutoCommit) - { - if (isTransaction()) - commit(); // end any in process transaction - } - - _isAutoCommit = aShouldAutoCommit; } diff --git a/Data/PostgreSQL/src/SessionImpl.cpp b/Data/PostgreSQL/src/SessionImpl.cpp index 778616acc..56a22bf9d 100644 --- a/Data/PostgreSQL/src/SessionImpl.cpp +++ b/Data/PostgreSQL/src/SessionImpl.cpp @@ -60,6 +60,7 @@ SessionImpl::SessionImpl(const std::string& aConnectionString, std::size_t aLogi Poco::Data::AbstractSessionImpl(aConnectionString, aLoginTimeout), _connectorName("postgresql") { + setFeature("sqlParse", false); // the parse currently cannot handle the PostgreSQL placeholders $1, $2, etc. setProperty("handle", static_cast(&_sessionHandle)); setConnectionTimeout(CONNECTION_TIMEOUT_DEFAULT); open(); @@ -134,7 +135,7 @@ void SessionImpl::open(const std::string& aConnectionString) _sessionHandle.connect(createConnectionStringFromOptionsMap(optionsMap)); addFeature("autoCommit", - &SessionImpl::setAutoCommit, + &SessionImpl::autoCommit, &SessionImpl::isAutoCommit); addFeature("asynchronousCommit", @@ -206,15 +207,18 @@ void SessionImpl::rollback() } -void SessionImpl::setAutoCommit(const std::string&, bool aValue) +void SessionImpl::autoCommit(const std::string& s, bool val) { - _sessionHandle.setAutoCommit(aValue); + if (val != getAutoCommit(s)) { + _sessionHandle.autoCommit(val); + AbstractSessionImpl::setAutoCommit(s, val); + } } -bool SessionImpl::isAutoCommit(const std::string&) const +bool SessionImpl::isAutoCommit(const std::string& s) const { - return _sessionHandle.isAutoCommit(); + return AbstractSessionImpl::getAutoCommit(s); } diff --git a/Data/PostgreSQL/testsuite/Makefile b/Data/PostgreSQL/testsuite/Makefile index ebb9696e8..5b3754f86 100644 --- a/Data/PostgreSQL/testsuite/Makefile +++ b/Data/PostgreSQL/testsuite/Makefile @@ -14,11 +14,12 @@ SYSLIBS += -lpq -lz -lpthread -ldl objects = PostgreSQLTestSuite Driver PostgreSQLTest SQLExecutor ifndef POCO_DATA_NO_SQL_PARSER - target_includes = $(POCO_BASE)/Data/src + target_includes += $(POCO_BASE)/Data/src endif target = testrunner target_version = 1 -target_libs = PocoDataPostgreSQL PocoData PocoFoundation CppUnit +target_libs = PocoDataPostgreSQL PocoDataTest PocoData PocoFoundation CppUnit +target_includes += $(POCO_BASE)/Data/testsuite/DataTest/include include $(POCO_BASE)/build/rules/exec diff --git a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp index 5ad2a649d..057384f71 100644 --- a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp +++ b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp @@ -774,6 +774,15 @@ void PostgreSQLTest::testSessionTransaction() } +void PostgreSQLTest::testSessionTransactionNoAutoCommit() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->sessionTransactionNoAutoCommit(_dbConnString); +} + + void PostgreSQLTest::testTransaction() { if (!_pSession) fail ("Test not available."); @@ -1328,6 +1337,7 @@ CppUnit::Test* PostgreSQLTest::suite() CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryBLOBStmt); CppUnit_addTest(pSuite, PostgreSQLTest, testSessionTransaction); + CppUnit_addTest(pSuite, PostgreSQLTest, testSessionTransactionNoAutoCommit); CppUnit_addTest(pSuite, PostgreSQLTest, testTransaction); CppUnit_addTest(pSuite, PostgreSQLTest, testReconnect); diff --git a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h index 86abfba14..be0551404 100644 --- a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h +++ b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h @@ -110,8 +110,8 @@ public: void testBinaryCLOBStmt(); void testSessionTransaction(); + void testSessionTransactionNoAutoCommit(); void testTransaction(); - void testReconnect(); void testSqlState(); diff --git a/Data/PostgreSQL/testsuite/src/SQLExecutor.cpp b/Data/PostgreSQL/testsuite/src/SQLExecutor.cpp index 12457d918..2698f3d24 100644 --- a/Data/PostgreSQL/testsuite/src/SQLExecutor.cpp +++ b/Data/PostgreSQL/testsuite/src/SQLExecutor.cpp @@ -141,7 +141,8 @@ private: SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession): CppUnit::TestCase(name), - _pSession(pSession) + _pSession(pSession), + _dataExecutor("Poco::Data SQL Executor", pSession, nullptr, true) { } @@ -460,209 +461,43 @@ void SQLExecutor::barebonePostgreSQLTest(std::string host, std::string user, std 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; - - count = 0; - try - { - Statement stmt(*_pSession); - stmt << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastName), use(firstName), use(address), use(age);//, now; - stmt.execute(); - } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - assertTrue (count == 1); - - try { *_pSession << "SELECT LastName FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (lastName == result); - - try { *_pSession << "SELECT Age FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == age); + _dataExecutor.simpleAccess(); } void SQLExecutor::complexType() { - std::string funct = "complexType()"; - Person p1("LN1", "FN1", "ADDR1", 1); - Person p2("LN2", "FN2", "ADDR2", 2); - - try { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(p1), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - try { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(p2), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - - Person c1; - Person c2; - try { *_pSession << "SELECT * FROM Person WHERE LastName = 'LN1'", into(c1), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (c1 == p1); + _dataExecutor.complexType(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - - std::vector lastNamesR; - std::vector firstNamesR; - std::vector addressesR; - std::vector agesR; - try { *_pSession << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ages == agesR); - assertTrue (lastNames == lastNamesR); - assertTrue (firstNames == firstNamesR); - assertTrue (addresses == addressesR); + _dataExecutor.simpleAccessVector(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - - std::vector result; - try { *_pSession << "SELECT * FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result == people); + _dataExecutor.complexTypeVector(); } 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((*_pSession << "INSERT INTO Strings VALUES ($1)", use(str))); - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 0); - - try { stmt.execute(); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 4); - } - count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 4); + _dataExecutor.insertVector(); } void SQLExecutor::insertEmptyVector() { - std::string funct = "insertEmptyVector()"; - std::vector str; - - try - { - *_pSession << "INSERT INTO Strings VALUES ($1)", use(str), now; - fail("empty collections should not work"); - } - catch (Poco::Exception&) - { - } + _dataExecutor.insertEmptyVector(); } void SQLExecutor::insertSingleBulk() { - std::string funct = "insertSingleBulk()"; - int x = 0; - Statement stmt((*_pSession << "INSERT INTO Strings VALUES ($1)", use(x))); - - for (x = 0; x < 100; ++x) - { - std::size_t i = stmt.execute(); - assertTrue (i == 1); - } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 100); - - try { *_pSession << "SELECT SUM(str) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == ((0+99)*100/2)); + _dataExecutor.insertSingleBulk(); } @@ -691,176 +526,50 @@ void SQLExecutor::unsignedInts() void SQLExecutor::floats() { - std::string funct = "floats()"; - float data = 1.5f; - float ret = 0.0f; - - try { *_pSession << "INSERT INTO Strings VALUES ($1)", use(data), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 1); - - try { *_pSession << "SELECT str FROM Strings", into(ret), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ret == data); + _dataExecutor.floats(); } void SQLExecutor::uuids() { - std::string funct = "uuids()"; - Poco::UUID data("264a1c6f-7af5-43a5-a593-377aff3d2d7d"); - Poco::UUID ret; - - try { *_pSession << "INSERT INTO Strings VALUES ($1)", use(data), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 1); - - try { *_pSession << "SELECT str FROM Strings", into(ret), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ret == data); + _dataExecutor.uuids(); } void SQLExecutor::doubles() { - std::string funct = "floats()"; - double data = 1.5; - double ret = 0.0; - - try { *_pSession << "INSERT INTO Strings VALUES ($1)", use(data), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 1); - - try { *_pSession << "SELECT str FROM Strings", into(ret), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ret == data); + _dataExecutor.doubles(); } void SQLExecutor::insertSingleBulkVec() { - std::string funct = "insertSingleBulkVec()"; - std::vector data; - - for (int x = 0; x < 100; ++x) - data.push_back(x); - - Statement stmt((*_pSession << "INSERT INTO Strings VALUES ($1)", use(data))); - stmt.execute(); - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - assertTrue (count == 100); - try { *_pSession << "SELECT SUM(str) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == ((0+99)*100/2)); + _dataExecutor.insertSingleBulkVec(); } void SQLExecutor::limits() { - std::string funct = "limit()"; - std::vector data; - for (int x = 0; x < 100; ++x) - { - data.push_back(x); - } - - try { *_pSession << "INSERT INTO Strings VALUES ($1)", use(data), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - std::vector retData; - try { *_pSession << "SELECT * FROM Strings", into(retData), limit(50), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (retData.size() == 50); - for (int x = 0; x < 50; ++x) - { - assertTrue (data[x] == retData[x]); - } + _dataExecutor.limits(); } void SQLExecutor::limitZero() { - std::string funct = "limitZero()"; - std::vector data; - for (int x = 0; x < 100; ++x) - { - data.push_back(x); - } - - try { *_pSession << "INSERT INTO Strings VALUES ($1)", use(data), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - std::vector retData; - try { *_pSession << "SELECT * FROM Strings", into(retData), limit(0), now; }// stupid test, but at least we shouldn't crash - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (retData.size() == 0); + _dataExecutor.limitZero(); } void SQLExecutor::limitOnce() { - std::string funct = "limitOnce()"; - std::vector data; - for (int x = 0; x < 101; ++x) - { - data.push_back(x); - } - - try { *_pSession << "INSERT INTO Strings VALUES ($1)", use(data), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - std::vector retData; - Statement stmt = (*_pSession << "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]); - } + _dataExecutor.limitOnce(); } void SQLExecutor::limitPrepare() { + // fails: _dataExecutor.limitPrepare(); + // failed assert: "100 == stmt.execute()" std::string funct = "limitPrepare()"; std::vector data; for (int x = 0; x < 100; ++x) @@ -895,583 +604,137 @@ void SQLExecutor::limitPrepare() { 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((*_pSession << "INSERT INTO Strings VALUES ($1)", use(data))); - } - // stmt should not have been executed when destroyed - int count = 100; - try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 0); + _dataExecutor.prepare(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - - std::set lastNamesR; - std::set firstNamesR; - std::set addressesR; - std::set agesR; - try { *_pSession << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ages == agesR); - assertTrue (lastNames == lastNamesR); - assertTrue (firstNames == firstNamesR); - assertTrue (addresses == addressesR); + _dataExecutor.setSimple(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - - std::set result; - try { *_pSession << "SELECT * FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result == people); + _dataExecutor.setComplex(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 5); - - std::set result; - try { *_pSession << "SELECT * FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result.size() == 2); - assertTrue (*result.begin() == p1); - assertTrue (*++result.begin() == p2); + _dataExecutor.setComplexUnique(); } + 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - - std::multiset lastNamesR; - std::multiset firstNamesR; - std::multiset addressesR; - std::multiset agesR; - try { *_pSession << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ages.size() == agesR.size()); - assertTrue (lastNames.size() == lastNamesR.size()); - assertTrue (firstNames.size() == firstNamesR.size()); - assertTrue (addresses.size() == addressesR.size()); + _dataExecutor.multiSetSimple(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 5); - - std::multiset result; - try { *_pSession << "SELECT * FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result.size() == people.size()); + _dataExecutor.multiSetComplex(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - - std::map result; - try { *_pSession << "SELECT * FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result == people); + _dataExecutor.mapComplex(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 5); - - std::map result; - try { *_pSession << "SELECT * FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result.size() == 2); + _dataExecutor.mapComplexUnique(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 5); - - std::multimap result; - try { *_pSession << "SELECT * FROM Person", into(result), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result.size() == people.size()); + _dataExecutor.multiMapComplex(); } 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("LN1", p2)); - - try { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - try { *_pSession << "SELECT * FROM Person", into(result), limit(1), now; }// will return 1 object into one single result - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result == p1); + _dataExecutor.selectIntoSingle(); } 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("LN1", p2)); - - try { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1)); - stmt.execute(); - assertTrue (result == p1); - assertTrue (!stmt.done()); - stmt.execute(); - assertTrue (result == p2); - assertTrue (stmt.done()); + _dataExecutor.selectIntoSingleStep(); } 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("LN1", p2)); - - try { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), limit(2, true), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - try - { - *_pSession << "SELECT * FROM Person", into(result), limit(1, true), now; // will fail now - fail("hardLimit is set: must fail"); - } - catch(Poco::Data::LimitException&) - { - } + _dataExecutor.selectIntoSingleFail(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - try - { - *_pSession << "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&) - { - } + _dataExecutor.lowerLimitOk(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1)); - stmt.execute(); - assertTrue (result == p1); - assertTrue (!stmt.done()); - stmt.execute(); - assertTrue (result == p2); - assertTrue (stmt.done()); + _dataExecutor.singleSelect(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - try - { - *_pSession << "SELECT * FROM Person", into(result), lowerLimit(3), now; // will fail - fail("should fail. not enough data"); - } - catch(Poco::Exception&) - { - } + _dataExecutor.lowerLimitFail(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - std::vector result; - try { *_pSession << "SELECT * FROM Person", into(result), lowerLimit(2), upperLimit(2), now; }// will return 2 objects - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result.size() == 2); - assertTrue (result[0] == p1); - assertTrue (result[1] == p2); + _dataExecutor.combinedLimits(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - std::vector result; - try { *_pSession << "SELECT * FROM Person", into(result), range(2, 2), now; }// will return 2 objects - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (result.size() == 2); - assertTrue (result[0] == p1); - assertTrue (result[1] == p2); + _dataExecutor.ranges(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - try - { - *_pSession << "SELECT * FROM Person", into(result), lowerLimit(3), upperLimit(2), now; - fail("lower > upper is not allowed"); - } - catch(LimitException&) - { - } + _dataExecutor.combinedIllegalLimits(); } 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 { *_pSession << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(people), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 2); - Person result; - try - { - *_pSession << "SELECT * FROM Person", into(result), range(3, 2), now; - fail("lower > upper is not allowed"); - } - catch(LimitException&) - { - } + _dataExecutor.illegalRange(); } void SQLExecutor::emptyDB() { - std::string funct = "emptyDB()"; - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 0); - - Person result; - Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1)); - stmt.execute(); - assertTrue (result.firstName.empty()); - assertTrue (stmt.done()); + _dataExecutor.emptyDB(); } void SQLExecutor::dateTime() { + // fails because Person as defined here has a birthday but not a born column + //_dataExecutor.dateTime(); + std::string funct = "dateTime()"; std::string lastName("Bart"); std::string firstName("Simpson"); @@ -1495,11 +758,15 @@ void SQLExecutor::dateTime() assertTrue (bd == birthday); std::cout << std::endl << RecordSet(*_pSession, "SELECT * FROM Person"); + } void SQLExecutor::date() { + // fails because Person as defined here has a birthday but not a bornDate column + //_dataExecutor.date(); + std::string funct = "date()"; std::string lastName("Bart"); std::string firstName("Simpson"); @@ -1528,7 +795,9 @@ void SQLExecutor::date() void SQLExecutor::time() { - std::string funct = "date()"; + // fails because Person as defined here has a birthday but not a bornTime column + //_dataExecutor.time(); + std::string funct = "time()"; std::string lastName("Bart"); std::string firstName("Simpson"); std::string address("Springfield"); @@ -1657,51 +926,13 @@ void SQLExecutor::blobStmt() 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 { *_pSession << "INSERT INTO Tuples VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20)", use(t), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - TupleType ret(-10,-11,-12,-13,-14,-15,-16,-17,-18,-19); - assertTrue (ret != t); - try { *_pSession << "SELECT * FROM Tuples", into(ret), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ret == t); + _dataExecutor.tuples(); } 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 { *_pSession << "INSERT INTO Tuples VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20)", use(v), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - int count = 0; - try { *_pSession << "SELECT COUNT(*) FROM Tuples", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (v.size() == (std::size_t) count); - - std::vector > ret; - try { *_pSession << "SELECT * FROM Tuples", into(ret), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (ret == v); + _dataExecutor.tupleVector(); } @@ -1829,323 +1060,30 @@ void SQLExecutor::doNull() 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::cout << "Transaction isolation not supported: "; - switch (ti) - { - case Session::TRANSACTION_READ_COMMITTED: - std::cout << "READ COMMITTED"; break; - case Session::TRANSACTION_READ_UNCOMMITTED: - std::cout << "READ UNCOMMITTED"; break; - case Session::TRANSACTION_REPEATABLE_READ: - std::cout << "REPEATABLE READ"; break; - case Session::TRANSACTION_SERIALIZABLE: - std::cout << "SERIALIZABLE"; break; - default: - std::cout << "UNKNOWN"; break; - } - std::cout << std::endl; - } + _dataExecutor.setTransactionIsolation(session, ti); } void SQLExecutor::sessionTransaction(const std::string& connect) { - if (!_pSession->canTransact()) - { - std::cout << "Session not capable of transactions." << std::endl; - return; - } + _dataExecutor.sessionTransaction("postgresql", connect); +} - Session local("postgresql", 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 = _pSession->getFeature("autoCommit"); - - // autoCommit set to true is the normal mode - _pSession->setFeature("autoCommit", true); - assertTrue (!_pSession->isTransaction()); - - setTransactionIsolation((*_pSession), Session::TRANSACTION_READ_UNCOMMITTED); - setTransactionIsolation((*_pSession), Session::TRANSACTION_REPEATABLE_READ); - setTransactionIsolation((*_pSession), Session::TRANSACTION_SERIALIZABLE); - - setTransactionIsolation((*_pSession), Session::TRANSACTION_READ_COMMITTED); - - _pSession->begin(); - assertTrue (_pSession->isTransaction()); - try { (*_pSession) << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (_pSession->isTransaction()); - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (0 == locCount); - - try { (*_pSession) << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (2 == count); - assertTrue (_pSession->isTransaction()); - _pSession->rollback(); - assertTrue (!_pSession->isTransaction()); - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (0 == locCount); - - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (0 == count); - assertTrue (!_pSession->isTransaction()); - - _pSession->begin(); - try { (*_pSession) << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (_pSession->isTransaction()); - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (0 == locCount); - - _pSession->commit(); - assertTrue (!_pSession->isTransaction()); - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (2 == locCount); - - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (2 == count); - - _pSession->setFeature("autoCommit", autoCommit); // redundant but ok +void SQLExecutor::sessionTransactionNoAutoCommit(const std::string& connect) +{ + _dataExecutor.sessionTransactionNoAutoCommit("postgresql", connect); } void SQLExecutor::transaction(const std::string& connect) { - if (!_pSession->canTransact()) - { - std::cout << "Session not transaction-capable." << std::endl; - return; - } - - Session local("postgresql", connect); - local.setFeature("autoCommit", true); - - setTransactionIsolation((*_pSession), 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 = _pSession->getFeature("autoCommit"); - - _pSession->setFeature("autoCommit", false); - _pSession->setFeature("autoCommit", true); - assertTrue (!_pSession->isTransaction()); - - _pSession->setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED); - - { - Transaction trans((*_pSession)); - assertTrue (trans.isActive()); - assertTrue (_pSession->isTransaction()); - - try { (*_pSession) << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - assertTrue (_pSession->isTransaction()); - assertTrue (trans.isActive()); - - try { (*_pSession) << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (2 == count); - assertTrue (_pSession->isTransaction()); - assertTrue (trans.isActive()); - } - assertTrue (!_pSession->isTransaction()); - - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (0 == count); - assertTrue (!_pSession->isTransaction()); - - { - Transaction trans((*_pSession)); - try { (*_pSession) << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (0 == locCount); - - assertTrue (_pSession->isTransaction()); - assertTrue (trans.isActive()); - trans.commit(); - assertTrue (!_pSession->isTransaction()); - assertTrue (!trans.isActive()); - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (2 == locCount); - } - - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (2 == count); - - _pSession->begin(); - try { (*_pSession) << "DELETE FROM Person", now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (2 == locCount); - - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (0 == count); - _pSession->commit(); - - 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((*_pSession)); - - trans.execute(sql1, false); - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (1 == count); - trans.execute(sql2, false); - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (2 == count); - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (0 == locCount); - - trans.rollback(); - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (0 == locCount); - - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (0 == count); - - trans.execute(sql); - - local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (2 == locCount); - - try { (*_pSession) << "SELECT count(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (2 == count); - - _pSession->setFeature("autoCommit", autoCommit); + _dataExecutor.transaction("postgresql", connect); } 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 { (*_pSession) << "INSERT INTO Person VALUES ($1,$2,$3,$4)", use(lastName), use(firstName), use(address), use(age), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - - count = 0; - try { (*_pSession) << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == 1); - - assertTrue (_pSession->isConnected()); - _pSession->close(); - assertTrue (!_pSession->isConnected()); - try - { - (*_pSession) << "SELECT LastName FROM Person", into(result), now; - fail ("must fail"); - } - catch(NotConnectedException&){ } - assertTrue (!_pSession->isConnected()); - - _pSession->open(); - assertTrue (_pSession->isConnected()); - try { (*_pSession) << "SELECT Age FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } - assertTrue (count == age); - assertTrue (_pSession->isConnected()); + _dataExecutor.reconnect(); } diff --git a/Data/PostgreSQL/testsuite/src/SQLExecutor.h b/Data/PostgreSQL/testsuite/src/SQLExecutor.h index 7f6753f8e..a9be8a607 100644 --- a/Data/PostgreSQL/testsuite/src/SQLExecutor.h +++ b/Data/PostgreSQL/testsuite/src/SQLExecutor.h @@ -14,6 +14,7 @@ #include "Poco/Data/PostgreSQL/PostgreSQL.h" #include "Poco/Data/Session.h" +#include "Poco/Data/Test/SQLExecutor.h" #include @@ -97,14 +98,17 @@ public: void doNull(); void sessionTransaction(const std::string& connect); + void sessionTransactionNoAutoCommit(const std::string& connect); void transaction(const std::string& connect); + void reconnect(); private: void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti); Poco::Data::Session* _pSession; + Poco::Data::Test::SQLExecutor _dataExecutor; }; diff --git a/Data/include/Poco/Data/AbstractSessionImpl.h b/Data/include/Poco/Data/AbstractSessionImpl.h index a96f64dd9..0fdfa9299 100644 --- a/Data/include/Poco/Data/AbstractSessionImpl.h +++ b/Data/include/Poco/Data/AbstractSessionImpl.h @@ -56,7 +56,8 @@ public: _bulk(false), _emptyStringIsNull(false), _forceEmptyString(false), - _sqlParse(true) + _sqlParse(true), + _autoCommit(true) /// Creates the AbstractSessionImpl. /// /// Adds "storage" property and sets the default internal storage container @@ -113,6 +114,10 @@ public: addFeature("sqlParse", &AbstractSessionImpl::setSQLParse, &AbstractSessionImpl::getSQLParse); + + addFeature("autoCommit", + &AbstractSessionImpl::setAutoCommit, + &AbstractSessionImpl::getAutoCommit); } ~AbstractSessionImpl() @@ -327,6 +332,32 @@ protected: _properties[name] = property; } + // most, if not all, back ends support the autocommit feature + // these handlers are added in this class by default, + // but an implementation can easily replace them by registering + // early its own handlers with: + // addFeature("autoCommit", setter, getter)"); + // + // these are here to be used by any back end DBMS client that + // does not provide its own autocommit get/set capabilities + + void setAutoCommit(const std::string&, bool autoCommit) + /// Enables automatic commit. When this feature is true, + /// every query is automatically commited. When false, + /// every query starts a transaction, except SELECT queries + /// (if properly detected by parser, see set/getSQLParse() and + /// Statement::checkBeginTransaction() documentation). + { + _autoCommit = autoCommit; + } + + bool getAutoCommit(const std::string& name = "") const + /// Returns the value of the automatic commit flag. + /// See setAutoCommit() documentation for more details. + { + return _autoCommit; + } + private: struct Feature { @@ -350,6 +381,7 @@ private: bool _emptyStringIsNull; bool _forceEmptyString; bool _sqlParse; + bool _autoCommit; Poco::Any _handle; }; diff --git a/Data/src/Statement.cpp b/Data/src/Statement.cpp index efb9b02cc..29c7e294d 100644 --- a/Data/src/Statement.cpp +++ b/Data/src/Statement.cpp @@ -235,11 +235,16 @@ void Statement::formatQuery() void Statement::checkBeginTransaction() { SessionImpl& session = _pImpl->session(); - if (!session.isAutocommit() && !session.isTransaction() && session.shouldParse()) - { - auto result = parse(); - if (result.isSpecified() && result.value() && !isSelect().value()) + if (!session.isTransaction() && !session.isAutocommit()) { + if (session.shouldParse()) + { + auto result = parse(); + if (result.isSpecified() && result.value() && !isSelect().value()) + session.begin(); + } else + { session.begin(); + } } } diff --git a/Data/testsuite/DataTest/include/Poco/Data/Test/SQLExecutor.h b/Data/testsuite/DataTest/include/Poco/Data/Test/SQLExecutor.h index 281dd51dc..9ef79e5e8 100644 --- a/Data/testsuite/DataTest/include/Poco/Data/Test/SQLExecutor.h +++ b/Data/testsuite/DataTest/include/Poco/Data/Test/SQLExecutor.h @@ -22,6 +22,7 @@ #include "Poco/String.h" #include "Poco/Exception.h" #include +#include namespace Poco { @@ -53,7 +54,7 @@ public: DE_BOUND }; - SQLExecutor(const std::string& name, Poco::Data::Session* pSession, Poco::Data::Session* pEncSession = 0); + SQLExecutor(const std::string& name, Poco::Data::Session* pSession, Poco::Data::Session* pEncSession = nullptr, bool numberedPlaceHolders = false); ~SQLExecutor(); template @@ -232,6 +233,9 @@ private: Poco::Data::Session* _pSession; Poco::Data::Session* _pEncSession; + bool _numberedPlaceHolders = false; + + std::string formatSQL(const std::string& s) const; }; diff --git a/Data/testsuite/DataTest/src/SQLExecutor.cpp b/Data/testsuite/DataTest/src/SQLExecutor.cpp index ed6c20cc3..7744ece24 100644 --- a/Data/testsuite/DataTest/src/SQLExecutor.cpp +++ b/Data/testsuite/DataTest/src/SQLExecutor.cpp @@ -292,10 +292,11 @@ const std::string SQLExecutor::MULTI_SELECT = "SELECT * FROM Test WHERE First = '5';"; -SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession, Poco::Data::Session* pEncSession): +SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession, Poco::Data::Session* pEncSession, bool numberedPlaceHolders): CppUnit::TestCase(name), _pSession(pSession), - _pEncSession(pEncSession) + _pEncSession(pEncSession), + _numberedPlaceHolders(numberedPlaceHolders) { } @@ -565,7 +566,7 @@ void SQLExecutor::simpleAccess() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(age), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -608,7 +609,7 @@ void SQLExecutor::complexType() Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(p1), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(p1), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -616,7 +617,7 @@ void SQLExecutor::complexType() } - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(p2), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(p2), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -652,7 +653,7 @@ void SQLExecutor::complexTypeTuple() Person p2("LN2", "FN2", "ADDR2", 2); Tuple t(p1,p2); - try { *_pSession << "INSERT INTO Person VALUES(?,?,?,?,?,?,?,?)", use(t), now; } + try { *_pSession << formatSQL("INSERT INTO Person VALUES(?,?,?,?,?,?,?,?)"), use(t), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -691,7 +692,7 @@ void SQLExecutor::simpleAccessVector() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -732,7 +733,7 @@ void SQLExecutor::complexTypeVector() 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; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -768,7 +769,7 @@ void SQLExecutor::sharedPtrComplexTypeVector() 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; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -806,7 +807,7 @@ void SQLExecutor::autoPtrComplexTypeVector() 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; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -854,7 +855,7 @@ void SQLExecutor::insertVector() int count = 100; { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); + Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str))); try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(DataException& ce) { @@ -899,7 +900,7 @@ void SQLExecutor::insertEmptyVector() try { - session() << "INSERT INTO Strings VALUES (?)", use(str), now; + session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str), now; fail("empty collections should not work", __LINE__, __FILE__); } catch (Poco::Exception&) { @@ -925,7 +926,7 @@ void SQLExecutor::simpleAccessList() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -966,7 +967,7 @@ void SQLExecutor::complexTypeList() 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; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1006,7 +1007,7 @@ void SQLExecutor::insertList() int count = 100; { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); + Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str))); try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(DataException& ce) { @@ -1050,7 +1051,7 @@ void SQLExecutor::insertEmptyList() try { - session() << "INSERT INTO Strings VALUES (?)", use(str), now; + session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str), now; fail("empty collections should not work"); } catch (Poco::Exception&) { @@ -1076,7 +1077,7 @@ void SQLExecutor::simpleAccessDeque() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1116,7 +1117,7 @@ void SQLExecutor::complexTypeDeque() 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; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1156,7 +1157,7 @@ void SQLExecutor::insertDeque() int count = 100; { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); + Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str))); try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(DataException& ce) { @@ -1217,7 +1218,7 @@ void SQLExecutor::affectedRows(const std::string& whereClause) str.push_back("s3"); int count = 100; - Statement stmt1((session() << "INSERT INTO Strings VALUES(?)", use(str))); + Statement stmt1((session() << formatSQL("INSERT INTO Strings VALUES(?)"), use(str))); session() << "SELECT COUNT(*) FROM Strings", into(count), now; assertTrue (count == 0); assertTrue (4 == stmt1.execute()); @@ -1232,7 +1233,7 @@ void SQLExecutor::affectedRows(const std::string& whereClause) std::string sql; format(sql, "DELETE FROM Strings %s", whereClause); - Statement stmt4(session() << sql); + Statement stmt4(session() << formatSQL(sql)); assertTrue (3 == stmt4.execute()); } @@ -1240,7 +1241,7 @@ void SQLExecutor::affectedRows(const std::string& whereClause) void SQLExecutor::insertSingleBulk() { int x = 0; - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(x))); + Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(x))); for (x = 0; x < 100; ++x) { @@ -1273,7 +1274,7 @@ void SQLExecutor::floats() float data = 1.5f; float ret = 0.0f; - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1307,7 +1308,7 @@ void SQLExecutor::doubles() double data = 1.5; double ret = 0.0; - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1341,7 +1342,7 @@ void SQLExecutor::uuids() Poco::UUID data("49cf6461-9b62-4163-9659-5472ef73153d"); Poco::UUID ret; - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1377,7 +1378,7 @@ void SQLExecutor::insertSingleBulkVec() for (int x = 0; x < 100; ++x) data.push_back(x); - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(data))); + Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data))); stmt.execute(); int count = 0; @@ -1409,7 +1410,7 @@ void SQLExecutor::limits() data.push_back(x); } - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1440,7 +1441,7 @@ void SQLExecutor::limitZero() data.push_back(x); } - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1467,7 +1468,7 @@ void SQLExecutor::limitOnce() data.push_back(x); } - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1502,7 +1503,7 @@ void SQLExecutor::limitPrepare() try { - Statement stmt = (session() << "INSERT INTO Strings VALUES (?)", use(data)); + Statement stmt = (session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data)); assertTrue (100 == stmt.execute()); } catch(DataException& ce) @@ -1561,7 +1562,7 @@ void SQLExecutor::prepare() } { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(data))); + Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data))); } // stmt should not have been executed when destroyed @@ -1588,7 +1589,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) try { sw.start(); - session() << "INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", + session() << formatSQL("INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)"), use(strings), use(ints), use(floats), @@ -1611,7 +1612,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) try { sw.restart(); - session() << "INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", + session() << formatSQL("INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)"), use(strings, bulk), use(ints, bulk), use(floats, bulk), @@ -1724,7 +1725,7 @@ void SQLExecutor::setSimple() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce) + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); @@ -1761,7 +1762,7 @@ void SQLExecutor::setComplex() people.insert(Person("LN1", "FN1", "ADDR1", 1)); people.insert(Person("LN2", "FN2", "ADDR2", 2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(DataException& ce) + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); @@ -1798,7 +1799,7 @@ void SQLExecutor::setComplexUnique() Person p2("LN2", "FN2", "ADDR2", 2); people.push_back(p2); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } catch(DataException& ce) + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); @@ -1845,7 +1846,7 @@ void SQLExecutor::multiSetSimple() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1890,7 +1891,7 @@ void SQLExecutor::multiSetComplex() Person p2("LN2", "FN2", "ADDR2", 2); people.insert(p2); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1927,7 +1928,7 @@ void SQLExecutor::mapComplex() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -1967,7 +1968,7 @@ void SQLExecutor::mapComplexUnique() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2007,7 +2008,7 @@ void SQLExecutor::multiMapComplex() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2044,7 +2045,7 @@ void SQLExecutor::selectIntoSingle() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2080,7 +2081,7 @@ void SQLExecutor::selectIntoSingleStep() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2116,7 +2117,7 @@ void SQLExecutor::selectIntoSingleFail() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2151,7 +2152,7 @@ void SQLExecutor::lowerLimitOk() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2186,7 +2187,7 @@ void SQLExecutor::singleSelect() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2221,7 +2222,7 @@ void SQLExecutor::lowerLimitFail() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2256,7 +2257,7 @@ void SQLExecutor::combinedLimits() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2295,7 +2296,7 @@ void SQLExecutor::ranges() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2333,7 +2334,7 @@ void SQLExecutor::combinedIllegalLimits() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2368,7 +2369,7 @@ void SQLExecutor::illegalRange() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2423,7 +2424,7 @@ void SQLExecutor::blob(int bigSize, const std::string& blobPlaceholder) CLOB img("0123456789", 10); int count = 0; - try { session() << format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), + try { session() << formatSQL(format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder)), use(lastName), use(firstName), use(address), use(img), now; } catch(DataException& ce) { @@ -2466,7 +2467,7 @@ void SQLExecutor::blob(int bigSize, const std::string& blobPlaceholder) try { - session() << format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), + session() << formatSQL(format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder)), use(lastName), use(firstName), use(address), use(big), now; } catch(DataException& ce) @@ -2490,7 +2491,7 @@ void SQLExecutor::blobStmt() CLOB blob("0123456789", 10); int count = 0; - Statement ins = (session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(blob)); + Statement ins = (session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(blob)); ins.execute(); try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce) @@ -2534,7 +2535,7 @@ void SQLExecutor::recordSet() { Statement stmt = (session() << - "INSERT INTO Person VALUES (?,?,?,?)", + formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(born), now); RecordSet rset(stmt); assertTrue (rset.rowCount() == 0); @@ -2557,7 +2558,7 @@ void SQLExecutor::recordSet() { Statement stmt = (session() << - "DELETE FROM Person WHERE born = ?", use(born), now); + formatSQL("DELETE FROM Person WHERE born = ?"), use(born), now); RecordSet rset(stmt); assertTrue (rset.rowCount() == 0); assertTrue (rset.affectedRowCount() == 1); @@ -2565,7 +2566,7 @@ void SQLExecutor::recordSet() { Statement stmt = (session() << - "INSERT INTO Person VALUES (?,?,?,?)", + formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(born), now); RecordSet rset(stmt); assertTrue (rset.rowCount() == 0); @@ -2574,7 +2575,7 @@ void SQLExecutor::recordSet() { Statement stmt = (session() << - "INSERT INTO Person VALUES (?,?,?,?)", + formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(born2), now); RecordSet rset(stmt); assertTrue (rset.rowCount() == 0); @@ -2620,7 +2621,7 @@ void SQLExecutor::dateTime() 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 (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(born), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } @@ -2647,7 +2648,7 @@ void SQLExecutor::date() Date bornDate(1965, 6, 18); int count = 0; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), @@ -2697,7 +2698,7 @@ void SQLExecutor::time() Time bornTime (5, 35, 1); int count = 0; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), @@ -2743,7 +2744,7 @@ void SQLExecutor::tuples() typedef Tuple TupleType; 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; } + try { session() << formatSQL("INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"), use(t), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2775,7 +2776,7 @@ void SQLExecutor::tupleVector() v.push_back(t10); v.push_back(t100); - try { session() << "INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(v), now; } + try { session() << formatSQL("INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"), use(v), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2812,7 +2813,7 @@ void SQLExecutor::internalExtraction() 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; } + try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -2940,7 +2941,7 @@ void SQLExecutor::filter(const std::string& query, const std::string& intFldName 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; } + try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3036,7 +3037,7 @@ void SQLExecutor::internalBulkExtraction() try { - session() << "INSERT INTO Person VALUES (?,?,?,?)", + session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName, bulk), use(firstName, bulk), use(address, bulk), @@ -3106,7 +3107,7 @@ void SQLExecutor::internalBulkExtractionUTF16() try { - session() << "INSERT INTO Person VALUES (?,?,?,?)", + session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName, bulk), use(firstName, bulk), use(address, bulk), @@ -3157,7 +3158,7 @@ void SQLExecutor::internalStorageType() 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; } + try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3222,7 +3223,7 @@ void SQLExecutor::internalStorageType() void SQLExecutor::nulls() { - try { session() << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; } + try { session() << formatSQL("INSERT INTO NullTest (i,r,v) VALUES (?,?,?)"), use(null), use(null), use(null), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3254,7 +3255,7 @@ void SQLExecutor::nulls() double f = 1.5; std::string s = "123"; - try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(f), use(s), now; } + try { session() << formatSQL("INSERT INTO NullTest (i, r, v) VALUES (?,?,?)"), use(i), use(f), use(s), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3284,7 +3285,7 @@ void SQLExecutor::nulls() i = 2; f = 3.4; - try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(null), use(null), now; } + try { session() << formatSQL("INSERT INTO NullTest (i, r, v) VALUES (?,?,?)"), use(i), use(null), use(null), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3314,7 +3315,7 @@ void SQLExecutor::nulls() fail (__func__, __LINE__, __FILE__); } - try { session() << "INSERT INTO NullTest (v) VALUES (?)", bind(""), now; } + try { session() << formatSQL("INSERT INTO NullTest (v) VALUES (?)"), bind(""), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3376,7 +3377,7 @@ void SQLExecutor::rowIterator() RecordSet rset0(session(), "SELECT * FROM Vectors"); assertTrue (rset0.begin() == rset0.end()); - try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } + try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3416,7 +3417,7 @@ void SQLExecutor::rowIterator() void SQLExecutor::stdVectorBool() { bool b = false; - try { session() << "INSERT INTO BoolTest VALUES (?)", use(b), now; } + try { session() << formatSQL("INSERT INTO BoolTest VALUES (?)"), use(b), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3429,7 +3430,7 @@ void SQLExecutor::stdVectorBool() session() << "DELETE FROM BoolTest", now; b = true; - try { session() << "INSERT INTO BoolTest VALUES (?)", use(b), now; } + try { session() << formatSQL("INSERT INTO BoolTest VALUES (?)"), use(b), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3447,7 +3448,7 @@ void SQLExecutor::stdVectorBool() v.push_back(false); v.push_back(true); - try { session() << "INSERT INTO BoolTest VALUES (?)", use(v), now; } + try { session() << formatSQL("INSERT INTO BoolTest VALUES (?)"), use(v), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -3465,9 +3466,9 @@ void SQLExecutor::stdVectorBool() t += *it ? 1 : 0; assertTrue (2 == t); - try { session() << "SELECT * FROM BoolTest WHERE b = ?", out(v), now; fail("must fail"); } catch (BindingException&) { } + try { session() << formatSQL("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&) { } + try { session() << formatSQL("SELECT * FROM BoolTest WHERE b = ?"), io(v), now; fail("must fail"); } catch (BindingException&) { } RecordSet rset(session(), "SELECT * FROM BoolTest"); @@ -3483,7 +3484,7 @@ void SQLExecutor::asynchronous(int rowCount) Session tmp = session(); std::vector data(rowCount); - Statement stmt = (tmp << "INSERT INTO Strings VALUES(?)", use(data)); + Statement stmt = (tmp << formatSQL("INSERT INTO Strings VALUES(?)"), use(data)); Statement::Result result = stmt.executeAsync(); assertTrue (!stmt.isAsync()); result.wait(); @@ -3573,7 +3574,7 @@ void SQLExecutor::any() Session tmp = session(); - tmp << "INSERT INTO Anys VALUES (?, ?, ?)", use(i), use(f), use(s), now; + tmp << formatSQL("INSERT INTO Anys VALUES (?, ?, ?)"), use(i), use(f), use(s), now; int count = 0; tmp << "SELECT COUNT(*) FROM Anys", into(count), now; @@ -3596,7 +3597,7 @@ void SQLExecutor::dynamicAny() Var s = "42"; Session tmp = session(); - tmp << "INSERT INTO Anys VALUES (?, ?, ?)", use(i), use(f), use(s), now; + tmp << formatSQL("INSERT INTO Anys VALUES (?, ?, ?)"), use(i), use(f), use(s), now; int count = 0; tmp << "SELECT COUNT(*) FROM Anys", into(count), now; @@ -3621,7 +3622,7 @@ void SQLExecutor::multipleResults(const std::string& sql) 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; + session() << formatSQL("INSERT INTO Person VALUES (?, ?, ?, ?)"), use(people), now; Person pHomer; int aHomer = 42, aLisa = 8; @@ -3856,7 +3857,7 @@ void SQLExecutor::sessionTransaction(const std::string& connector, const std::st session().setFeature("autoCommit", false); assertTrue (!session().getFeature("autoCommit")); - session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; assertTrue (session().isTransaction()); Statement stmt = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); @@ -3876,16 +3877,17 @@ void SQLExecutor::sessionTransaction(const std::string& connector, const std::st assertTrue (!session().isTransaction()); session().begin(); - session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; assertTrue (session().isTransaction()); stmt = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); + assertTrue (0 == locCount); session().commit(); assertTrue (!session().isTransaction()); - stmt.wait(); - assertTrue (2 == locCount); + // in general, no guarantee if stmt was executed before or after the commit + assertTrue (0 == locCount || 2 == locCount); session() << "SELECT count(*) FROM Person", into(count), now; assertTrue (2 == count); @@ -3900,7 +3902,7 @@ void SQLExecutor::sessionTransactionNoAutoCommit(const std::string& connector, c { bool autoCommit = session().getFeature("autoCommit"); - Session local("odbc", connect); + Session local(connector, connect); local.setFeature("autoCommit", false); assertTrue (!local.getFeature("autoCommit")); @@ -3921,7 +3923,7 @@ void SQLExecutor::sessionTransactionNoAutoCommit(const std::string& connector, c // no autoCommit session becomes transaction without explicit begin() assertTrue (!local.isTransaction()); assertTrue (!session().isTransaction()); - local << "INSERT INTO Person VALUES (?,?,?,?)", + local << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; Statement stmt = (session() << "SELECT COUNT(*) FROM Person", into(count), async, now); @@ -3949,17 +3951,21 @@ void SQLExecutor::sessionTransactionNoAutoCommit(const std::string& connector, c assertTrue (!local.isTransaction()); stmt.wait(); - assertTrue (2 == count); + // in general, there is no guarantee if stmt was exeuted before or after the commit + assertTrue (2 == count || 0 == count); count = 0; stmt.reset(session()); - + session() << "SELECT COUNT(*) FROM Person", into(count), now; + assertTrue (2 == count); + count = 0; assertTrue (!local.isTransaction()); assertTrue (!session().isTransaction()); - local << "INSERT INTO Person VALUES (?,?,?,?)", + local << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; stmt = (session() << "SELECT COUNT(*) FROM Person", into(count), async, now); local << "SELECT COUNT(*) FROM Person", into(locCount), now; - assertTrue (0 == count); + // no guarantee if stmt is executed or not: + assertTrue (0 == count || 2 == count); assertTrue (4 == locCount); #ifndef POCO_DATA_NO_SQL_PARSER assertTrue (local.isTransaction()); @@ -3994,7 +4000,7 @@ void SQLExecutor::transaction(const std::string& connector, const std::string& c return; } - Session local("odbc", connect); + Session local(connector, connect); local.setFeature("autoCommit", true); bool autoCommit = session().getFeature("autoCommit"); @@ -4025,7 +4031,7 @@ void SQLExecutor::transaction(const std::string& connector, const std::string& c assertTrue (trans.isActive()); assertTrue (session().isTransaction()); - session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; assertTrue (session().isTransaction()); assertTrue (trans.isActive()); @@ -4039,12 +4045,12 @@ void SQLExecutor::transaction(const std::string& connector, const std::string& c session() << "SELECT count(*) FROM Person", into(count), now; assertTrue (0 == count); - assertTrue (!session().isTransaction()); + assertTrue (!(session().impl()->shouldParse() && session().isTransaction())); session().commit(); { Transaction trans(session()); - session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); @@ -4270,7 +4276,7 @@ void SQLExecutor::reconnect() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(age), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; @@ -4319,7 +4325,7 @@ void SQLExecutor::unicode(const std::string& dbConnString) UTF16String wtext; Poco::UnicodeConverter::convert(text, wtext); - session() << "INSERT INTO UnicodeTable VALUES (?)", use(wtext), now; + session() << formatSQL("INSERT INTO UnicodeTable VALUES (?)"), use(wtext), now; wtext.clear(); text.clear(); session() << "SELECT str FROM UnicodeTable", into(wtext), now; @@ -4337,7 +4343,7 @@ void SQLExecutor::encoding(const std::string& dbConnString) std::string latinText((const char*)latinChars); std::string utf8TextIn((const char*)utf8Chars); - session(true) << "INSERT INTO Latin1Table VALUES (?)", use(utf8TextIn), now; + session(true) << formatSQL("INSERT INTO Latin1Table VALUES (?)"), use(utf8TextIn), now; std::string latinTextOut; session() << "SELECT str FROM Latin1Table", into(latinTextOut), now; @@ -4352,7 +4358,7 @@ void SQLExecutor::encoding(const std::string& dbConnString) std::string latinText2 = (const char*)latinChars2; std::string utf8TextIn2 = (const char*)utf8Chars2; - session(true) << "INSERT INTO Latin1Table VALUES (?)", use(utf8TextIn2), now; + session(true) << formatSQL("INSERT INTO Latin1Table VALUES (?)"), use(utf8TextIn2), now; std::vector textOutVec; session() << "SELECT str FROM Latin1Table", into(textOutVec), now; @@ -4378,4 +4384,27 @@ void SQLExecutor::encoding(const std::string& dbConnString) } } + +std::string SQLExecutor::formatSQL(const std::string& s) const +{ + if (!_numberedPlaceHolders) + return std::string(s); + + std::string r; + r.reserve(s.size()); + int idx = 0; + for (char c: s) + { + if (c == '?') + { + r += '$'; + r += std::to_string(++idx); + } + else + r += c; + } + return r; +} + + } } } // Poco::Data::Test diff --git a/Data/testsuite/src/DataTest.cpp b/Data/testsuite/src/DataTest.cpp index 8249379c0..8a20b419c 100644 --- a/Data/testsuite/src/DataTest.cpp +++ b/Data/testsuite/src/DataTest.cpp @@ -39,6 +39,8 @@ #include +using namespace Poco; +using namespace Poco::Data; using namespace Poco::Data::Keywords; @@ -181,6 +183,47 @@ void DataTest::testFeatures() { Session sess(SessionFactory::instance().create("test", "cs")); + // AbstractSession features + assertTrue (sess.hasFeature("bulk")); + assertTrue (!sess.getFeature("bulk")); + sess.setFeature("bulk", true); + assertTrue (sess.getFeature("bulk")); + sess.setFeature("bulk", false); + assertTrue (!sess.getFeature("bulk")); + + assertTrue (sess.hasFeature("emptyStringIsNull")); + assertTrue (!sess.getFeature("emptyStringIsNull")); + sess.setFeature("emptyStringIsNull", true); + assertTrue (sess.getFeature("emptyStringIsNull")); + sess.setFeature("emptyStringIsNull", false); + assertTrue (!sess.getFeature("emptyStringIsNull")); + + assertTrue (sess.hasFeature("forceEmptyString")); + assertTrue (!sess.getFeature("forceEmptyString")); + sess.setFeature("forceEmptyString", true); + assertTrue (sess.getFeature("forceEmptyString")); + sess.setFeature("forceEmptyString", false); + assertTrue (!sess.getFeature("forceEmptyString")); + + assertTrue (sess.hasFeature("sqlParse")); + assertTrue (sess.getFeature("sqlParse")); + sess.setFeature("sqlParse", false); + assertTrue (!sess.getFeature("sqlParse")); + sess.setFeature("sqlParse", true); + assertTrue (sess.getFeature("sqlParse")); + + assertTrue (sess.hasFeature("autoCommit")); + assertTrue (sess.getFeature("autoCommit")); + sess.setFeature("autoCommit", false); + assertTrue (!sess.getFeature("autoCommit")); + sess.setFeature("autoCommit", true); + assertTrue (sess.getFeature("autoCommit")); + + // Session implementation features + sess.setFeature("f1", true); + assertTrue (sess.getFeature("f1")); + assertTrue (sess.getFeature("f2")); + sess.setFeature("f1", true); assertTrue (sess.getFeature("f1")); assertTrue (sess.getFeature("f2")); @@ -218,6 +261,16 @@ void DataTest::testProperties() { Session sess(SessionFactory::instance().create("test", "cs")); + // AbstractSession properties + sess.setProperty("storage", "myStorage"s); + Poco::Any s1 = sess.getProperty("storage"); + assertTrue (Poco::AnyCast(s1) == "myStorage"s); + + sess.setProperty("handle", 1); + Poco::Any h1 = sess.getProperty("handle"); + assertTrue (Poco::AnyCast(h1) == 1); + + // Session implementation properties sess.setProperty("p1", 1); Poco::Any v1 = sess.getProperty("p1"); assertTrue (Poco::AnyCast(v1) == 1); diff --git a/Data/testsuite/src/SessionImpl.cpp b/Data/testsuite/src/SessionImpl.cpp index dc8a0e815..198f9960d 100644 --- a/Data/testsuite/src/SessionImpl.cpp +++ b/Data/testsuite/src/SessionImpl.cpp @@ -21,15 +21,13 @@ namespace Test { SessionImpl::SessionImpl(const std::string& init, std::size_t timeout): Poco::Data::AbstractSessionImpl(init, timeout), _f(false), - _connected(true), - _autoCommit(true) + _connected(true) { addFeature("f1", &SessionImpl::setF, &SessionImpl::getF); addFeature("f2", 0, &SessionImpl::getF); addFeature("f3", &SessionImpl::setF, 0); addFeature("throwOnHasNext", &SessionImpl::setThrowOnHasNext, &SessionImpl::getThrowOnHasNext); addFeature("connected", &SessionImpl::setConnected, &SessionImpl::getConnected); - addFeature("autoCommit", &SessionImpl::setAutoCommit, &SessionImpl::getAutoCommit); addProperty("p1", &SessionImpl::setP, &SessionImpl::getP); addProperty("p2", 0, &SessionImpl::getP); addProperty("p3", &SessionImpl::setP, &SessionImpl::getP); @@ -148,18 +146,6 @@ void SessionImpl::setConnected(const std::string&, bool value) } -bool SessionImpl::getAutoCommit(const std::string& name) const -{ - return _autoCommit; -} - - -void SessionImpl::setAutoCommit(const std::string&, bool value) -{ - _autoCommit = value; -} - - void SessionImpl::setF(const std::string&, bool value) { _f = value; diff --git a/Data/testsuite/src/SessionImpl.h b/Data/testsuite/src/SessionImpl.h index 6223e6df2..a0d695533 100644 --- a/Data/testsuite/src/SessionImpl.h +++ b/Data/testsuite/src/SessionImpl.h @@ -96,10 +96,6 @@ public: /// This is normally done by implementation /// when a database connection loss is detected. - void setAutoCommit(const std::string& name, bool value); - bool getAutoCommit(const std::string& name) const; - /// Sets/gets the autoCommit property. - void setF(const std::string& name, bool value); bool getF(const std::string& name) const; void setThrowOnHasNext(const std::string& name, bool value); @@ -112,7 +108,6 @@ private: bool _throwOnHasNext = false; Poco::Any _p; bool _connected; - bool _autoCommit = true; std::string _connectionString; }; diff --git a/Foundation/include/Poco/Foundation.h b/Foundation/include/Poco/Foundation.h index 83133af79..139a93d75 100644 --- a/Foundation/include/Poco/Foundation.h +++ b/Foundation/include/Poco/Foundation.h @@ -97,7 +97,7 @@ namespace Poco { using namespace std::literals; -} // Poco +} // namespace Poco // diff --git a/Foundation/nonexistent.txt b/Foundation/nonexistent.txt new file mode 100644 index 000000000..e69de29bb