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 <frwilckens@gmail.com>
Co-authored-by: Friedrich Wilckens <friedrich.wilckens@ingramcontent.com>
This commit is contained in:
Aleksandar Fabijanic 2023-12-22 09:27:34 +01:00 committed by GitHub
parent 80cde9e3e6
commit 86084cb7b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 441 additions and 1340 deletions

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -107,6 +107,7 @@ public:
void testTransaction();
void testReconnect();
void testSessionPoolAndUnicode();
void setUp();
void tearDown();

View File

@ -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"
@ -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<Poco::Data::SessionPool> 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);
}

View File

@ -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);

View File

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

View File

@ -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 <std::string> _preparedStatementsToBeDeallocated;
@ -306,12 +305,6 @@ inline bool SessionHandle::isTransaction() const
}
inline bool SessionHandle::isAutoCommit() const
{
return _isAutoCommit;
}
inline bool SessionHandle::isAsynchronousCommit() const
{
return _isAsynchronousCommit;

View File

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

View File

@ -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)
{
return;
}
if (aShouldAutoCommit)
{
if (isTransaction())
commit(); // end any in process transaction
{
throw Poco::InvalidAccessException();
}
_isAutoCommit = aShouldAutoCommit;
}

View File

@ -60,6 +60,7 @@ SessionImpl::SessionImpl(const std::string& aConnectionString, std::size_t aLogi
Poco::Data::AbstractSessionImpl<SessionImpl>(aConnectionString, aLoginTimeout),
_connectorName("postgresql")
{
setFeature("sqlParse", false); // the parse currently cannot handle the PostgreSQL placeholders $1, $2, etc.
setProperty("handle", static_cast<SessionHandle*>(&_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);
}

View File

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

View File

@ -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);

View File

@ -110,8 +110,8 @@ public:
void testBinaryCLOBStmt();
void testSessionTransaction();
void testSessionTransactionNoAutoCommit();
void testTransaction();
void testReconnect();
void testSqlState();

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@
#include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/Test/SQLExecutor.h"
#include <libpq-fe.h>
@ -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;
};

View File

@ -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<C>::setSQLParse,
&AbstractSessionImpl<C>::getSQLParse);
addFeature("autoCommit",
&AbstractSessionImpl<C>::setAutoCommit,
&AbstractSessionImpl<C>::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;
};

View File

@ -235,11 +235,16 @@ void Statement::formatQuery()
void Statement::checkBeginTransaction()
{
SessionImpl& session = _pImpl->session();
if (!session.isAutocommit() && !session.isTransaction() && session.shouldParse())
if (!session.isTransaction() && !session.isAutocommit()) {
if (session.shouldParse())
{
auto result = parse();
if (result.isSpecified() && result.value() && !isSelect().value())
session.begin();
} else
{
session.begin();
}
}
}

View File

@ -22,6 +22,7 @@
#include "Poco/String.h"
#include "Poco/Exception.h"
#include <iostream>
#include <string_view>
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 <typename C>
@ -232,6 +233,9 @@ private:
Poco::Data::Session* _pSession;
Poco::Data::Session* _pEncSession;
bool _numberedPlaceHolders = false;
std::string formatSQL(const std::string& s) const;
};

View File

@ -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<Person,Person> 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<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> 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<int, double, std::string>(3, 3.5f, "5"));
v.push_back(Tuple<int, double, std::string>(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<int, double, std::string>(3, 3.5f, "5"));
v.push_back(Tuple<int, double, std::string>(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<int, double, std::string>(3, 3.5f, "5"));
v.push_back(Tuple<int, double, std::string>(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<int> 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<std::string> 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

View File

@ -39,6 +39,8 @@
#include <set>
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<std::string>(s1) == "myStorage"s);
sess.setProperty("handle", 1);
Poco::Any h1 = sess.getProperty("handle");
assertTrue (Poco::AnyCast<int>(h1) == 1);
// Session implementation properties
sess.setProperty("p1", 1);
Poco::Any v1 = sess.getProperty("p1");
assertTrue (Poco::AnyCast<int>(v1) == 1);

View File

@ -21,15 +21,13 @@ namespace Test {
SessionImpl::SessionImpl(const std::string& init, std::size_t timeout):
Poco::Data::AbstractSessionImpl<SessionImpl>(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;

View File

@ -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;
};

View File

@ -97,7 +97,7 @@ namespace Poco {
using namespace std::literals;
} // Poco
} // namespace Poco
//

View File