mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-16 18:56:52 +02:00
SF [2643953] Improve Data::Session connection
This commit is contained in:
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user