mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 10:13:51 +01:00
* 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:
parent
80cde9e3e6
commit
86084cb7b2
96
.github/workflows/ci.yml
vendored
96
.github/workflows/ci.yml
vendored
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ public:
|
||||
void testTransaction();
|
||||
|
||||
void testReconnect();
|
||||
void testSessionPoolAndUnicode();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -97,7 +97,7 @@ namespace Poco {
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
} // Poco
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
//
|
||||
|
0
Foundation/nonexistent.txt
Normal file
0
Foundation/nonexistent.txt
Normal file
Loading…
Reference in New Issue
Block a user