SF [2643953] Improve Data::Session connection

This commit is contained in:
Aleksandar Fabijanic
2009-02-27 03:14:53 +00:00
parent 9bef44cab6
commit 68a79674c1
50 changed files with 689 additions and 165 deletions

View File

@@ -62,7 +62,8 @@ public:
virtual const std::string& name() const; virtual const std::string& name() const;
/// Returns the name associated with this connector. /// 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. /// Creates a MySQL SessionImpl object and initializes it with the given connectionString.
static void registerConnector(); static void registerConnector();

View File

@@ -59,12 +59,18 @@ public:
~SessionHandle(); ~SessionHandle();
/// Destroy handle, close connection /// Destroy handle, close connection
void init(MYSQL* mysql = 0);
/// Initializes the handle iff not initialized.
void options(mysql_option opt); void options(mysql_option opt);
/// Set connection options /// Set connection options
void options(mysql_option opt, bool b); void options(mysql_option opt, bool b);
/// Set connection options /// 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); void connect(const char* host, const char* user, const char* password, const char* db, unsigned int port);
/// Connect to server /// Connect to server

View File

@@ -62,7 +62,8 @@ public:
static const std::string MYSQL_REPEATABLE_READ; static const std::string MYSQL_REPEATABLE_READ;
static const std::string MYSQL_SERIALIZABLE; 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 /// Creates the SessionImpl. Opens a connection to the database
/// ///
/// Connection string format: /// Connection string format:
@@ -81,6 +82,15 @@ public:
Poco::Data::StatementImpl* createStatementImpl(); Poco::Data::StatementImpl* createStatementImpl();
/// Returns an MySQL StatementImpl /// 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(); void begin();
/// Starts a transaction /// Starts a transaction
@@ -90,12 +100,6 @@ public:
void rollback(); void rollback();
/// Aborts a transaction /// Aborts a transaction
void close();
/// Closes the connection
bool isConnected();
/// Returns true if connected, false otherwise.
bool canTransact(); bool canTransact();
/// Returns true if session has transaction capabilities. /// Returns true if session has transaction capabilities.

View File

@@ -64,9 +64,10 @@ const std::string& Connector::name() const
return KEY; 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));
} }

View File

@@ -35,6 +35,7 @@
#include "Poco/Data/MySQL/SessionHandle.h" #include "Poco/Data/MySQL/SessionHandle.h"
#include "Poco/Data/DataException.h"
namespace Poco { namespace Poco {
@@ -42,11 +43,21 @@ namespace Data {
namespace MySQL { namespace MySQL {
SessionHandle::SessionHandle(MYSQL* mysql) SessionHandle::SessionHandle(MYSQL* mysql): _pHandle(0)
{ {
if (!(_pHandle = mysql_init(mysql))) init(mysql);
}
void SessionHandle::init(MYSQL* mysql)
{
if (!_pHandle)
{
_pHandle = mysql_init(mysql);
if (!_pHandle)
throw ConnectionException("mysql_init error"); throw ConnectionException("mysql_init error");
} }
}
SessionHandle::~SessionHandle() SessionHandle::~SessionHandle()
@@ -69,11 +80,17 @@ void SessionHandle::options(mysql_option opt, bool b)
throw ConnectionException("mysql_options error", _pHandle); 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) 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)) 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");
} }

View File

@@ -66,8 +66,8 @@ const std::string SessionImpl::MYSQL_REPEATABLE_READ = "REPEATABLE READ";
const std::string SessionImpl::MYSQL_SERIALIZABLE = "SERIALIZABLE"; const std::string SessionImpl::MYSQL_SERIALIZABLE = "SERIALIZABLE";
SessionImpl::SessionImpl(const std::string& connectionString) : SessionImpl::SessionImpl(const std::string& connectionString, std::size_t timeout) :
Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString)), Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString), timeout),
_handle(0), _handle(0),
_connected(false), _connected(false),
_inTransaction(false) _inTransaction(false)
@@ -76,6 +76,28 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
&SessionImpl::setInsertId, &SessionImpl::setInsertId,
&SessionImpl::getInsertId); &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; std::map<std::string, std::string> options;
// Default values // Default values
@@ -87,9 +109,10 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
options["compress"] = ""; options["compress"] = "";
options["auto-reconnect"] = ""; 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, '='); std::string::const_iterator middle = std::find(start, finish, '=');
if (middle == finish) if (middle == finish)
@@ -97,7 +120,7 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
options[copyStripped(start, middle)] = copyStripped(middle + 1, finish); 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; 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"); throw MySQLException("create session: specify correct auto-reconnect option (true or false) or skip it");
// Real connect // Real connect
_handle.connect( _handle.connect(options["host"].c_str(),
options["host"].c_str(),
options["user"].c_str(), options["user"].c_str(),
options["password"].c_str(), options["password"].c_str(),
options["db"].c_str(), options["db"].c_str(),

View File

@@ -507,6 +507,15 @@ void MySQLTest::testTransaction()
} }
void MySQLTest::testReconnect()
{
if (!_pSession) fail ("Test not available.");
recreatePersonTable();
_pExecutor->reconnect();
}
void MySQLTest::testNullableInt() void MySQLTest::testNullableInt()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@@ -813,6 +822,7 @@ CppUnit::Test* MySQLTest::suite()
CppUnit_addTest(pSuite, MySQLTest, testTupleWithNullable); CppUnit_addTest(pSuite, MySQLTest, testTupleWithNullable);
CppUnit_addTest(pSuite, MySQLTest, testSessionTransaction); CppUnit_addTest(pSuite, MySQLTest, testSessionTransaction);
CppUnit_addTest(pSuite, MySQLTest, testTransaction); CppUnit_addTest(pSuite, MySQLTest, testTransaction);
CppUnit_addTest(pSuite, MySQLTest, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -116,6 +116,8 @@ public:
void testSessionTransaction(); void testSessionTransaction();
void testTransaction(); void testTransaction();
void testReconnect();
void setUp(); void setUp();
void tearDown(); void tearDown();

View File

@@ -476,7 +476,7 @@ void SQLExecutor::insertSingleBulk()
for (x = 0; x < 100; ++x) for (x = 0; x < 100; ++x)
{ {
int i = stmt.execute(); std::size_t i = stmt.execute();
assert (i == 0); assert (i == 0);
} }
@@ -1803,3 +1803,44 @@ void SQLExecutor::transaction(const std::string& connect)
_pSession->setFeature("autoCommit", autoCommit); _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());
}

View File

@@ -113,6 +113,8 @@ public:
void sessionTransaction(const std::string& connect); void sessionTransaction(const std::string& connect);
void transaction(const std::string& connect); void transaction(const std::string& connect);
void reconnect();
private: private:
void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti); void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti);

View File

@@ -65,7 +65,8 @@ public:
const std::string& name() const; const std::string& name() const;
/// Returns the name associated with this connector. /// 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. /// Creates a ODBC SessionImpl object and initializes it with the given connectionString.
static void registerConnector(); static void registerConnector();

View File

@@ -64,6 +64,8 @@ class ODBC_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl>
/// Implements SessionImpl interface /// Implements SessionImpl interface
{ {
public: public:
static const std::size_t ODBC_MAX_FIELD_SIZE = 1024u;
enum TransactionCapability enum TransactionCapability
{ {
ODBC_TXN_CAPABILITY_UNKNOWN = -1, ODBC_TXN_CAPABILITY_UNKNOWN = -1,
@@ -72,11 +74,20 @@ public:
}; };
SessionImpl(const std::string& connect, SessionImpl(const std::string& connect,
Poco::Any maxFieldSize = std::size_t(1024), 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 = ODBC_MAX_FIELD_SIZE,
bool enforceCapability=false, bool enforceCapability=false,
bool autoBind = true, bool autoBind = true,
bool autoExtract = true); bool autoExtract = true);
/// Creates the SessionImpl. Opens a connection to the database /// Creates the SessionImpl. Opens a connection to the database.
~SessionImpl(); ~SessionImpl();
/// Destroys the SessionImpl. /// Destroys the SessionImpl.
@@ -84,6 +95,15 @@ public:
Poco::Data::StatementImpl* createStatementImpl(); Poco::Data::StatementImpl* createStatementImpl();
/// Returns an ODBC StatementImpl /// 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(); void begin();
/// Starts a transaction /// Starts a transaction
@@ -93,12 +113,6 @@ public:
void rollback(); void rollback();
/// Aborts a transaction /// Aborts a transaction
void close();
/// Closes the connection
bool isConnected();
/// Returns true if session is connected
bool isTransaction(); bool isTransaction();
/// Returns true iff a transaction is in progress. /// Returns true iff a transaction is in progress.
@@ -161,9 +175,6 @@ private:
static const int FUNCTIONS = SQL_API_ODBC3_ALL_FUNCTIONS_SIZE; 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=""); void checkError(SQLRETURN rc, const std::string& msg="");
Poco::UInt32 getDefaultTransactionIsolation(); Poco::UInt32 getDefaultTransactionIsolation();

View File

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

View File

@@ -49,6 +49,24 @@ namespace Data {
namespace ODBC { 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, SessionImpl::SessionImpl(const std::string& connect,
Poco::Any maxFieldSize, Poco::Any maxFieldSize,
bool enforceCapability, 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}; SQLCHAR connectOutput[512] = {0};
SQLSMALLINT result; SQLSMALLINT result;
@@ -99,9 +139,10 @@ void SessionImpl::open()
, &result , &result
, SQL_DRIVER_NOPROMPT))) , SQL_DRIVER_NOPROMPT)))
{ {
ConnectionException exc(_db); ConnectionError err(_db);
std::string errStr = err.toString();
close(); close();
throw exc; throw ConnectionFailedException(errStr);
} }
_dataTypes.fillTypeInfo(_db); _dataTypes.fillTypeInfo(_db);

View File

@@ -681,6 +681,7 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit_addTest(pSuite, ODBCDB2Test, testSessionTransaction); CppUnit_addTest(pSuite, ODBCDB2Test, testSessionTransaction);
CppUnit_addTest(pSuite, ODBCDB2Test, testTransaction); CppUnit_addTest(pSuite, ODBCDB2Test, testTransaction);
CppUnit_addTest(pSuite, ODBCDB2Test, testTransactor); CppUnit_addTest(pSuite, ODBCDB2Test, testTransactor);
CppUnit_addTest(pSuite, ODBCDB2Test, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -497,6 +497,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testSessionTransaction); CppUnit_addTest(pSuite, ODBCMySQLTest, testSessionTransaction);
CppUnit_addTest(pSuite, ODBCMySQLTest, testTransaction); CppUnit_addTest(pSuite, ODBCMySQLTest, testTransaction);
CppUnit_addTest(pSuite, ODBCMySQLTest, testTransactor); CppUnit_addTest(pSuite, ODBCMySQLTest, testTransactor);
CppUnit_addTest(pSuite, ODBCMySQLTest, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -922,6 +922,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testSessionTransaction); CppUnit_addTest(pSuite, ODBCOracleTest, testSessionTransaction);
CppUnit_addTest(pSuite, ODBCOracleTest, testTransaction); CppUnit_addTest(pSuite, ODBCOracleTest, testTransaction);
CppUnit_addTest(pSuite, ODBCOracleTest, testTransactor); CppUnit_addTest(pSuite, ODBCOracleTest, testTransactor);
CppUnit_addTest(pSuite, ODBCOracleTest, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -659,6 +659,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSessionTransaction); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSessionTransaction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransaction); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransaction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransactor); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransactor);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -809,6 +809,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSessionTransaction); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSessionTransaction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransaction); CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransaction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransactor); CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransactor);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -400,6 +400,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSessionTransaction); CppUnit_addTest(pSuite, ODBCSQLiteTest, testSessionTransaction);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransaction); CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransaction);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransactor); CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransactor);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -47,12 +47,14 @@
#include "Poco/Data/ODBC/Diagnostics.h" #include "Poco/Data/ODBC/Diagnostics.h"
#include "Poco/Data/ODBC/ODBCException.h" #include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/ODBC/ODBCStatementImpl.h" #include "Poco/Data/ODBC/ODBCStatementImpl.h"
#include "Poco/Data/DataException.h"
#include <sqltypes.h> #include <sqltypes.h>
#include <iostream> #include <iostream>
using namespace Poco::Data::Keywords; using namespace Poco::Data::Keywords;
using Poco::Data::Session; using Poco::Data::Session;
using Poco::Data::ConnectionFailedException;
using Poco::Data::CLOB; using Poco::Data::CLOB;
using Poco::Data::ODBC::Utility; using Poco::Data::ODBC::Utility;
using Poco::Data::ODBC::ODBCException; 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, bool ODBCTest::canConnect(const std::string& driver,
std::string& dsn, std::string& dsn,
std::string& uid, std::string& uid,
@@ -1262,9 +1281,9 @@ ODBCTest::SessionPtr ODBCTest::init(const std::string& driver,
try try
{ {
return new Session(Poco::Data::ODBC::Connector::KEY, dbConnString); 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; return 0;
} }
} }

View File

@@ -167,6 +167,8 @@ public:
virtual void testTransaction(); virtual void testTransaction();
virtual void testTransactor(); virtual void testTransactor();
virtual void testReconnect();
protected: protected:
typedef Poco::Data::ODBC::Utility::DriverMap Drivers; typedef Poco::Data::ODBC::Utility::DriverMap Drivers;

View File

@@ -85,6 +85,7 @@ using Poco::Data::CLOB;
using Poco::Data::Date; using Poco::Data::Date;
using Poco::Data::Time; using Poco::Data::Time;
using Poco::Data::Transaction; using Poco::Data::Transaction;
using Poco::Data::NotConnectedException;
using Poco::Data::ODBC::Utility; using Poco::Data::ODBC::Utility;
using Poco::Data::ODBC::Preparator; using Poco::Data::ODBC::Preparator;
using Poco::Data::ODBC::ConnectionException; using Poco::Data::ODBC::ConnectionException;
@@ -3763,3 +3764,44 @@ void SQLExecutor::transactor()
session().setFeature("autoCommit", autoCommit); 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());
}

View File

@@ -518,6 +518,8 @@ public:
void transaction(const std::string& connect); void transaction(const std::string& connect);
void transactor(); void transactor();
void reconnect();
private: private:
static const std::string MULTI_INSERT; static const std::string MULTI_INSERT;
static const std::string MULTI_SELECT; static const std::string MULTI_SELECT;

View File

@@ -65,7 +65,8 @@ public:
const std::string& name() const; const std::string& name() const;
/// Returns the name associated with this connector. /// 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. /// Creates a SQLite SessionImpl object and initializes it with the given connectionString.
static void registerConnector(); static void registerConnector();

View File

@@ -59,7 +59,8 @@ class SQLite_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl
/// Implements SessionImpl interface. /// Implements SessionImpl interface.
{ {
public: 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. /// Creates the SessionImpl. Opens a connection to the database.
~SessionImpl(); ~SessionImpl();
@@ -77,6 +78,9 @@ public:
void rollback(); void rollback();
/// Aborts a transaction. /// Aborts a transaction.
void open(const std::string& connect = "");
/// Opens a connection to the Database.
void close(); void close();
/// Closes the session. /// Closes the session.
@@ -107,8 +111,6 @@ public:
/// Returns the name of the connector. /// Returns the name of the connector.
private: private:
void open();
/// Opens a connection to the Database.
std::string _connector; std::string _connector;
sqlite3* _pDB; sqlite3* _pDB;

View File

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

View File

@@ -38,7 +38,10 @@
#include "Poco/Data/SQLite/Utility.h" #include "Poco/Data/SQLite/Utility.h"
#include "Poco/Data/SQLite/SQLiteStatementImpl.h" #include "Poco/Data/SQLite/SQLiteStatementImpl.h"
#include "Poco/Data/SQLite/Connector.h" #include "Poco/Data/SQLite/Connector.h"
#include "Poco/Data/SQLite/SQLiteException.h"
#include "Poco/Data/Session.h" #include "Poco/Data/Session.h"
#include "Poco/ActiveMethod.h"
#include "Poco/ActiveResult.h"
#include "Poco/String.h" #include "Poco/String.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include "sqlite3.h" #include "sqlite3.h"
@@ -55,8 +58,8 @@ const std::string SessionImpl::COMMIT_TRANSACTION("COMMIT");
const std::string SessionImpl::ABORT_TRANSACTION("ROLLBACK"); const std::string SessionImpl::ABORT_TRANSACTION("ROLLBACK");
SessionImpl::SessionImpl(const std::string& fileName): SessionImpl::SessionImpl(const std::string& fileName, std::size_t timeout):
Poco::Data::AbstractSessionImpl<SessionImpl>(fileName), Poco::Data::AbstractSessionImpl<SessionImpl>(fileName, timeout),
_connector(toLower(Connector::KEY)), _connector(toLower(Connector::KEY)),
_pDB(0), _pDB(0),
_connected(false), _connected(false),
@@ -133,15 +136,62 @@ bool SessionImpl::isTransactionIsolation(Poco::UInt32 ti)
} }
void SessionImpl::open() class ActiveConnector
{ {
int rc = sqlite3_open(connectionString().c_str(), &_pDB); public:
ActiveConnector(const std::string& connectString, sqlite3** ppDB):
connect(this, &ActiveConnector::connectImpl),
_connectString(connectString),
_ppDB(ppDB)
{
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) if (rc != 0)
{ {
close(); close();
Utility::throwException(rc); Utility::throwException(rc);
} }
} catch (SQLiteException& ex)
{
throw ConnectionFailedException(ex.displayText());
}
_connected = true; _connected = true;
} }

View File

@@ -43,6 +43,7 @@
#include "Poco/Data/SQLite/Connector.h" #include "Poco/Data/SQLite/Connector.h"
#include "Poco/Data/SQLite/SQLiteException.h" #include "Poco/Data/SQLite/SQLiteException.h"
#include "Poco/Data/TypeHandler.h" #include "Poco/Data/TypeHandler.h"
#include "Poco/Data/DataException.h"
#include "Poco/Tuple.h" #include "Poco/Tuple.h"
#include "Poco/Any.h" #include "Poco/Any.h"
#include "Poco/SharedPtr.h" #include "Poco/SharedPtr.h"
@@ -71,6 +72,7 @@ using Poco::Data::Time;
using Poco::Data::AbstractExtractionVec; using Poco::Data::AbstractExtractionVec;
using Poco::Data::AbstractExtractionVecVec; using Poco::Data::AbstractExtractionVecVec;
using Poco::Data::AbstractBindingVec; using Poco::Data::AbstractBindingVec;
using Poco::Data::NotConnectedException;
using Poco::Tuple; using Poco::Tuple;
using Poco::Any; using Poco::Any;
using Poco::AnyCast; 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() void SQLiteTest::setUp()
{ {
} }
@@ -2404,6 +2448,7 @@ CppUnit::Test* SQLiteTest::suite()
CppUnit_addTest(pSuite, SQLiteTest, testBindingCount); CppUnit_addTest(pSuite, SQLiteTest, testBindingCount);
CppUnit_addTest(pSuite, SQLiteTest, testMultipleResults); CppUnit_addTest(pSuite, SQLiteTest, testMultipleResults);
CppUnit_addTest(pSuite, SQLiteTest, testPair); CppUnit_addTest(pSuite, SQLiteTest, testPair);
CppUnit_addTest(pSuite, SQLiteTest, testReconnect);
return pSuite; return pSuite;
} }

View File

@@ -129,6 +129,8 @@ public:
void testBindingCount(); void testBindingCount();
void testMultipleResults(); void testMultipleResults();
void testReconnect();
void setUp(); void setUp();
void tearDown(); void tearDown();

View File

@@ -72,7 +72,8 @@ public:
typedef Poco::Any (C::*PropertyGetter)(const std::string&); typedef Poco::Any (C::*PropertyGetter)(const std::string&);
/// The getter method for a property. /// The getter method for a property.
AbstractSessionImpl(const std::string& connectionString): SessionImpl(connectionString), AbstractSessionImpl(const std::string& connectionString,
std::size_t timeout = CONNECT_TIMEOUT_DEFAULT): SessionImpl(connectionString, timeout),
_storage(std::string("deque")), _storage(std::string("deque")),
_bulk(false), _bulk(false),
_emptyStringIsNull(false), _emptyStringIsNull(false),

View File

@@ -66,7 +66,8 @@ public:
virtual const std::string& name() const = 0; virtual const std::string& name() const = 0;
/// Returns the name associated with this connector. /// 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. /// Create a SessionImpl object and initialize it with the given connectionString.
}; };

View File

@@ -62,6 +62,8 @@ POCO_DECLARE_EXCEPTION(Data_API, SessionPoolExhaustedException, DataException)
POCO_DECLARE_EXCEPTION(Data_API, SessionPoolExistsException, DataException) POCO_DECLARE_EXCEPTION(Data_API, SessionPoolExistsException, DataException)
POCO_DECLARE_EXCEPTION(Data_API, NoDataException, DataException) POCO_DECLARE_EXCEPTION(Data_API, NoDataException, DataException)
POCO_DECLARE_EXCEPTION(Data_API, LengthExceededException, 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 } } // namespace Poco::Data

View File

@@ -70,6 +70,7 @@ public:
void begin(); void begin();
void commit(); void commit();
void rollback(); void rollback();
void open(const std::string& connect = "");
void close(); void close();
bool isConnected(); bool isConnected();
bool canTransact(); bool canTransact();

View File

@@ -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. /// For complete list of supported data types with their respective specifications, see the documentation for format in Foundation.
{ {
public: 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_UNCOMMITTED = 0x00000001L;
static const Poco::UInt32 TRANSACTION_READ_COMMITTED = 0x00000002L; static const Poco::UInt32 TRANSACTION_READ_COMMITTED = 0x00000002L;
static const Poco::UInt32 TRANSACTION_REPEATABLE_READ = 0x00000004L; static const Poco::UInt32 TRANSACTION_REPEATABLE_READ = 0x00000004L;
@@ -181,11 +182,14 @@ public:
Session(Poco::AutoPtr<SessionImpl> ptrImpl); Session(Poco::AutoPtr<SessionImpl> ptrImpl);
/// Creates the Session. /// 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 /// Creates a new session, using the given connector (which must have
/// been registered), and connectionString. /// 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 /// Creates a new session, using the given connection (must be in
/// "connection:///connectionString" format). /// "connection:///connectionString" format).
@@ -211,6 +215,29 @@ public:
StatementImpl* createStatementImpl(); StatementImpl* createStatementImpl();
/// Creates a StatementImpl. /// 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(); void begin();
/// Starts a transaction. /// Starts a transaction.
@@ -220,12 +247,6 @@ public:
void rollback(); void rollback();
/// Rolls back and ends a transaction. /// Rolls back and ends a transaction.
void close();
/// Closes the session.
bool isConnected();
/// Returns true iff session is connected, false otherwise.
bool canTransact(); bool canTransact();
/// Returns true if session has transaction capabilities. /// Returns true if session has transaction capabilities.
@@ -296,7 +317,7 @@ public:
private: private:
Session(); Session();
Poco::AutoPtr<SessionImpl> _ptrImpl; Poco::AutoPtr<SessionImpl> _pImpl;
StatementCreator _statementCreator; StatementCreator _statementCreator;
}; };
@@ -306,73 +327,97 @@ private:
// //
inline StatementImpl* Session::createStatementImpl() 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(); _pImpl->open(connect);
}
inline void Session::commit()
{
return _ptrImpl->commit();
}
inline void Session::rollback()
{
return _ptrImpl->rollback();
} }
inline void Session::close() inline void Session::close()
{ {
_ptrImpl->close(); _pImpl->close();
} }
inline bool Session::isConnected() 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() inline bool Session::canTransact()
{ {
return _ptrImpl->canTransact(); return _pImpl->canTransact();
} }
inline bool Session::isTransaction() inline bool Session::isTransaction()
{ {
return _ptrImpl->isTransaction(); return _pImpl->isTransaction();
} }
inline void Session::setTransactionIsolation(Poco::UInt32 ti) inline void Session::setTransactionIsolation(Poco::UInt32 ti)
{ {
_ptrImpl->setTransactionIsolation(ti); _pImpl->setTransactionIsolation(ti);
} }
inline Poco::UInt32 Session::getTransactionIsolation() inline Poco::UInt32 Session::getTransactionIsolation()
{ {
return _ptrImpl->getTransactionIsolation(); return _pImpl->getTransactionIsolation();
} }
inline bool Session::hasTransactionIsolation(Poco::UInt32 ti) inline bool Session::hasTransactionIsolation(Poco::UInt32 ti)
{ {
return _ptrImpl->hasTransactionIsolation(ti); return _pImpl->hasTransactionIsolation(ti);
} }
inline bool Session::isTransactionIsolation(Poco::UInt32 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() inline std::string Session::uri()
{ {
return _ptrImpl->uri(); return _pImpl->uri();
} }
inline void Session::setFeature(const std::string& name, bool state) 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 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) 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 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() inline SessionImpl* Session::impl()
{ {
return _ptrImpl; return _pImpl;
} }

View File

@@ -83,11 +83,14 @@ public:
/// Lowers the reference count for the Connector registered under that key. If the count reaches zero, /// Lowers the reference count for the Connector registered under that key. If the count reaches zero,
/// the object is removed. /// 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 /// Creates a Session for the given key with the connectionString. Throws an Poco:Data::UnknownDataBaseException
/// if no Connector is registered for that key. /// 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). /// 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. /// Throws an Poco:Data::UnknownDataBaseException if no Connector is registered for the key.

View File

@@ -59,7 +59,14 @@ class Data_API SessionImpl: public Poco::RefCountedObject
/// SessionImpl objects are noncopyable. /// SessionImpl objects are noncopyable.
{ {
public: 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. /// Creates the SessionImpl.
virtual ~SessionImpl(); virtual ~SessionImpl();
@@ -68,6 +75,29 @@ public:
virtual StatementImpl* createStatementImpl() = 0; virtual StatementImpl* createStatementImpl() = 0;
/// Creates a StatementImpl. /// 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; virtual void begin() = 0;
/// Starts a transaction. /// Starts a transaction.
@@ -77,12 +107,6 @@ public:
virtual void rollback() = 0; virtual void rollback() = 0;
/// Aborts a transaction. /// 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; virtual bool canTransact() = 0;
/// Returns true if session has transaction capabilities. /// Returns true if session has transaction capabilities.
@@ -151,12 +175,19 @@ public:
/// Throws a NotSupportedException if the requested property is /// Throws a NotSupportedException if the requested property is
/// not supported by the underlying implementation. /// 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: private:
SessionImpl(); SessionImpl();
SessionImpl(const SessionImpl&); SessionImpl(const SessionImpl&);
SessionImpl& operator = (const SessionImpl&); SessionImpl& operator = (const SessionImpl&);
std::string _connectionString; 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, inline std::string SessionImpl::uri(const std::string& connector,
const std::string& connectionString) const std::string& connectionString)
{ {

View File

@@ -76,6 +76,9 @@ public:
Statement operator << (const T& t) Statement operator << (const T& t)
/// Creates a Statement. /// Creates a Statement.
{ {
if (!_ptrImpl->isConnected())
throw NotConnectedException(_ptrImpl->connectionString());
Statement stmt(_ptrImpl->createStatementImpl()); Statement stmt(_ptrImpl->createStatementImpl());
stmt << t; stmt << t;
return stmt; return stmt;

View File

@@ -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(SessionPoolExistsException, DataException, "Session already exists in the pool")
POCO_IMPLEMENT_EXCEPTION(NoDataException, DataException, "No data found") POCO_IMPLEMENT_EXCEPTION(NoDataException, DataException, "No data found")
POCO_IMPLEMENT_EXCEPTION(LengthExceededException, DataException, "Data too long") 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 } } // namespace Poco::Data

View File

@@ -44,7 +44,8 @@ namespace Data {
PooledSessionImpl::PooledSessionImpl(PooledSessionHolder* pHolder): PooledSessionImpl::PooledSessionImpl(PooledSessionHolder* pHolder):
SessionImpl(pHolder->session()->connectionString()), SessionImpl(pHolder->session()->connectionString(),
pHolder->session()->getTimeout()),
_pHolder(pHolder, true) _pHolder(pHolder, true)
{ {
} }
@@ -122,6 +123,12 @@ void PooledSessionImpl::rollback()
} }
void PooledSessionImpl::open(const std::string& connect)
{
access()->open(connect);
}
void PooledSessionImpl::close() void PooledSessionImpl::close()
{ {
if (_pHolder) if (_pHolder)

View File

@@ -45,30 +45,33 @@ namespace Poco {
namespace Data { namespace Data {
Session::Session(Poco::AutoPtr<SessionImpl> ptrImpl): Session::Session(Poco::AutoPtr<SessionImpl> pImpl):
_ptrImpl(ptrImpl), _pImpl(pImpl),
_statementCreator(ptrImpl) _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); 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); swap(newSession);
} }
Session::Session(const Session& other): _ptrImpl(other._ptrImpl), Session::Session(const Session& other): _pImpl(other._pImpl),
_statementCreator(other._ptrImpl) _statementCreator(other._pImpl)
{ {
} }
@@ -90,7 +93,7 @@ void Session::swap(Session& other)
{ {
using std::swap; using std::swap;
swap(_statementCreator, other._statementCreator); swap(_statementCreator, other._statementCreator);
swap(_ptrImpl, other._ptrImpl); swap(_pImpl, other._pImpl);
} }

View File

@@ -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); Poco::FastMutex::ScopedLock lock(_mutex);
Connectors::iterator it = _connectors.find(toLower(key)); Connectors::iterator it = _connectors.find(toLower(key));
poco_assert (_connectors.end() != it); 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); URI u(uri);
poco_assert (!u.getPath().empty()); poco_assert (!u.getPath().empty());
return create(u.getScheme(), u.getPath().substr(1)); return create(u.getScheme(), u.getPath().substr(1), timeout);
} }

View File

@@ -35,14 +35,16 @@
#include "Poco/Data/SessionImpl.h" #include "Poco/Data/SessionImpl.h"
#include "Poco/Exception.h"
namespace Poco { namespace Poco {
namespace Data { namespace Data {
SessionImpl::SessionImpl(const std::string& connectionString): SessionImpl::SessionImpl(const std::string& connectionString, std::size_t timeout):
_connectionString(connectionString) _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 } } // namespace Poco::Data

View File

@@ -45,6 +45,7 @@
#include "Poco/SharedPtr.h" #include "Poco/SharedPtr.h"
#include "Poco/DateTime.h" #include "Poco/DateTime.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include "Poco/Data/DataException.h"
using Poco::icompare; using Poco::icompare;
@@ -74,6 +75,9 @@ StatementImpl::StatementImpl(SessionImpl& rSession):
_bulkBinding(BULK_UNDEFINED), _bulkBinding(BULK_UNDEFINED),
_bulkExtraction(BULK_UNDEFINED) _bulkExtraction(BULK_UNDEFINED)
{ {
if (!_rSession.isConnected())
throw NotConnectedException(_rSession.connectionString());
_extractors.resize(1); _extractors.resize(1);
_columnsExtracted.resize(1, 0); _columnsExtracted.resize(1, 0);
} }
@@ -87,6 +91,13 @@ StatementImpl::~StatementImpl()
std::size_t StatementImpl::execute() std::size_t StatementImpl::execute()
{ {
resetExtraction(); resetExtraction();
if (!_rSession.isConnected())
{
_state = ST_DONE;
throw NotConnectedException(_rSession.connectionString());
}
std::size_t lim = 0; std::size_t lim = 0;
if (_lowerLimit > _extrLimit.value()) if (_lowerLimit > _extrLimit.value())
throw LimitException("Illegal Statement state. Upper limit must not be smaller than the lower limit."); throw LimitException("Illegal Statement state. Upper limit must not be smaller than the lower limit.");

View File

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

View File

@@ -60,7 +60,8 @@ public:
const std::string& name() const; const std::string& name() const;
/// Returns the name associated with this connector. /// 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. /// Creates a test SessionImpl object and initializes it with the given connectionString.
static void addToFactory(); static void addToFactory();

View File

@@ -42,6 +42,7 @@
#include "Poco/Data/Date.h" #include "Poco/Data/Date.h"
#include "Poco/Data/Time.h" #include "Poco/Data/Time.h"
#include "Poco/Data/SimpleRowFormatter.h" #include "Poco/Data/SimpleRowFormatter.h"
#include "Poco/Data/DataException.h"
#include "Connector.h" #include "Connector.h"
#include "Poco/BinaryReader.h" #include "Poco/BinaryReader.h"
#include "Poco/BinaryWriter.h" #include "Poco/BinaryWriter.h"
@@ -89,6 +90,7 @@ using Poco::Data::AbstractExtractionVec;
using Poco::Data::AbstractExtractionVecVec; using Poco::Data::AbstractExtractionVecVec;
using Poco::Data::AbstractBinding; using Poco::Data::AbstractBinding;
using Poco::Data::AbstractBindingVec; using Poco::Data::AbstractBindingVec;
using Poco::Data::NotConnectedException;
DataTest::DataTest(const std::string& name): CppUnit::TestCase(name) DataTest::DataTest(const std::string& name): CppUnit::TestCase(name)
@@ -110,6 +112,10 @@ void DataTest::testSession()
assert ("cs" == sess.impl()->connectionString()); assert ("cs" == sess.impl()->connectionString());
assert ("test:///cs" == sess.uri()); 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")); Session sess2(SessionFactory::instance().create("TeSt:///Cs"));
assert ("test" == sess2.impl()->connectorName()); assert ("test" == sess2.impl()->connectorName());
assert ("Cs" == sess2.impl()->connectionString()); assert ("Cs" == sess2.impl()->connectionString());
@@ -122,6 +128,36 @@ void DataTest::testSession()
std::string str; std::string str;
Statement stmt = (sess << "SELECT * FROM Strings", into(str), limit(50)); Statement stmt = (sess << "SELECT * FROM Strings", into(str), limit(50));
stmt.execute(); 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();
} }

View File

@@ -40,8 +40,8 @@ namespace Data {
namespace Test { namespace Test {
SessionImpl::SessionImpl(const std::string& init): SessionImpl::SessionImpl(const std::string& init, std::size_t timeout):
Poco::Data::AbstractSessionImpl<SessionImpl>(init), Poco::Data::AbstractSessionImpl<SessionImpl>(init, timeout),
_f(false), _f(false),
_connected(true) _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() Poco::Data::StatementImpl* SessionImpl::createStatementImpl()
{ {
return new TestStatementImpl(*this); return new TestStatementImpl(*this);
@@ -81,18 +99,6 @@ void SessionImpl::rollback()
} }
void SessionImpl::close()
{
_connected = false;
}
bool SessionImpl::isConnected()
{
return _connected;
}
bool SessionImpl::canTransact() bool SessionImpl::canTransact()
{ {
return false; return false;

View File

@@ -50,7 +50,8 @@ class SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl>
/// A no-op implementation of SessionImpl for testing. /// A no-op implementation of SessionImpl for testing.
{ {
public: 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. /// Creates the SessionImpl. Opens a connection to the database.
~SessionImpl(); ~SessionImpl();
@@ -59,6 +60,16 @@ public:
Poco::Data::StatementImpl* createStatementImpl(); Poco::Data::StatementImpl* createStatementImpl();
/// Returns an test StatementImpl. /// 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(); void begin();
/// Starts a transaction. /// Starts a transaction.
@@ -68,13 +79,6 @@ public:
void rollback(); void rollback();
/// Aborts a transaction. /// Aborts a transaction.
void close();
/// Closes the session.
bool isConnected();
/// Returns true if session is connected to the database,
/// false otherwise.
bool canTransact(); bool canTransact();
/// Returns true if session has transaction capabilities. /// Returns true if session has transaction capabilities.