mirror of
https://github.com/pocoproject/poco.git
synced 2025-02-20 22:31:23 +01:00
SF [2643953] Improve Data::Session connection
This commit is contained in:
parent
9bef44cab6
commit
68a79674c1
@ -62,7 +62,8 @@ public:
|
||||
virtual const std::string& name() const;
|
||||
/// Returns the name associated with this connector.
|
||||
|
||||
virtual Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString);
|
||||
virtual Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString,
|
||||
std::size_t timeout = Poco::Data::SessionImpl::CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a MySQL SessionImpl object and initializes it with the given connectionString.
|
||||
|
||||
static void registerConnector();
|
||||
|
@ -59,12 +59,18 @@ public:
|
||||
~SessionHandle();
|
||||
/// Destroy handle, close connection
|
||||
|
||||
void init(MYSQL* mysql = 0);
|
||||
/// Initializes the handle iff not initialized.
|
||||
|
||||
void options(mysql_option opt);
|
||||
/// Set connection options
|
||||
|
||||
void options(mysql_option opt, bool b);
|
||||
/// Set connection options
|
||||
|
||||
void options(mysql_option opt, unsigned int i);
|
||||
/// Set connection options
|
||||
|
||||
void connect(const char* host, const char* user, const char* password, const char* db, unsigned int port);
|
||||
/// Connect to server
|
||||
|
||||
|
@ -62,7 +62,8 @@ public:
|
||||
static const std::string MYSQL_REPEATABLE_READ;
|
||||
static const std::string MYSQL_SERIALIZABLE;
|
||||
|
||||
SessionImpl(const std::string& connectionString);
|
||||
SessionImpl(const std::string& connectionString,
|
||||
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates the SessionImpl. Opens a connection to the database
|
||||
///
|
||||
/// Connection string format:
|
||||
@ -81,6 +82,15 @@ public:
|
||||
Poco::Data::StatementImpl* createStatementImpl();
|
||||
/// Returns an MySQL StatementImpl
|
||||
|
||||
void open(const std::string& connection = "");
|
||||
/// Opens a connection to the database.
|
||||
|
||||
void close();
|
||||
/// Closes the connection.
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true if connected, false otherwise.
|
||||
|
||||
void begin();
|
||||
/// Starts a transaction
|
||||
|
||||
@ -90,12 +100,6 @@ public:
|
||||
void rollback();
|
||||
/// Aborts a transaction
|
||||
|
||||
void close();
|
||||
/// Closes the connection
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true if connected, false otherwise.
|
||||
|
||||
bool canTransact();
|
||||
/// Returns true if session has transaction capabilities.
|
||||
|
||||
@ -163,10 +167,10 @@ private:
|
||||
return getValue<T>(pResult, val);
|
||||
}
|
||||
|
||||
std::string _connector;
|
||||
SessionHandle _handle;
|
||||
bool _connected;
|
||||
bool _inTransaction;
|
||||
std::string _connector;
|
||||
SessionHandle _handle;
|
||||
bool _connected;
|
||||
bool _inTransaction;
|
||||
Poco::FastMutex _mutex;
|
||||
};
|
||||
|
||||
|
@ -64,9 +64,10 @@ const std::string& Connector::name() const
|
||||
return KEY;
|
||||
}
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString)
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString,
|
||||
std::size_t timeout)
|
||||
{
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString));
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString, timeout));
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
|
||||
#include "Poco/Data/MySQL/SessionHandle.h"
|
||||
#include "Poco/Data/DataException.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -42,10 +43,20 @@ namespace Data {
|
||||
namespace MySQL {
|
||||
|
||||
|
||||
SessionHandle::SessionHandle(MYSQL* mysql)
|
||||
SessionHandle::SessionHandle(MYSQL* mysql): _pHandle(0)
|
||||
{
|
||||
if (!(_pHandle = mysql_init(mysql)))
|
||||
throw ConnectionException("mysql_init error");
|
||||
init(mysql);
|
||||
}
|
||||
|
||||
|
||||
void SessionHandle::init(MYSQL* mysql)
|
||||
{
|
||||
if (!_pHandle)
|
||||
{
|
||||
_pHandle = mysql_init(mysql);
|
||||
if (!_pHandle)
|
||||
throw ConnectionException("mysql_init error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -69,11 +80,17 @@ void SessionHandle::options(mysql_option opt, bool b)
|
||||
throw ConnectionException("mysql_options error", _pHandle);
|
||||
}
|
||||
|
||||
void SessionHandle::options(mysql_option opt, unsigned int i)
|
||||
{
|
||||
if (mysql_options(_pHandle, opt, &i) != 0)
|
||||
throw ConnectionException("mysql_options error", _pHandle);
|
||||
}
|
||||
|
||||
|
||||
void SessionHandle::connect(const char* host, const char* user, const char* password, const char* db, unsigned int port)
|
||||
{
|
||||
if (!mysql_real_connect(_pHandle, host, user, password, db, port, 0, 0))
|
||||
throw ConnectionException("create session: mysql_real_connect error", _pHandle);
|
||||
throw ConnectionFailedException("mysql_real_connect error");
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,8 +66,8 @@ const std::string SessionImpl::MYSQL_REPEATABLE_READ = "REPEATABLE READ";
|
||||
const std::string SessionImpl::MYSQL_SERIALIZABLE = "SERIALIZABLE";
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& connectionString) :
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString)),
|
||||
SessionImpl::SessionImpl(const std::string& connectionString, std::size_t timeout) :
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString), timeout),
|
||||
_handle(0),
|
||||
_connected(false),
|
||||
_inTransaction(false)
|
||||
@ -76,6 +76,28 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
|
||||
&SessionImpl::setInsertId,
|
||||
&SessionImpl::getInsertId);
|
||||
|
||||
open();
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::open(const std::string& connect)
|
||||
{
|
||||
if (connect != connectionString())
|
||||
{
|
||||
if (isConnected())
|
||||
throw InvalidAccessException("Session already connected");
|
||||
|
||||
if (!connect.empty())
|
||||
setConnectionString(connect);
|
||||
}
|
||||
|
||||
poco_assert_dbg (!connectionString().empty());
|
||||
|
||||
_handle.init();
|
||||
|
||||
unsigned int timeout = static_cast<unsigned int>(getTimeout());
|
||||
_handle.options(MYSQL_OPT_CONNECT_TIMEOUT, timeout);
|
||||
|
||||
std::map<std::string, std::string> options;
|
||||
|
||||
// Default values
|
||||
@ -87,9 +109,10 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
|
||||
options["compress"] = "";
|
||||
options["auto-reconnect"] = "";
|
||||
|
||||
for (std::string::const_iterator start = connectionString.begin();;)
|
||||
const std::string& connString = connectionString();
|
||||
for (std::string::const_iterator start = connString.begin();;)
|
||||
{
|
||||
std::string::const_iterator finish = std::find(start, connectionString.end(), ';');
|
||||
std::string::const_iterator finish = std::find(start, connString.end(), ';');
|
||||
std::string::const_iterator middle = std::find(start, finish, '=');
|
||||
|
||||
if (middle == finish)
|
||||
@ -97,7 +120,7 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
|
||||
|
||||
options[copyStripped(start, middle)] = copyStripped(middle + 1, finish);
|
||||
|
||||
if ((finish == connectionString.end()) || (finish + 1 == connectionString.end())) break;
|
||||
if ((finish == connString.end()) || (finish + 1 == connString.end())) break;
|
||||
|
||||
start = finish + 1;
|
||||
}
|
||||
@ -127,8 +150,7 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
|
||||
throw MySQLException("create session: specify correct auto-reconnect option (true or false) or skip it");
|
||||
|
||||
// Real connect
|
||||
_handle.connect(
|
||||
options["host"].c_str(),
|
||||
_handle.connect(options["host"].c_str(),
|
||||
options["user"].c_str(),
|
||||
options["password"].c_str(),
|
||||
options["db"].c_str(),
|
||||
|
@ -507,6 +507,15 @@ void MySQLTest::testTransaction()
|
||||
}
|
||||
|
||||
|
||||
void MySQLTest::testReconnect()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
recreatePersonTable();
|
||||
_pExecutor->reconnect();
|
||||
}
|
||||
|
||||
|
||||
void MySQLTest::testNullableInt()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@ -813,6 +822,7 @@ CppUnit::Test* MySQLTest::suite()
|
||||
CppUnit_addTest(pSuite, MySQLTest, testTupleWithNullable);
|
||||
CppUnit_addTest(pSuite, MySQLTest, testSessionTransaction);
|
||||
CppUnit_addTest(pSuite, MySQLTest, testTransaction);
|
||||
CppUnit_addTest(pSuite, MySQLTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -116,6 +116,8 @@ public:
|
||||
void testSessionTransaction();
|
||||
void testTransaction();
|
||||
|
||||
void testReconnect();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -476,7 +476,7 @@ void SQLExecutor::insertSingleBulk()
|
||||
|
||||
for (x = 0; x < 100; ++x)
|
||||
{
|
||||
int i = stmt.execute();
|
||||
std::size_t i = stmt.execute();
|
||||
assert (i == 0);
|
||||
}
|
||||
|
||||
@ -1803,3 +1803,44 @@ void SQLExecutor::transaction(const std::string& connect)
|
||||
|
||||
_pSession->setFeature("autoCommit", autoCommit);
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::reconnect()
|
||||
{
|
||||
std::string funct = "reconnect()";
|
||||
std::string lastName = "lastName";
|
||||
std::string firstName("firstName");
|
||||
std::string address("Address");
|
||||
int age = 133132;
|
||||
int count = 0;
|
||||
std::string result;
|
||||
|
||||
try { (*_pSession) << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||
|
||||
count = 0;
|
||||
try { (*_pSession) << "SELECT COUNT(*) FROM PERSON", into(count), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||
assert (count == 1);
|
||||
|
||||
assert (_pSession->isConnected());
|
||||
_pSession->close();
|
||||
assert (!_pSession->isConnected());
|
||||
try
|
||||
{
|
||||
(*_pSession) << "SELECT LastName FROM PERSON", into(result), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(NotConnectedException&){ }
|
||||
assert (!_pSession->isConnected());
|
||||
|
||||
_pSession->open();
|
||||
assert (_pSession->isConnected());
|
||||
try { (*_pSession) << "SELECT Age FROM PERSON", into(count), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||
assert (count == age);
|
||||
assert (_pSession->isConnected());
|
||||
}
|
||||
|
@ -113,6 +113,8 @@ public:
|
||||
void sessionTransaction(const std::string& connect);
|
||||
void transaction(const std::string& connect);
|
||||
|
||||
void reconnect();
|
||||
|
||||
private:
|
||||
void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti);
|
||||
|
||||
|
@ -65,7 +65,8 @@ public:
|
||||
const std::string& name() const;
|
||||
/// Returns the name associated with this connector.
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString);
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString,
|
||||
std::size_t timeout = Poco::Data::SessionImpl::CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a ODBC SessionImpl object and initializes it with the given connectionString.
|
||||
|
||||
static void registerConnector();
|
||||
|
@ -64,6 +64,8 @@ class ODBC_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl>
|
||||
/// Implements SessionImpl interface
|
||||
{
|
||||
public:
|
||||
static const std::size_t ODBC_MAX_FIELD_SIZE = 1024u;
|
||||
|
||||
enum TransactionCapability
|
||||
{
|
||||
ODBC_TXN_CAPABILITY_UNKNOWN = -1,
|
||||
@ -71,12 +73,21 @@ public:
|
||||
ODBC_TXN_CAPABILITY_TRUE = 1
|
||||
};
|
||||
|
||||
SessionImpl(const std::string& connect,
|
||||
std::size_t timeout,
|
||||
std::size_t maxFieldSize = ODBC_MAX_FIELD_SIZE,
|
||||
bool autoBind = true,
|
||||
bool autoExtract = true);
|
||||
/// Creates the SessionImpl. Opens a connection to the database.
|
||||
/// Throws NotConnectedException if connection was not succesful.
|
||||
|
||||
//@ deprecated
|
||||
SessionImpl(const std::string& connect,
|
||||
Poco::Any maxFieldSize = std::size_t(1024),
|
||||
Poco::Any maxFieldSize = ODBC_MAX_FIELD_SIZE,
|
||||
bool enforceCapability=false,
|
||||
bool autoBind = true,
|
||||
bool autoExtract = true);
|
||||
/// Creates the SessionImpl. Opens a connection to the database
|
||||
/// Creates the SessionImpl. Opens a connection to the database.
|
||||
|
||||
~SessionImpl();
|
||||
/// Destroys the SessionImpl.
|
||||
@ -84,6 +95,15 @@ public:
|
||||
Poco::Data::StatementImpl* createStatementImpl();
|
||||
/// Returns an ODBC StatementImpl
|
||||
|
||||
void open(const std::string& connect = "");
|
||||
/// Opens a connection to the Database
|
||||
|
||||
void close();
|
||||
/// Closes the connection
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true if session is connected
|
||||
|
||||
void begin();
|
||||
/// Starts a transaction
|
||||
|
||||
@ -93,12 +113,6 @@ public:
|
||||
void rollback();
|
||||
/// Aborts a transaction
|
||||
|
||||
void close();
|
||||
/// Closes the connection
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true if session is connected
|
||||
|
||||
bool isTransaction();
|
||||
/// Returns true iff a transaction is in progress.
|
||||
|
||||
@ -161,24 +175,21 @@ private:
|
||||
|
||||
static const int FUNCTIONS = SQL_API_ODBC3_ALL_FUNCTIONS_SIZE;
|
||||
|
||||
void open();
|
||||
/// Opens a connection to the Database
|
||||
|
||||
void checkError(SQLRETURN rc, const std::string& msg="");
|
||||
|
||||
Poco::UInt32 getDefaultTransactionIsolation();
|
||||
|
||||
Poco::UInt32 transactionIsolation(SQLUINTEGER isolation);
|
||||
|
||||
std::string _connector;
|
||||
std::string _connector;
|
||||
const ConnectionHandle _db;
|
||||
Poco::Any _maxFieldSize;
|
||||
bool _autoBind;
|
||||
bool _autoExtract;
|
||||
TypeInfo _dataTypes;
|
||||
char _canTransact;
|
||||
bool _inTransaction;
|
||||
Poco::FastMutex _mutex;
|
||||
Poco::Any _maxFieldSize;
|
||||
bool _autoBind;
|
||||
bool _autoExtract;
|
||||
TypeInfo _dataTypes;
|
||||
char _canTransact;
|
||||
bool _inTransaction;
|
||||
Poco::FastMutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
|
@ -57,9 +57,10 @@ Connector::~Connector()
|
||||
}
|
||||
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString)
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString,
|
||||
std::size_t timeout)
|
||||
{
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString));
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString, timeout));
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,6 +49,24 @@ namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& connect,
|
||||
std::size_t timeout,
|
||||
std::size_t maxFieldSize,
|
||||
bool autoBind,
|
||||
bool autoExtract):
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(connect, timeout),
|
||||
_connector(toLower(Connector::KEY)),
|
||||
_maxFieldSize(maxFieldSize),
|
||||
_autoBind(autoBind),
|
||||
_autoExtract(autoExtract),
|
||||
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||
_inTransaction(false)
|
||||
{
|
||||
setFeature("bulk", true);
|
||||
open();
|
||||
}
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& connect,
|
||||
Poco::Any maxFieldSize,
|
||||
bool enforceCapability,
|
||||
@ -85,8 +103,30 @@ Poco::Data::StatementImpl* SessionImpl::createStatementImpl()
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::open()
|
||||
void SessionImpl::open(const std::string& connect)
|
||||
{
|
||||
if (connect != connectionString())
|
||||
{
|
||||
if (isConnected())
|
||||
throw InvalidAccessException("Session already connected");
|
||||
|
||||
if (!connect.empty())
|
||||
setConnectionString(connect);
|
||||
}
|
||||
|
||||
poco_assert_dbg (!connectionString().empty());
|
||||
|
||||
SQLUINTEGER tout = static_cast<SQLUINTEGER>(getTimeout());
|
||||
if (Utility::isError(SQLSetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) tout, 0)))
|
||||
{
|
||||
if (Utility::isError(SQLGetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, &tout, 0, 0)) ||
|
||||
getTimeout() != tout)
|
||||
{
|
||||
ConnectionError e(_db);
|
||||
throw ConnectionFailedException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
SQLCHAR connectOutput[512] = {0};
|
||||
SQLSMALLINT result;
|
||||
|
||||
@ -99,9 +139,10 @@ void SessionImpl::open()
|
||||
, &result
|
||||
, SQL_DRIVER_NOPROMPT)))
|
||||
{
|
||||
ConnectionException exc(_db);
|
||||
ConnectionError err(_db);
|
||||
std::string errStr = err.toString();
|
||||
close();
|
||||
throw exc;
|
||||
throw ConnectionFailedException(errStr);
|
||||
}
|
||||
|
||||
_dataTypes.fillTypeInfo(_db);
|
||||
|
@ -681,6 +681,7 @@ CppUnit::Test* ODBCDB2Test::suite()
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testSessionTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testTransactor);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -497,6 +497,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testSessionTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testTransactor);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -922,6 +922,7 @@ CppUnit::Test* ODBCOracleTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testSessionTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testTransactor);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -659,6 +659,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSessionTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransactor);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -809,6 +809,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSessionTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransactor);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -400,6 +400,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSessionTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransaction);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransactor);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -47,12 +47,14 @@
|
||||
#include "Poco/Data/ODBC/Diagnostics.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
|
||||
#include "Poco/Data/DataException.h"
|
||||
#include <sqltypes.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace Poco::Data::Keywords;
|
||||
using Poco::Data::Session;
|
||||
using Poco::Data::ConnectionFailedException;
|
||||
using Poco::Data::CLOB;
|
||||
using Poco::Data::ODBC::Utility;
|
||||
using Poco::Data::ODBC::ODBCException;
|
||||
@ -1187,6 +1189,23 @@ void ODBCTest::testTransactor()
|
||||
}
|
||||
|
||||
|
||||
void ODBCTest::testReconnect()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
std::string tableName("Person");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreatePersonTable();
|
||||
_pSession->setFeature("autoBind", bindValue(i));
|
||||
_pSession->setFeature("autoExtract", bindValue(i+1));
|
||||
_pExecutor->reconnect();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ODBCTest::canConnect(const std::string& driver,
|
||||
std::string& dsn,
|
||||
std::string& uid,
|
||||
@ -1262,9 +1281,9 @@ ODBCTest::SessionPtr ODBCTest::init(const std::string& driver,
|
||||
try
|
||||
{
|
||||
return new Session(Poco::Data::ODBC::Connector::KEY, dbConnString);
|
||||
}catch (ConnectionException& ex)
|
||||
}catch (ConnectionFailedException& ex)
|
||||
{
|
||||
std::cout << ex.toString() << std::endl;
|
||||
std::cout << ex.displayText() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +167,8 @@ public:
|
||||
virtual void testTransaction();
|
||||
virtual void testTransactor();
|
||||
|
||||
virtual void testReconnect();
|
||||
|
||||
protected:
|
||||
typedef Poco::Data::ODBC::Utility::DriverMap Drivers;
|
||||
|
||||
|
@ -85,6 +85,7 @@ using Poco::Data::CLOB;
|
||||
using Poco::Data::Date;
|
||||
using Poco::Data::Time;
|
||||
using Poco::Data::Transaction;
|
||||
using Poco::Data::NotConnectedException;
|
||||
using Poco::Data::ODBC::Utility;
|
||||
using Poco::Data::ODBC::Preparator;
|
||||
using Poco::Data::ODBC::ConnectionException;
|
||||
@ -3763,3 +3764,44 @@ void SQLExecutor::transactor()
|
||||
|
||||
session().setFeature("autoCommit", autoCommit);
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::reconnect()
|
||||
{
|
||||
std::string funct = "reconnect()";
|
||||
std::string lastName = "lastName";
|
||||
std::string firstName("firstName");
|
||||
std::string address("Address");
|
||||
int age = 133132;
|
||||
int count = 0;
|
||||
std::string result;
|
||||
|
||||
try { session() << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
count = 0;
|
||||
try { session() << "SELECT COUNT(*) FROM PERSON", into(count), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
assert (count == 1);
|
||||
|
||||
assert (session().isConnected());
|
||||
session().close();
|
||||
assert (!session().isConnected());
|
||||
try
|
||||
{
|
||||
session() << "SELECT LastName FROM PERSON", into(result), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(NotConnectedException&){ }
|
||||
assert (!session().isConnected());
|
||||
|
||||
session().open();
|
||||
assert (session().isConnected());
|
||||
try { session() << "SELECT Age FROM PERSON", into(count), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
assert (count == age);
|
||||
assert (session().isConnected());
|
||||
}
|
||||
|
@ -518,6 +518,8 @@ public:
|
||||
void transaction(const std::string& connect);
|
||||
void transactor();
|
||||
|
||||
void reconnect();
|
||||
|
||||
private:
|
||||
static const std::string MULTI_INSERT;
|
||||
static const std::string MULTI_SELECT;
|
||||
|
@ -65,7 +65,8 @@ public:
|
||||
const std::string& name() const;
|
||||
/// Returns the name associated with this connector.
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString);
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString,
|
||||
std::size_t timeout = Poco::Data::SessionImpl::CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a SQLite SessionImpl object and initializes it with the given connectionString.
|
||||
|
||||
static void registerConnector();
|
||||
|
@ -59,7 +59,8 @@ class SQLite_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl
|
||||
/// Implements SessionImpl interface.
|
||||
{
|
||||
public:
|
||||
SessionImpl(const std::string& fileName);
|
||||
SessionImpl(const std::string& fileName,
|
||||
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates the SessionImpl. Opens a connection to the database.
|
||||
|
||||
~SessionImpl();
|
||||
@ -77,6 +78,9 @@ public:
|
||||
void rollback();
|
||||
/// Aborts a transaction.
|
||||
|
||||
void open(const std::string& connect = "");
|
||||
/// Opens a connection to the Database.
|
||||
|
||||
void close();
|
||||
/// Closes the session.
|
||||
|
||||
@ -107,8 +111,6 @@ public:
|
||||
/// Returns the name of the connector.
|
||||
|
||||
private:
|
||||
void open();
|
||||
/// Opens a connection to the Database.
|
||||
|
||||
std::string _connector;
|
||||
sqlite3* _pDB;
|
||||
|
@ -58,9 +58,10 @@ Connector::~Connector()
|
||||
}
|
||||
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString)
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString,
|
||||
std::size_t timeout)
|
||||
{
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString));
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString, timeout));
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,7 +38,10 @@
|
||||
#include "Poco/Data/SQLite/Utility.h"
|
||||
#include "Poco/Data/SQLite/SQLiteStatementImpl.h"
|
||||
#include "Poco/Data/SQLite/Connector.h"
|
||||
#include "Poco/Data/SQLite/SQLiteException.h"
|
||||
#include "Poco/Data/Session.h"
|
||||
#include "Poco/ActiveMethod.h"
|
||||
#include "Poco/ActiveResult.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "sqlite3.h"
|
||||
@ -55,8 +58,8 @@ const std::string SessionImpl::COMMIT_TRANSACTION("COMMIT");
|
||||
const std::string SessionImpl::ABORT_TRANSACTION("ROLLBACK");
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& fileName):
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(fileName),
|
||||
SessionImpl::SessionImpl(const std::string& fileName, std::size_t timeout):
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(fileName, timeout),
|
||||
_connector(toLower(Connector::KEY)),
|
||||
_pDB(0),
|
||||
_connected(false),
|
||||
@ -133,14 +136,61 @@ bool SessionImpl::isTransactionIsolation(Poco::UInt32 ti)
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::open()
|
||||
class ActiveConnector
|
||||
{
|
||||
int rc = sqlite3_open(connectionString().c_str(), &_pDB);
|
||||
|
||||
if (rc != 0)
|
||||
public:
|
||||
ActiveConnector(const std::string& connectString, sqlite3** ppDB):
|
||||
connect(this, &ActiveConnector::connectImpl),
|
||||
_connectString(connectString),
|
||||
_ppDB(ppDB)
|
||||
{
|
||||
close();
|
||||
Utility::throwException(rc);
|
||||
poco_check_ptr(_ppDB);
|
||||
}
|
||||
|
||||
ActiveMethod<int, void, ActiveConnector> connect;
|
||||
|
||||
private:
|
||||
ActiveConnector();
|
||||
|
||||
inline int connectImpl()
|
||||
{
|
||||
return sqlite3_open(_connectString.c_str(), _ppDB);
|
||||
}
|
||||
|
||||
std::string _connectString;
|
||||
sqlite3** _ppDB;
|
||||
};
|
||||
|
||||
|
||||
void SessionImpl::open(const std::string& connect)
|
||||
{
|
||||
if (connect != connectionString())
|
||||
{
|
||||
if (isConnected())
|
||||
throw InvalidAccessException("Session already connected");
|
||||
|
||||
if (!connect.empty())
|
||||
setConnectionString(connect);
|
||||
}
|
||||
|
||||
poco_assert_dbg (!connectionString().empty());
|
||||
|
||||
try
|
||||
{
|
||||
ActiveConnector connector(connectionString(), &_pDB);
|
||||
ActiveResult<int> result = connector.connect();
|
||||
if (!result.tryWait(getTimeout() * 1000))
|
||||
throw ConnectionFailedException("Timed out.");
|
||||
|
||||
int rc = result.data();
|
||||
if (rc != 0)
|
||||
{
|
||||
close();
|
||||
Utility::throwException(rc);
|
||||
}
|
||||
} catch (SQLiteException& ex)
|
||||
{
|
||||
throw ConnectionFailedException(ex.displayText());
|
||||
}
|
||||
|
||||
_connected = true;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "Poco/Data/SQLite/Connector.h"
|
||||
#include "Poco/Data/SQLite/SQLiteException.h"
|
||||
#include "Poco/Data/TypeHandler.h"
|
||||
#include "Poco/Data/DataException.h"
|
||||
#include "Poco/Tuple.h"
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
@ -71,6 +72,7 @@ using Poco::Data::Time;
|
||||
using Poco::Data::AbstractExtractionVec;
|
||||
using Poco::Data::AbstractExtractionVecVec;
|
||||
using Poco::Data::AbstractBindingVec;
|
||||
using Poco::Data::NotConnectedException;
|
||||
using Poco::Tuple;
|
||||
using Poco::Any;
|
||||
using Poco::AnyCast;
|
||||
@ -2317,6 +2319,48 @@ void SQLiteTest::testMultipleResults()
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::testReconnect()
|
||||
{
|
||||
Session session (Poco::Data::SQLite::Connector::KEY, "dummy.db");
|
||||
|
||||
session << "DROP TABLE IF EXISTS Person", now;
|
||||
session << "CREATE TABLE Person (LastName VARCHAR(30),"
|
||||
"FirstName VARCHAR(30),"
|
||||
"Address VARCHAR(30),"
|
||||
"Age INTEGER)", now;
|
||||
|
||||
std::string lastName = "lastName";
|
||||
std::string firstName("firstName");
|
||||
std::string address("Address");
|
||||
int age = 133132;
|
||||
int count = 0;
|
||||
std::string result;
|
||||
|
||||
session << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now;
|
||||
|
||||
count = 0;
|
||||
session << "SELECT COUNT(*) FROM PERSON", into(count), now;
|
||||
assert (count == 1);
|
||||
|
||||
assert (session.isConnected());
|
||||
session.close();
|
||||
assert (!session.isConnected());
|
||||
try
|
||||
{
|
||||
session << "SELECT LastName FROM PERSON", into(result), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(NotConnectedException&){ }
|
||||
assert (!session.isConnected());
|
||||
|
||||
session.open();
|
||||
assert (session.isConnected());
|
||||
session << "SELECT Age FROM PERSON", into(count), now;
|
||||
assert (count == age);
|
||||
assert (session.isConnected());
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -2404,6 +2448,7 @@ CppUnit::Test* SQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testBindingCount);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testMultipleResults);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testPair);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -129,6 +129,8 @@ public:
|
||||
void testBindingCount();
|
||||
void testMultipleResults();
|
||||
|
||||
void testReconnect();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -72,11 +72,12 @@ public:
|
||||
typedef Poco::Any (C::*PropertyGetter)(const std::string&);
|
||||
/// The getter method for a property.
|
||||
|
||||
AbstractSessionImpl(const std::string& connectionString): SessionImpl(connectionString),
|
||||
_storage(std::string("deque")),
|
||||
_bulk(false),
|
||||
_emptyStringIsNull(false),
|
||||
_forceEmptyString(false)
|
||||
AbstractSessionImpl(const std::string& connectionString,
|
||||
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT): SessionImpl(connectionString, timeout),
|
||||
_storage(std::string("deque")),
|
||||
_bulk(false),
|
||||
_emptyStringIsNull(false),
|
||||
_forceEmptyString(false)
|
||||
/// Creates the AbstractSessionImpl.
|
||||
///
|
||||
/// Adds "storage" property and sets the default internal storage container
|
||||
|
@ -66,7 +66,8 @@ public:
|
||||
virtual const std::string& name() const = 0;
|
||||
/// Returns the name associated with this connector.
|
||||
|
||||
virtual Poco::AutoPtr<SessionImpl> createSession(const std::string& connectionString) = 0;
|
||||
virtual Poco::AutoPtr<SessionImpl> createSession(const std::string& connectionString,
|
||||
std::size_t timeout = SessionImpl::CONNECT_TIMEOUT_DEFAULT) = 0;
|
||||
/// Create a SessionImpl object and initialize it with the given connectionString.
|
||||
};
|
||||
|
||||
|
@ -62,6 +62,8 @@ POCO_DECLARE_EXCEPTION(Data_API, SessionPoolExhaustedException, DataException)
|
||||
POCO_DECLARE_EXCEPTION(Data_API, SessionPoolExistsException, DataException)
|
||||
POCO_DECLARE_EXCEPTION(Data_API, NoDataException, DataException)
|
||||
POCO_DECLARE_EXCEPTION(Data_API, LengthExceededException, DataException)
|
||||
POCO_DECLARE_EXCEPTION(Data_API, ConnectionFailedException, DataException)
|
||||
POCO_DECLARE_EXCEPTION(Data_API, NotConnectedException, DataException)
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
@ -70,6 +70,7 @@ public:
|
||||
void begin();
|
||||
void commit();
|
||||
void rollback();
|
||||
void open(const std::string& connect = "");
|
||||
void close();
|
||||
bool isConnected();
|
||||
bool canTransact();
|
||||
|
@ -173,6 +173,7 @@ class Data_API Session
|
||||
/// For complete list of supported data types with their respective specifications, see the documentation for format in Foundation.
|
||||
{
|
||||
public:
|
||||
static const std::size_t CONNECT_TIMEOUT_DEFAULT = SessionImpl::CONNECT_TIMEOUT_DEFAULT;
|
||||
static const Poco::UInt32 TRANSACTION_READ_UNCOMMITTED = 0x00000001L;
|
||||
static const Poco::UInt32 TRANSACTION_READ_COMMITTED = 0x00000002L;
|
||||
static const Poco::UInt32 TRANSACTION_REPEATABLE_READ = 0x00000004L;
|
||||
@ -181,11 +182,14 @@ public:
|
||||
Session(Poco::AutoPtr<SessionImpl> ptrImpl);
|
||||
/// Creates the Session.
|
||||
|
||||
Session(const std::string& connector, const std::string& connectionString);
|
||||
Session(const std::string& connector,
|
||||
const std::string& connectionString,
|
||||
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a new session, using the given connector (which must have
|
||||
/// been registered), and connectionString.
|
||||
|
||||
Session(const std::string& connection);
|
||||
Session(const std::string& connection,
|
||||
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a new session, using the given connection (must be in
|
||||
/// "connection:///connectionString" format).
|
||||
|
||||
@ -211,6 +215,29 @@ public:
|
||||
StatementImpl* createStatementImpl();
|
||||
/// Creates a StatementImpl.
|
||||
|
||||
void open(const std::string& connect = "");
|
||||
/// Opens the session using the supplied string.
|
||||
/// Can also be used with default empty string to
|
||||
/// reconnect a disconnected session.
|
||||
/// If the connection is not established,
|
||||
/// a ConnectionFailedException is thrown.
|
||||
/// Zero timout means indefinite
|
||||
|
||||
void close();
|
||||
/// Closes the session.
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true iff session is connected, false otherwise.
|
||||
|
||||
void reconnect();
|
||||
/// Closes the session and opens it.
|
||||
|
||||
void setTimeout(std::size_t timeout);
|
||||
/// Sets the session timeout value.
|
||||
|
||||
std::size_t getTimeout() const;
|
||||
/// Returns the session timeout value.
|
||||
|
||||
void begin();
|
||||
/// Starts a transaction.
|
||||
|
||||
@ -219,12 +246,6 @@ public:
|
||||
|
||||
void rollback();
|
||||
/// Rolls back and ends a transaction.
|
||||
|
||||
void close();
|
||||
/// Closes the session.
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true iff session is connected, false otherwise.
|
||||
|
||||
bool canTransact();
|
||||
/// Returns true if session has transaction capabilities.
|
||||
@ -296,7 +317,7 @@ public:
|
||||
private:
|
||||
Session();
|
||||
|
||||
Poco::AutoPtr<SessionImpl> _ptrImpl;
|
||||
Poco::AutoPtr<SessionImpl> _pImpl;
|
||||
StatementCreator _statementCreator;
|
||||
};
|
||||
|
||||
@ -306,73 +327,97 @@ private:
|
||||
//
|
||||
inline StatementImpl* Session::createStatementImpl()
|
||||
{
|
||||
return _ptrImpl->createStatementImpl();
|
||||
return _pImpl->createStatementImpl();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::begin()
|
||||
inline void Session::open(const std::string& connect)
|
||||
{
|
||||
return _ptrImpl->begin();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::commit()
|
||||
{
|
||||
return _ptrImpl->commit();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::rollback()
|
||||
{
|
||||
return _ptrImpl->rollback();
|
||||
_pImpl->open(connect);
|
||||
}
|
||||
|
||||
|
||||
inline void Session::close()
|
||||
{
|
||||
_ptrImpl->close();
|
||||
_pImpl->close();
|
||||
}
|
||||
|
||||
|
||||
inline bool Session::isConnected()
|
||||
{
|
||||
return _ptrImpl->isConnected();
|
||||
return _pImpl->isConnected();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::reconnect()
|
||||
{
|
||||
_pImpl->reconnect();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::setTimeout(std::size_t timeout)
|
||||
{
|
||||
_pImpl->setTimeout(timeout);
|
||||
}
|
||||
|
||||
|
||||
inline std::size_t Session::getTimeout() const
|
||||
{
|
||||
return _pImpl->getTimeout();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::begin()
|
||||
{
|
||||
return _pImpl->begin();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::commit()
|
||||
{
|
||||
return _pImpl->commit();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::rollback()
|
||||
{
|
||||
return _pImpl->rollback();
|
||||
}
|
||||
|
||||
|
||||
inline bool Session::canTransact()
|
||||
{
|
||||
return _ptrImpl->canTransact();
|
||||
return _pImpl->canTransact();
|
||||
}
|
||||
|
||||
|
||||
inline bool Session::isTransaction()
|
||||
{
|
||||
return _ptrImpl->isTransaction();
|
||||
return _pImpl->isTransaction();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::setTransactionIsolation(Poco::UInt32 ti)
|
||||
{
|
||||
_ptrImpl->setTransactionIsolation(ti);
|
||||
_pImpl->setTransactionIsolation(ti);
|
||||
}
|
||||
|
||||
|
||||
inline Poco::UInt32 Session::getTransactionIsolation()
|
||||
{
|
||||
return _ptrImpl->getTransactionIsolation();
|
||||
return _pImpl->getTransactionIsolation();
|
||||
}
|
||||
|
||||
|
||||
inline bool Session::hasTransactionIsolation(Poco::UInt32 ti)
|
||||
{
|
||||
return _ptrImpl->hasTransactionIsolation(ti);
|
||||
return _pImpl->hasTransactionIsolation(ti);
|
||||
}
|
||||
|
||||
|
||||
inline bool Session::isTransactionIsolation(Poco::UInt32 ti)
|
||||
{
|
||||
return _ptrImpl->isTransactionIsolation(ti);
|
||||
return _pImpl->isTransactionIsolation(ti);
|
||||
}
|
||||
|
||||
|
||||
@ -385,37 +430,37 @@ inline std::string Session::uri(const std::string& connector,
|
||||
|
||||
inline std::string Session::uri()
|
||||
{
|
||||
return _ptrImpl->uri();
|
||||
return _pImpl->uri();
|
||||
}
|
||||
|
||||
|
||||
inline void Session::setFeature(const std::string& name, bool state)
|
||||
{
|
||||
_ptrImpl->setFeature(name, state);
|
||||
_pImpl->setFeature(name, state);
|
||||
}
|
||||
|
||||
|
||||
inline bool Session::getFeature(const std::string& name) const
|
||||
{
|
||||
return const_cast<SessionImpl*>(_ptrImpl.get())->getFeature(name);
|
||||
return const_cast<SessionImpl*>(_pImpl.get())->getFeature(name);
|
||||
}
|
||||
|
||||
|
||||
inline void Session::setProperty(const std::string& name, const Poco::Any& value)
|
||||
{
|
||||
_ptrImpl->setProperty(name, value);
|
||||
_pImpl->setProperty(name, value);
|
||||
}
|
||||
|
||||
|
||||
inline Poco::Any Session::getProperty(const std::string& name) const
|
||||
{
|
||||
return const_cast<SessionImpl*>(_ptrImpl.get())->getProperty(name);
|
||||
return const_cast<SessionImpl*>(_pImpl.get())->getProperty(name);
|
||||
}
|
||||
|
||||
|
||||
inline SessionImpl* Session::impl()
|
||||
{
|
||||
return _ptrImpl;
|
||||
return _pImpl;
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,11 +83,14 @@ public:
|
||||
/// Lowers the reference count for the Connector registered under that key. If the count reaches zero,
|
||||
/// the object is removed.
|
||||
|
||||
Session create(const std::string& key, const std::string& connectionString);
|
||||
Session create(const std::string& key,
|
||||
const std::string& connectionString,
|
||||
std::size_t timeout = Session::CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a Session for the given key with the connectionString. Throws an Poco:Data::UnknownDataBaseException
|
||||
/// if no Connector is registered for that key.
|
||||
|
||||
Session create(const std::string& uri);
|
||||
Session create(const std::string& uri,
|
||||
std::size_t timeout = Session::CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a Session for the given URI (must be in key:///connectionString format).
|
||||
/// Throws an Poco:Data::UnknownDataBaseException if no Connector is registered for the key.
|
||||
|
||||
|
@ -59,7 +59,14 @@ class Data_API SessionImpl: public Poco::RefCountedObject
|
||||
/// SessionImpl objects are noncopyable.
|
||||
{
|
||||
public:
|
||||
SessionImpl(const std::string& connectionString);
|
||||
static const std::size_t CONNECT_TIMEOUT_INFINITE = 0;
|
||||
/// Infinite connection/login timeout.
|
||||
|
||||
static const std::size_t CONNECT_TIMEOUT_DEFAULT = 30;
|
||||
/// Default connection/login timeout in seconds.
|
||||
|
||||
SessionImpl(const std::string& connectionString,
|
||||
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates the SessionImpl.
|
||||
|
||||
virtual ~SessionImpl();
|
||||
@ -68,6 +75,29 @@ public:
|
||||
virtual StatementImpl* createStatementImpl() = 0;
|
||||
/// Creates a StatementImpl.
|
||||
|
||||
virtual void open(const std::string& connectionString = "") = 0;
|
||||
/// Opens the session using the supplied string.
|
||||
/// Can also be used with default empty string to reconnect
|
||||
/// a disconnected session.
|
||||
/// If the connection is not established within requested timeout
|
||||
/// (specified in seconds), a ConnectionFailedException is thrown.
|
||||
/// Zero timout means indefinite
|
||||
|
||||
virtual void close() = 0;
|
||||
/// Closes the connection.
|
||||
|
||||
virtual bool isConnected() = 0;
|
||||
/// Returns true if session is connected, false otherwise.
|
||||
|
||||
void setTimeout(std::size_t timeout);
|
||||
/// Sets the session timeout value.
|
||||
|
||||
std::size_t getTimeout() const;
|
||||
/// Returns the session timeout value.
|
||||
|
||||
void reconnect();
|
||||
/// Closes the connection and opens it again.
|
||||
|
||||
virtual void begin() = 0;
|
||||
/// Starts a transaction.
|
||||
|
||||
@ -77,12 +107,6 @@ public:
|
||||
virtual void rollback() = 0;
|
||||
/// Aborts a transaction.
|
||||
|
||||
virtual void close() = 0;
|
||||
/// Closes the connection.
|
||||
|
||||
virtual bool isConnected() = 0;
|
||||
/// Returns true if session is connected, false otherwise.
|
||||
|
||||
virtual bool canTransact() = 0;
|
||||
/// Returns true if session has transaction capabilities.
|
||||
|
||||
@ -151,12 +175,19 @@ public:
|
||||
/// Throws a NotSupportedException if the requested property is
|
||||
/// not supported by the underlying implementation.
|
||||
|
||||
protected:
|
||||
void setConnectionString(const std::string& connectionString);
|
||||
/// Sets the connection string. Should only be called on
|
||||
/// disconnetced sessions. Throws InvalidAccessException when called on
|
||||
/// a connected session.
|
||||
|
||||
private:
|
||||
SessionImpl();
|
||||
SessionImpl(const SessionImpl&);
|
||||
SessionImpl& operator = (const SessionImpl&);
|
||||
|
||||
std::string _connectionString;
|
||||
std::size_t _timeout;
|
||||
};
|
||||
|
||||
|
||||
@ -169,6 +200,18 @@ inline const std::string& SessionImpl::connectionString()
|
||||
}
|
||||
|
||||
|
||||
inline void SessionImpl::setTimeout(std::size_t timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
inline std::size_t SessionImpl::getTimeout() const
|
||||
{
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
|
||||
inline std::string SessionImpl::uri(const std::string& connector,
|
||||
const std::string& connectionString)
|
||||
{
|
||||
|
@ -76,6 +76,9 @@ public:
|
||||
Statement operator << (const T& t)
|
||||
/// Creates a Statement.
|
||||
{
|
||||
if (!_ptrImpl->isConnected())
|
||||
throw NotConnectedException(_ptrImpl->connectionString());
|
||||
|
||||
Statement stmt(_ptrImpl->createStatementImpl());
|
||||
stmt << t;
|
||||
return stmt;
|
||||
|
@ -435,14 +435,14 @@ private:
|
||||
|
||||
State _state;
|
||||
Limit _extrLimit;
|
||||
std::size_t _lowerLimit;
|
||||
std::size_t _lowerLimit;
|
||||
std::vector<int> _columnsExtracted;
|
||||
SessionImpl& _rSession;
|
||||
Storage _storage;
|
||||
std::ostringstream _ostr;
|
||||
AbstractBindingVec _bindings;
|
||||
AbstractExtractionVecVec _extractors;
|
||||
std::size_t _curDataSet;
|
||||
std::size_t _curDataSet;
|
||||
BulkType _bulkBinding;
|
||||
BulkType _bulkExtraction;
|
||||
|
||||
|
@ -56,6 +56,8 @@ POCO_IMPLEMENT_EXCEPTION(SessionPoolExhaustedException, DataException, "No more
|
||||
POCO_IMPLEMENT_EXCEPTION(SessionPoolExistsException, DataException, "Session already exists in the pool")
|
||||
POCO_IMPLEMENT_EXCEPTION(NoDataException, DataException, "No data found")
|
||||
POCO_IMPLEMENT_EXCEPTION(LengthExceededException, DataException, "Data too long")
|
||||
POCO_IMPLEMENT_EXCEPTION(ConnectionFailedException, DataException, "Connection attempt failed")
|
||||
POCO_IMPLEMENT_EXCEPTION(NotConnectedException, DataException, "Not connected to data source")
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
@ -44,7 +44,8 @@ namespace Data {
|
||||
|
||||
|
||||
PooledSessionImpl::PooledSessionImpl(PooledSessionHolder* pHolder):
|
||||
SessionImpl(pHolder->session()->connectionString()),
|
||||
SessionImpl(pHolder->session()->connectionString(),
|
||||
pHolder->session()->getTimeout()),
|
||||
_pHolder(pHolder, true)
|
||||
{
|
||||
}
|
||||
@ -122,6 +123,12 @@ void PooledSessionImpl::rollback()
|
||||
}
|
||||
|
||||
|
||||
void PooledSessionImpl::open(const std::string& connect)
|
||||
{
|
||||
access()->open(connect);
|
||||
}
|
||||
|
||||
|
||||
void PooledSessionImpl::close()
|
||||
{
|
||||
if (_pHolder)
|
||||
|
@ -45,30 +45,33 @@ namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
Session::Session(Poco::AutoPtr<SessionImpl> ptrImpl):
|
||||
_ptrImpl(ptrImpl),
|
||||
_statementCreator(ptrImpl)
|
||||
Session::Session(Poco::AutoPtr<SessionImpl> pImpl):
|
||||
_pImpl(pImpl),
|
||||
_statementCreator(pImpl)
|
||||
{
|
||||
poco_check_ptr (ptrImpl.get());
|
||||
poco_check_ptr (pImpl.get());
|
||||
}
|
||||
|
||||
|
||||
Session::Session(const std::string& connector, const std::string& connectionString)
|
||||
Session::Session(const std::string& connector,
|
||||
const std::string& connectionString,
|
||||
std::size_t timeout)
|
||||
{
|
||||
Session newSession(SessionFactory::instance().create(connector, connectionString));
|
||||
Session newSession(SessionFactory::instance().create(connector, connectionString, timeout));
|
||||
swap(newSession);
|
||||
}
|
||||
|
||||
|
||||
Session::Session(const std::string& connection)
|
||||
Session::Session(const std::string& connection,
|
||||
std::size_t timeout)
|
||||
{
|
||||
Session newSession(SessionFactory::instance().create(connection));
|
||||
Session newSession(SessionFactory::instance().create(connection, timeout));
|
||||
swap(newSession);
|
||||
}
|
||||
|
||||
|
||||
Session::Session(const Session& other): _ptrImpl(other._ptrImpl),
|
||||
_statementCreator(other._ptrImpl)
|
||||
Session::Session(const Session& other): _pImpl(other._pImpl),
|
||||
_statementCreator(other._pImpl)
|
||||
{
|
||||
}
|
||||
|
||||
@ -90,7 +93,7 @@ void Session::swap(Session& other)
|
||||
{
|
||||
using std::swap;
|
||||
swap(_statementCreator, other._statementCreator);
|
||||
swap(_ptrImpl, other._ptrImpl);
|
||||
swap(_pImpl, other._pImpl);
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,21 +81,24 @@ void SessionFactory::remove(const std::string& key)
|
||||
}
|
||||
|
||||
|
||||
Session SessionFactory::create(const std::string& key, const std::string& connectionString)
|
||||
Session SessionFactory::create(const std::string& key,
|
||||
const std::string& connectionString,
|
||||
std::size_t timeout)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
Connectors::iterator it = _connectors.find(toLower(key));
|
||||
poco_assert (_connectors.end() != it);
|
||||
|
||||
return Session(it->second.ptrSI->createSession(connectionString));
|
||||
return Session(it->second.ptrSI->createSession(connectionString, timeout));
|
||||
}
|
||||
|
||||
|
||||
Session SessionFactory::create(const std::string& uri)
|
||||
Session SessionFactory::create(const std::string& uri,
|
||||
std::size_t timeout)
|
||||
{
|
||||
URI u(uri);
|
||||
poco_assert (!u.getPath().empty());
|
||||
return create(u.getScheme(), u.getPath().substr(1));
|
||||
return create(u.getScheme(), u.getPath().substr(1), timeout);
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,14 +35,16 @@
|
||||
|
||||
|
||||
#include "Poco/Data/SessionImpl.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& connectionString):
|
||||
_connectionString(connectionString)
|
||||
SessionImpl::SessionImpl(const std::string& connectionString, std::size_t timeout):
|
||||
_connectionString(connectionString),
|
||||
_timeout(timeout)
|
||||
{
|
||||
}
|
||||
|
||||
@ -52,4 +54,21 @@ SessionImpl::~SessionImpl()
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::reconnect()
|
||||
{
|
||||
close();
|
||||
open();
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::setConnectionString(const std::string& connectionString)
|
||||
{
|
||||
if (isConnected())
|
||||
throw Poco::InvalidAccessException("Can not change connection string on connected session."
|
||||
" Close the session first.");
|
||||
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Data/DataException.h"
|
||||
|
||||
|
||||
using Poco::icompare;
|
||||
@ -74,6 +75,9 @@ StatementImpl::StatementImpl(SessionImpl& rSession):
|
||||
_bulkBinding(BULK_UNDEFINED),
|
||||
_bulkExtraction(BULK_UNDEFINED)
|
||||
{
|
||||
if (!_rSession.isConnected())
|
||||
throw NotConnectedException(_rSession.connectionString());
|
||||
|
||||
_extractors.resize(1);
|
||||
_columnsExtracted.resize(1, 0);
|
||||
}
|
||||
@ -87,6 +91,13 @@ StatementImpl::~StatementImpl()
|
||||
std::size_t StatementImpl::execute()
|
||||
{
|
||||
resetExtraction();
|
||||
|
||||
if (!_rSession.isConnected())
|
||||
{
|
||||
_state = ST_DONE;
|
||||
throw NotConnectedException(_rSession.connectionString());
|
||||
}
|
||||
|
||||
std::size_t lim = 0;
|
||||
if (_lowerLimit > _extrLimit.value())
|
||||
throw LimitException("Illegal Statement state. Upper limit must not be smaller than the lower limit.");
|
||||
|
@ -53,9 +53,10 @@ Connector::~Connector()
|
||||
}
|
||||
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString)
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString,
|
||||
std::size_t timeout)
|
||||
{
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString));
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString, timeout));
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,7 +60,8 @@ public:
|
||||
const std::string& name() const;
|
||||
/// Returns the name associated with this connector.
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString);
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString,
|
||||
std::size_t timeout = SessionImpl::CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates a test SessionImpl object and initializes it with the given connectionString.
|
||||
|
||||
static void addToFactory();
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "Poco/Data/Date.h"
|
||||
#include "Poco/Data/Time.h"
|
||||
#include "Poco/Data/SimpleRowFormatter.h"
|
||||
#include "Poco/Data/DataException.h"
|
||||
#include "Connector.h"
|
||||
#include "Poco/BinaryReader.h"
|
||||
#include "Poco/BinaryWriter.h"
|
||||
@ -89,6 +90,7 @@ using Poco::Data::AbstractExtractionVec;
|
||||
using Poco::Data::AbstractExtractionVecVec;
|
||||
using Poco::Data::AbstractBinding;
|
||||
using Poco::Data::AbstractBindingVec;
|
||||
using Poco::Data::NotConnectedException;
|
||||
|
||||
|
||||
DataTest::DataTest(const std::string& name): CppUnit::TestCase(name)
|
||||
@ -110,6 +112,10 @@ void DataTest::testSession()
|
||||
assert ("cs" == sess.impl()->connectionString());
|
||||
assert ("test:///cs" == sess.uri());
|
||||
|
||||
assert (sess.getTimeout() == Session::CONNECT_TIMEOUT_DEFAULT);
|
||||
sess.setTimeout(123);
|
||||
assert (sess.getTimeout() == 123);
|
||||
|
||||
Session sess2(SessionFactory::instance().create("TeSt:///Cs"));
|
||||
assert ("test" == sess2.impl()->connectorName());
|
||||
assert ("Cs" == sess2.impl()->connectionString());
|
||||
@ -122,6 +128,36 @@ void DataTest::testSession()
|
||||
std::string str;
|
||||
Statement stmt = (sess << "SELECT * FROM Strings", into(str), limit(50));
|
||||
stmt.execute();
|
||||
|
||||
sess.close();
|
||||
assert (!sess.getFeature("connected"));
|
||||
assert (!sess.isConnected());
|
||||
|
||||
try
|
||||
{
|
||||
stmt.execute();
|
||||
fail ("must fail");
|
||||
} catch (NotConnectedException&) { }
|
||||
|
||||
try
|
||||
{
|
||||
sess << "SELECT * FROM Strings", now;
|
||||
fail ("must fail");
|
||||
} catch (NotConnectedException&) { }
|
||||
|
||||
sess.open();
|
||||
assert (sess.getFeature("connected"));
|
||||
assert (sess.isConnected());
|
||||
|
||||
sess << "SELECT * FROM Strings", now;
|
||||
stmt.execute();
|
||||
|
||||
sess.reconnect();
|
||||
assert (sess.getFeature("connected"));
|
||||
assert (sess.isConnected());
|
||||
|
||||
sess << "SELECT * FROM Strings", now;
|
||||
stmt.execute();
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,8 +40,8 @@ namespace Data {
|
||||
namespace Test {
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& init):
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(init),
|
||||
SessionImpl::SessionImpl(const std::string& init, std::size_t timeout):
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(init, timeout),
|
||||
_f(false),
|
||||
_connected(true)
|
||||
{
|
||||
@ -60,6 +60,24 @@ SessionImpl::~SessionImpl()
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::open(const std::string& connectionString)
|
||||
{
|
||||
_connected = true;
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::close()
|
||||
{
|
||||
_connected = false;
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::isConnected()
|
||||
{
|
||||
return _connected;
|
||||
}
|
||||
|
||||
|
||||
Poco::Data::StatementImpl* SessionImpl::createStatementImpl()
|
||||
{
|
||||
return new TestStatementImpl(*this);
|
||||
@ -81,18 +99,6 @@ void SessionImpl::rollback()
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::close()
|
||||
{
|
||||
_connected = false;
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::isConnected()
|
||||
{
|
||||
return _connected;
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::canTransact()
|
||||
{
|
||||
return false;
|
||||
|
@ -50,7 +50,8 @@ class SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl>
|
||||
/// A no-op implementation of SessionImpl for testing.
|
||||
{
|
||||
public:
|
||||
SessionImpl(const std::string& init);
|
||||
SessionImpl(const std::string& init,
|
||||
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT);
|
||||
/// Creates the SessionImpl. Opens a connection to the database.
|
||||
|
||||
~SessionImpl();
|
||||
@ -59,6 +60,16 @@ public:
|
||||
Poco::Data::StatementImpl* createStatementImpl();
|
||||
/// Returns an test StatementImpl.
|
||||
|
||||
void open(const std::string& connectionString = "");
|
||||
/// Opens the session.
|
||||
|
||||
void close();
|
||||
/// Closes the session.
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true if session is connected to the database,
|
||||
/// false otherwise.
|
||||
|
||||
void begin();
|
||||
/// Starts a transaction.
|
||||
|
||||
@ -67,13 +78,6 @@ public:
|
||||
|
||||
void rollback();
|
||||
/// Aborts a transaction.
|
||||
|
||||
void close();
|
||||
/// Closes the session.
|
||||
|
||||
bool isConnected();
|
||||
/// Returns true if session is connected to the database,
|
||||
/// false otherwise.
|
||||
|
||||
bool canTransact();
|
||||
/// Returns true if session has transaction capabilities.
|
||||
|
Loading…
x
Reference in New Issue
Block a user