mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-13 18:45:10 +01:00
[SF 2580108] Improve transaction handling
This commit is contained in:
parent
ad543acb58
commit
d11f007d23
@ -270,6 +270,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\AbstractSessionImpl.h">
|
RelativePath=".\include\Poco\Data\AbstractSessionImpl.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\Poco\Data\AutoTransaction.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\Binder.h">
|
RelativePath=".\include\Poco\Data\Binder.h">
|
||||||
</File>
|
</File>
|
||||||
@ -366,6 +369,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\Time.h">
|
RelativePath=".\include\Poco\Data\Time.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\Poco\Data\Transaction.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\TypeHandler.h">
|
RelativePath=".\include\Poco\Data\TypeHandler.h">
|
||||||
</File>
|
</File>
|
||||||
@ -454,6 +460,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\src\Time.cpp">
|
RelativePath=".\src\Time.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\Transaction.cpp">
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
@ -505,6 +505,10 @@
|
|||||||
RelativePath=".\include\Poco\Data\Time.h"
|
RelativePath=".\include\Poco\Data\Time.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\Poco\Data\Transaction.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\TypeHandler.h"
|
RelativePath=".\include\Poco\Data\TypeHandler.h"
|
||||||
>
|
>
|
||||||
@ -537,10 +541,6 @@
|
|||||||
RelativePath=".\src\AbstractPreparator.cpp"
|
RelativePath=".\src\AbstractPreparator.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath=".\src\AutoTransaction.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\Bulk.cpp"
|
RelativePath=".\src\Bulk.cpp"
|
||||||
>
|
>
|
||||||
@ -625,6 +625,10 @@
|
|||||||
RelativePath=".\src\Time.cpp"
|
RelativePath=".\src\Time.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\Transaction.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
@ -510,6 +510,10 @@
|
|||||||
RelativePath=".\include\Poco\Data\Time.h"
|
RelativePath=".\include\Poco\Data\Time.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\Poco\Data\Transaction.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\TypeHandler.h"
|
RelativePath=".\include\Poco\Data\TypeHandler.h"
|
||||||
>
|
>
|
||||||
@ -542,10 +546,6 @@
|
|||||||
RelativePath=".\src\AbstractPreparator.cpp"
|
RelativePath=".\src\AbstractPreparator.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath=".\src\AutoTransaction.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\Bulk.cpp"
|
RelativePath=".\src\Bulk.cpp"
|
||||||
>
|
>
|
||||||
@ -630,6 +630,10 @@
|
|||||||
RelativePath=".\src\Time.cpp"
|
RelativePath=".\src\Time.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\Transaction.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
include $(POCO_BASE)/build/rules/global
|
include $(POCO_BASE)/build/rules/global
|
||||||
|
|
||||||
objects = AbstractBinder AbstractBinding AbstractExtraction AbstractExtractor \
|
objects = AbstractBinder AbstractBinding AbstractExtraction AbstractExtractor \
|
||||||
AbstractPreparation AbstractPreparator ArchiveStrategy AutoTransaction \
|
AbstractPreparation AbstractPreparator ArchiveStrategy Transaction \
|
||||||
Bulk Connector DataException Date Limit MetaColumn \
|
Bulk Connector DataException Date Limit MetaColumn \
|
||||||
PooledSessionHolder PooledSessionImpl Position \
|
PooledSessionHolder PooledSessionImpl Position \
|
||||||
Range RecordSet Row RowFilter RowFormatter RowIterator \
|
Range RecordSet Row RowFilter RowFormatter RowIterator \
|
||||||
|
@ -4,6 +4,9 @@ Microsoft Visual Studio Solution File, Format Version 10.00
|
|||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MySQL", "MySQL_VS90.vcproj", "{D9C692A6-D089-4269-B444-C445ED192F0D}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MySQL", "MySQL_VS90.vcproj", "{D9C692A6-D089-4269-B444-C445ED192F0D}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestSuite", "testsuite\TestSuite_VS90.vcproj", "{1B30A91B-375F-11DB-837B-00123FC423B5}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestSuite", "testsuite\TestSuite_VS90.vcproj", "{1B30A91B-375F-11DB-837B-00123FC423B5}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{D9C692A6-D089-4269-B444-C445ED192F0D} = {D9C692A6-D089-4269-B444-C445ED192F0D}
|
||||||
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories=".\include;.\src;..\..\Foundation\include;..\..\Data\include"
|
AdditionalIncludeDirectories=".\include;.\src;..\..\Foundation\include;..\..\Data\include;.\include\Poco\Data\MySQL\mysql"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;POCO_DLL;NO_TCL;THREADSAFE;__LCC__"
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;POCO_DLL;NO_TCL;THREADSAFE;__LCC__"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
|
@ -89,7 +89,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MYSQL* h;
|
MYSQL* _pHandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ private:
|
|||||||
|
|
||||||
inline SessionHandle::operator MYSQL* ()
|
inline SessionHandle::operator MYSQL* ()
|
||||||
{
|
{
|
||||||
return h;
|
return _pHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "Poco/Data/MySQL/MySQL.h"
|
#include "Poco/Data/MySQL/MySQL.h"
|
||||||
#include "Poco/Data/AbstractSessionImpl.h"
|
#include "Poco/Data/AbstractSessionImpl.h"
|
||||||
#include "Poco/Data/MySQL/SessionHandle.h"
|
#include "Poco/Data/MySQL/SessionHandle.h"
|
||||||
|
#include "Poco/Mutex.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@ -54,6 +55,10 @@ class MySQL_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl>
|
|||||||
/// Implements SessionImpl interface
|
/// Implements SessionImpl interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static const std::string MYSQL_READ_UNCOMMITTED;
|
||||||
|
static const std::string MYSQL_READ_COMMITTED;
|
||||||
|
static const std::string MYSQL_REPEATABLE_READ;
|
||||||
|
static const std::string MYSQL_SERIALIZABLE;
|
||||||
|
|
||||||
SessionImpl(const std::string& connectionString);
|
SessionImpl(const std::string& connectionString);
|
||||||
/// Creates the SessionImpl. Opens a connection to the database
|
/// Creates the SessionImpl. Opens a connection to the database
|
||||||
@ -71,26 +76,49 @@ public:
|
|||||||
~SessionImpl();
|
~SessionImpl();
|
||||||
/// Destroys the SessionImpl.
|
/// Destroys the SessionImpl.
|
||||||
|
|
||||||
virtual Poco::Data::StatementImpl* createStatementImpl();
|
Poco::Data::StatementImpl* createStatementImpl();
|
||||||
/// Returns an MySQL StatementImpl
|
/// Returns an MySQL StatementImpl
|
||||||
|
|
||||||
virtual void begin();
|
void begin();
|
||||||
/// Starts a transaction
|
/// Starts a transaction
|
||||||
|
|
||||||
virtual void commit();
|
void commit();
|
||||||
/// Commits and ends a transaction
|
/// Commits and ends a transaction
|
||||||
|
|
||||||
virtual void rollback();
|
void rollback();
|
||||||
/// Aborts a transaction
|
/// Aborts a transaction
|
||||||
|
|
||||||
virtual void close();
|
void close();
|
||||||
/// Closes the connection
|
/// Closes the connection
|
||||||
|
|
||||||
virtual bool isConnected();
|
bool isConnected();
|
||||||
/// Returns true iff session is connected.
|
/// Returns true if connected, false otherwise.
|
||||||
|
|
||||||
virtual bool isTransaction();
|
bool canTransact();
|
||||||
/// Returns true iff a transaction is in progress.
|
/// Returns true if session has transaction capabilities.
|
||||||
|
|
||||||
|
bool isTransaction();
|
||||||
|
/// Returns true iff a transaction is a transaction is in progress, false otherwise.
|
||||||
|
|
||||||
|
void setTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Sets the transaction isolation level.
|
||||||
|
|
||||||
|
Poco::UInt32 getTransactionIsolation();
|
||||||
|
/// Returns the transaction isolation level.
|
||||||
|
|
||||||
|
bool hasTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponding
|
||||||
|
/// to the supplied bitmask is supported.
|
||||||
|
|
||||||
|
bool isTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponds
|
||||||
|
/// to the supplied bitmask.
|
||||||
|
|
||||||
|
void autoCommit(const std::string&, bool val);
|
||||||
|
/// Sets autocommit property for the session.
|
||||||
|
|
||||||
|
bool isAutoCommit(const std::string& name="");
|
||||||
|
/// Returns autocommit property value.
|
||||||
|
|
||||||
void setInsertId(const std::string&, const Poco::Any&);
|
void setInsertId(const std::string&, const Poco::Any&);
|
||||||
/// Try to set insert id - do nothing.
|
/// Try to set insert id - do nothing.
|
||||||
@ -106,16 +134,49 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T& getValue(MYSQL_BIND* pResult, T& val)
|
||||||
|
{
|
||||||
|
return val = *((T*) pResult->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T& getSetting(const std::string& name, T& val)
|
||||||
|
/// Returns required setting.
|
||||||
|
/// Limited to one setting at a time.
|
||||||
|
{
|
||||||
|
StatementExecutor ex(_handle);
|
||||||
|
ResultMetadata metadata;
|
||||||
|
metadata.reset();
|
||||||
|
ex.prepare(Poco::format("SELECT @@%s", name));
|
||||||
|
metadata.init(ex);
|
||||||
|
|
||||||
|
if (metadata.columnsReturned() > 0)
|
||||||
|
ex.bindResult(metadata.row());
|
||||||
|
else
|
||||||
|
throw InvalidArgumentException("No data returned.");
|
||||||
|
|
||||||
|
ex.execute(); ex.fetch();
|
||||||
|
MYSQL_BIND* pResult = metadata.row();
|
||||||
|
return getValue<T>(pResult, val);
|
||||||
|
}
|
||||||
|
|
||||||
std::string _connector;
|
std::string _connector;
|
||||||
SessionHandle _mysql;
|
SessionHandle _handle;
|
||||||
bool _connected;
|
bool _connected;
|
||||||
int _inTransaction;
|
bool _inTransaction;
|
||||||
|
Poco::FastMutex _mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// inlines
|
// inlines
|
||||||
//
|
//
|
||||||
|
inline bool SessionImpl::canTransact()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void SessionImpl::setInsertId(const std::string&, const Poco::Any&)
|
inline void SessionImpl::setInsertId(const std::string&, const Poco::Any&)
|
||||||
{
|
{
|
||||||
@ -124,13 +185,13 @@ inline void SessionImpl::setInsertId(const std::string&, const Poco::Any&)
|
|||||||
|
|
||||||
inline Poco::Any SessionImpl::getInsertId(const std::string&)
|
inline Poco::Any SessionImpl::getInsertId(const std::string&)
|
||||||
{
|
{
|
||||||
return Poco::Any(Poco::UInt64(mysql_insert_id(_mysql)));
|
return Poco::Any(Poco::UInt64(mysql_insert_id(_handle)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline SessionHandle& SessionImpl::handle()
|
inline SessionHandle& SessionImpl::handle()
|
||||||
{
|
{
|
||||||
return _mysql;
|
return _handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,6 +201,20 @@ inline const std::string& SessionImpl::connectorName()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool SessionImpl::isTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return getTransactionIsolation() == ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline std::string& SessionImpl::getValue(MYSQL_BIND* pResult, std::string& val)
|
||||||
|
{
|
||||||
|
val.assign((char*) pResult->buffer, pResult->buffer_length);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::MySQL
|
} } } // namespace Poco::Data::MySQL
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MYSQL_STMT* h;
|
MYSQL_STMT* _pHandle;
|
||||||
int _state;
|
int _state;
|
||||||
std::string _query;
|
std::string _query;
|
||||||
};
|
};
|
||||||
@ -108,7 +108,7 @@ private:
|
|||||||
|
|
||||||
inline StatementExecutor::operator MYSQL_STMT* ()
|
inline StatementExecutor::operator MYSQL_STMT* ()
|
||||||
{
|
{
|
||||||
return h;
|
return _pHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,43 +144,24 @@ void MySQLStatementImpl::compileImpl()
|
|||||||
_metadata.init(_stmt);
|
_metadata.init(_stmt);
|
||||||
|
|
||||||
if (_metadata.columnsReturned() > 0)
|
if (_metadata.columnsReturned() > 0)
|
||||||
{
|
|
||||||
_stmt.bindResult(_metadata.row());
|
_stmt.bindResult(_metadata.row());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MySQLStatementImpl::bindImpl()
|
void MySQLStatementImpl::bindImpl()
|
||||||
{
|
{
|
||||||
//
|
Poco::Data::AbstractBindingVec& binds = bindings();
|
||||||
// Bind all bindings
|
size_t pos = 0;
|
||||||
//
|
Poco::Data::AbstractBindingVec::iterator it = binds.begin();
|
||||||
|
Poco::Data::AbstractBindingVec::iterator itEnd = binds.end();
|
||||||
|
for (; it != itEnd && (*it)->canBind(); ++it)
|
||||||
{
|
{
|
||||||
Poco::Data::AbstractBindingVec& binds = bindings();
|
(*it)->bind(pos);
|
||||||
size_t pos = 0;
|
pos += (*it)->numOfColumnsHandled();
|
||||||
Poco::Data::AbstractBindingVec::iterator it = binds.begin();
|
|
||||||
Poco::Data::AbstractBindingVec::iterator itEnd = binds.end();
|
|
||||||
|
|
||||||
for (; it != itEnd && (*it)->canBind(); ++it)
|
|
||||||
{
|
|
||||||
(*it)->bind(pos);
|
|
||||||
pos += (*it)->numOfColumnsHandled();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// And bind them to statement
|
|
||||||
//
|
|
||||||
|
|
||||||
_stmt.bindParams(_binder.getBindArray(), _binder.size());
|
_stmt.bindParams(_binder.getBindArray(), _binder.size());
|
||||||
|
|
||||||
//
|
|
||||||
// And execute
|
|
||||||
//
|
|
||||||
|
|
||||||
_stmt.execute();
|
_stmt.execute();
|
||||||
|
|
||||||
_hasNext = NEXT_DONTKNOW;
|
_hasNext = NEXT_DONTKNOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,12 +44,8 @@ namespace MySQL {
|
|||||||
|
|
||||||
SessionHandle::SessionHandle(MYSQL* mysql)
|
SessionHandle::SessionHandle(MYSQL* mysql)
|
||||||
{
|
{
|
||||||
h = mysql_init(mysql);
|
if (!(_pHandle = mysql_init(mysql)))
|
||||||
|
|
||||||
if (!h)
|
|
||||||
{
|
|
||||||
throw ConnectionException("mysql_init error");
|
throw ConnectionException("mysql_init error");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -61,74 +57,54 @@ SessionHandle::~SessionHandle()
|
|||||||
|
|
||||||
void SessionHandle::options(mysql_option opt)
|
void SessionHandle::options(mysql_option opt)
|
||||||
{
|
{
|
||||||
int res = mysql_options(h, opt, 0);
|
if (mysql_options(_pHandle, opt, 0) != 0)
|
||||||
|
throw ConnectionException("mysql_options error", _pHandle);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw ConnectionException("mysql_options error", h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionHandle::options(mysql_option opt, bool b)
|
void SessionHandle::options(mysql_option opt, bool b)
|
||||||
{
|
{
|
||||||
my_bool tmp = b;
|
my_bool tmp = b;
|
||||||
int res = mysql_options(h, opt, &tmp);
|
if (mysql_options(_pHandle, opt, &tmp) != 0)
|
||||||
|
throw ConnectionException("mysql_options error", _pHandle);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw ConnectionException("mysql_options error", h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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(h, 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 ConnectionException("create session: mysql_real_connect error", h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionHandle::close()
|
void SessionHandle::close()
|
||||||
{
|
{
|
||||||
if (h)
|
if (_pHandle)
|
||||||
{
|
{
|
||||||
mysql_close(h);
|
mysql_close(_pHandle);
|
||||||
h = 0;
|
_pHandle = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionHandle::startTransaction()
|
void SessionHandle::startTransaction()
|
||||||
{
|
{
|
||||||
int res = mysql_autocommit(h, false);
|
if (mysql_autocommit(_pHandle, false) != 0)
|
||||||
|
throw TransactionException("Start transaction failed.", _pHandle);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw TransactionException("Start transaction failed.", h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionHandle::commit()
|
void SessionHandle::commit()
|
||||||
{
|
{
|
||||||
int res = mysql_commit(h);
|
if (mysql_commit(_pHandle) != 0)
|
||||||
|
throw TransactionException("Commit failed.", _pHandle);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw TransactionException("Commit failed.", h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionHandle::rollback()
|
void SessionHandle::rollback()
|
||||||
{
|
{
|
||||||
int res = mysql_rollback(h);
|
if (mysql_rollback(_pHandle) != 0)
|
||||||
|
throw TransactionException("Rollback failed.", _pHandle);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw TransactionException("Rollback failed.", h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
#include "Poco/Data/MySQL/SessionImpl.h"
|
#include "Poco/Data/MySQL/SessionImpl.h"
|
||||||
#include "Poco/Data/MySQL/MySQLStatementImpl.h"
|
#include "Poco/Data/MySQL/MySQLStatementImpl.h"
|
||||||
|
#include "Poco/Data/MySQL/StatementExecutor.h"
|
||||||
|
#include "Poco/Data/Session.h"
|
||||||
#include "Poco/NumberParser.h"
|
#include "Poco/NumberParser.h"
|
||||||
#include "Poco/String.h"
|
#include "Poco/String.h"
|
||||||
|
|
||||||
@ -59,11 +61,17 @@ namespace Data {
|
|||||||
namespace MySQL {
|
namespace MySQL {
|
||||||
|
|
||||||
|
|
||||||
|
const std::string SessionImpl::MYSQL_READ_UNCOMMITTED = "READ UNCOMMITTED";
|
||||||
|
const std::string SessionImpl::MYSQL_READ_COMMITTED = "READ COMMITTED";
|
||||||
|
const std::string SessionImpl::MYSQL_REPEATABLE_READ = "REPEATABLE READ";
|
||||||
|
const std::string SessionImpl::MYSQL_SERIALIZABLE = "SERIALIZABLE";
|
||||||
|
|
||||||
|
|
||||||
SessionImpl::SessionImpl(const std::string& connectionString) :
|
SessionImpl::SessionImpl(const std::string& connectionString) :
|
||||||
Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString)),
|
Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString)),
|
||||||
_mysql(0),
|
_handle(0),
|
||||||
_connected(false),
|
_connected(false),
|
||||||
_inTransaction(0)
|
_inTransaction(false)
|
||||||
{
|
{
|
||||||
addProperty("insertId",
|
addProperty("insertId",
|
||||||
&SessionImpl::setInsertId,
|
&SessionImpl::setInsertId,
|
||||||
@ -80,97 +88,57 @@ SessionImpl::SessionImpl(const std::string& connectionString) :
|
|||||||
options["compress"] = "";
|
options["compress"] = "";
|
||||||
options["auto-reconnect"] = "";
|
options["auto-reconnect"] = "";
|
||||||
|
|
||||||
//
|
|
||||||
// Parse string
|
|
||||||
//
|
|
||||||
|
|
||||||
for (std::string::const_iterator start = connectionString.begin();;)
|
for (std::string::const_iterator start = connectionString.begin();;)
|
||||||
{
|
{
|
||||||
// find next ';'
|
|
||||||
std::string::const_iterator finish = std::find(start, connectionString.end(), ';');
|
std::string::const_iterator finish = std::find(start, connectionString.end(), ';');
|
||||||
|
|
||||||
// find '='
|
|
||||||
std::string::const_iterator middle = std::find(start, finish, '=');
|
std::string::const_iterator middle = std::find(start, finish, '=');
|
||||||
|
|
||||||
if (middle == finish)
|
if (middle == finish)
|
||||||
{
|
|
||||||
throw MySQLException("create session: bad connection string format, can not find '='");
|
throw MySQLException("create session: bad connection string format, can not find '='");
|
||||||
}
|
|
||||||
|
|
||||||
// Parse name and value, skip all spaces
|
|
||||||
options[copyStripped(start, middle)] = copyStripped(middle + 1, finish);
|
options[copyStripped(start, middle)] = copyStripped(middle + 1, finish);
|
||||||
|
|
||||||
if ((finish == connectionString.end()) || (finish + 1 == connectionString.end()))
|
if ((finish == connectionString.end()) || (finish + 1 == connectionString.end())) break;
|
||||||
{
|
|
||||||
// end of parse
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move start position after ';'
|
|
||||||
start = finish + 1;
|
start = finish + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Checking
|
|
||||||
//
|
|
||||||
|
|
||||||
if (options["user"] == "")
|
if (options["user"] == "")
|
||||||
{
|
|
||||||
throw MySQLException("create session: specify user name");
|
throw MySQLException("create session: specify user name");
|
||||||
}
|
|
||||||
|
|
||||||
if (options["db"] == "")
|
if (options["db"] == "")
|
||||||
{
|
|
||||||
throw MySQLException("create session: specify database");
|
throw MySQLException("create session: specify database");
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int port = 0;
|
unsigned int port = 0;
|
||||||
if (!NumberParser::tryParseUnsigned(options["port"], port) || 0 == port || port > 65535)
|
if (!NumberParser::tryParseUnsigned(options["port"], port) || 0 == port || port > 65535)
|
||||||
{
|
|
||||||
throw MySQLException("create session: specify correct port (numeric in decimal notation)");
|
throw MySQLException("create session: specify correct port (numeric in decimal notation)");
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Options
|
|
||||||
//
|
|
||||||
|
|
||||||
if (options["compress"] == "true")
|
if (options["compress"] == "true")
|
||||||
{
|
_handle.options(MYSQL_OPT_COMPRESS);
|
||||||
_mysql.options(MYSQL_OPT_COMPRESS);
|
|
||||||
}
|
|
||||||
else if (options["compress"] == "false")
|
else if (options["compress"] == "false")
|
||||||
{
|
;
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
else if (options["compress"] != "")
|
else if (options["compress"] != "")
|
||||||
{
|
|
||||||
throw MySQLException("create session: specify correct compress option (true or false) or skip it");
|
throw MySQLException("create session: specify correct compress option (true or false) or skip it");
|
||||||
}
|
|
||||||
|
|
||||||
if (options["auto-reconnect"] == "true")
|
if (options["auto-reconnect"] == "true")
|
||||||
{
|
_handle.options(MYSQL_OPT_RECONNECT, true);
|
||||||
_mysql.options(MYSQL_OPT_RECONNECT, true);
|
|
||||||
}
|
|
||||||
else if (options["auto-reconnect"] == "false")
|
else if (options["auto-reconnect"] == "false")
|
||||||
{
|
_handle.options(MYSQL_OPT_RECONNECT, false);
|
||||||
_mysql.options(MYSQL_OPT_RECONNECT, false);
|
|
||||||
}
|
|
||||||
else if (options["auto-reconnect"] != "")
|
else if (options["auto-reconnect"] != "")
|
||||||
{
|
|
||||||
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(
|
||||||
|
|
||||||
_mysql.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(),
|
||||||
port);
|
port);
|
||||||
|
|
||||||
|
addFeature("autoCommit",
|
||||||
|
&SessionImpl::autoCommit,
|
||||||
|
&SessionImpl::isAutoCommit);
|
||||||
|
|
||||||
_connected = true;
|
_connected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,22 +157,92 @@ Poco::Data::StatementImpl* SessionImpl::createStatementImpl()
|
|||||||
|
|
||||||
void SessionImpl::begin()
|
void SessionImpl::begin()
|
||||||
{
|
{
|
||||||
_mysql.startTransaction();
|
Poco::FastMutex::ScopedLock l(_mutex);
|
||||||
_inTransaction++;
|
|
||||||
|
if (_inTransaction)
|
||||||
|
throw Poco::InvalidAccessException("Already in transaction.");
|
||||||
|
|
||||||
|
_handle.startTransaction();
|
||||||
|
_inTransaction = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionImpl::commit()
|
void SessionImpl::commit()
|
||||||
{
|
{
|
||||||
_mysql.commit();
|
_handle.commit();
|
||||||
_inTransaction--;
|
_inTransaction = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionImpl::rollback()
|
void SessionImpl::rollback()
|
||||||
{
|
{
|
||||||
_mysql.rollback();
|
_handle.rollback();
|
||||||
_inTransaction--;
|
_inTransaction = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::autoCommit(const std::string&, bool val)
|
||||||
|
{
|
||||||
|
StatementExecutor ex(_handle);
|
||||||
|
ex.prepare(Poco::format("SET autocommit=%d", val ? 1 : 0));
|
||||||
|
ex.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::isAutoCommit(const std::string&)
|
||||||
|
{
|
||||||
|
int ac = 0;
|
||||||
|
return 1 == getSetting("autocommit", ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::setTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
std::string isolation;
|
||||||
|
switch (ti)
|
||||||
|
{
|
||||||
|
case Session::TRANSACTION_READ_UNCOMMITTED:
|
||||||
|
isolation = MYSQL_READ_UNCOMMITTED; break;
|
||||||
|
case Session::TRANSACTION_READ_COMMITTED:
|
||||||
|
isolation = MYSQL_READ_COMMITTED; break;
|
||||||
|
case Session::TRANSACTION_REPEATABLE_READ:
|
||||||
|
isolation = MYSQL_REPEATABLE_READ; break;
|
||||||
|
case Session::TRANSACTION_SERIALIZABLE:
|
||||||
|
isolation = MYSQL_SERIALIZABLE; break;
|
||||||
|
default:
|
||||||
|
throw Poco::InvalidArgumentException("setTransactionIsolation()");
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementExecutor ex(_handle);
|
||||||
|
ex.prepare(Poco::format("SET SESSION TRANSACTION ISOLATION LEVEL %s", isolation));
|
||||||
|
ex.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 SessionImpl::getTransactionIsolation()
|
||||||
|
{
|
||||||
|
std::string isolation;
|
||||||
|
getSetting("tx_isolation", isolation);
|
||||||
|
Poco::replaceInPlace(isolation, "-", " ");
|
||||||
|
if (MYSQL_READ_UNCOMMITTED == isolation)
|
||||||
|
return Session::TRANSACTION_READ_UNCOMMITTED;
|
||||||
|
else if (MYSQL_READ_COMMITTED == isolation)
|
||||||
|
return Session::TRANSACTION_READ_COMMITTED;
|
||||||
|
else if (MYSQL_REPEATABLE_READ == isolation)
|
||||||
|
return Session::TRANSACTION_REPEATABLE_READ;
|
||||||
|
else if (MYSQL_SERIALIZABLE == isolation)
|
||||||
|
return Session::TRANSACTION_SERIALIZABLE;
|
||||||
|
|
||||||
|
throw InvalidArgumentException("getTransactionIsolation()");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::hasTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return Session::TRANSACTION_READ_UNCOMMITTED == ti ||
|
||||||
|
Session::TRANSACTION_READ_COMMITTED == ti ||
|
||||||
|
Session::TRANSACTION_REPEATABLE_READ == ti ||
|
||||||
|
Session::TRANSACTION_SERIALIZABLE == ti;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -212,7 +250,7 @@ void SessionImpl::close()
|
|||||||
{
|
{
|
||||||
if (_connected)
|
if (_connected)
|
||||||
{
|
{
|
||||||
_mysql.close();
|
_handle.close();
|
||||||
_connected = false;
|
_connected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,7 +264,7 @@ bool SessionImpl::isConnected()
|
|||||||
|
|
||||||
bool SessionImpl::isTransaction()
|
bool SessionImpl::isTransaction()
|
||||||
{
|
{
|
||||||
return (_inTransaction > 0);
|
return _inTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,12 +46,8 @@ namespace MySQL {
|
|||||||
|
|
||||||
StatementExecutor::StatementExecutor(MYSQL* mysql)
|
StatementExecutor::StatementExecutor(MYSQL* mysql)
|
||||||
{
|
{
|
||||||
h = mysql_stmt_init(mysql);
|
if (!(_pHandle = mysql_stmt_init(mysql)))
|
||||||
|
|
||||||
if (!h)
|
|
||||||
{
|
|
||||||
throw StatementException("mysql_stmt_init error");
|
throw StatementException("mysql_stmt_init error");
|
||||||
}
|
|
||||||
|
|
||||||
_state = STMT_INITED;
|
_state = STMT_INITED;
|
||||||
}
|
}
|
||||||
@ -59,7 +55,7 @@ StatementExecutor::StatementExecutor(MYSQL* mysql)
|
|||||||
|
|
||||||
StatementExecutor::~StatementExecutor()
|
StatementExecutor::~StatementExecutor()
|
||||||
{
|
{
|
||||||
mysql_stmt_close(h);
|
mysql_stmt_close(_pHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -75,16 +71,10 @@ void StatementExecutor::prepare(const std::string& query)
|
|||||||
{
|
{
|
||||||
_state = STMT_COMPILED;
|
_state = STMT_COMPILED;
|
||||||
return;
|
return;
|
||||||
//throw StatementException("Satement is already compiled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile
|
if (mysql_stmt_prepare(_pHandle, query.c_str(), static_cast<unsigned int>(query.length())) != 0)
|
||||||
int res = mysql_stmt_prepare(h, query.c_str(), static_cast<unsigned int>(query.length()));
|
throw StatementException("mysql_stmt_prepare error", _pHandle, query);
|
||||||
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw StatementException("mysql_stmt_prepare error", h, query);
|
|
||||||
}
|
|
||||||
|
|
||||||
_query = query;
|
_query = query;
|
||||||
_state = STMT_COMPILED;
|
_state = STMT_COMPILED;
|
||||||
@ -94,58 +84,35 @@ void StatementExecutor::prepare(const std::string& query)
|
|||||||
void StatementExecutor::bindParams(MYSQL_BIND* params, size_t count)
|
void StatementExecutor::bindParams(MYSQL_BIND* params, size_t count)
|
||||||
{
|
{
|
||||||
if (_state < STMT_COMPILED)
|
if (_state < STMT_COMPILED)
|
||||||
{
|
|
||||||
throw StatementException("Satement is not compiled yet");
|
throw StatementException("Satement is not compiled yet");
|
||||||
}
|
|
||||||
|
|
||||||
if (count != mysql_stmt_param_count(h))
|
if (count != mysql_stmt_param_count(_pHandle))
|
||||||
{
|
|
||||||
throw StatementException("wrong bind parameters count", 0, _query);
|
throw StatementException("wrong bind parameters count", 0, _query);
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = mysql_stmt_bind_param(h, params);
|
if (mysql_stmt_bind_param(_pHandle, params) != 0)
|
||||||
|
throw StatementException("mysql_stmt_bind_param() error ", _pHandle, _query);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw StatementException("mysql_stmt_bind_param() error ", h, _query);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StatementExecutor::bindResult(MYSQL_BIND* result)
|
void StatementExecutor::bindResult(MYSQL_BIND* result)
|
||||||
{
|
{
|
||||||
if (_state < STMT_COMPILED)
|
if (_state < STMT_COMPILED)
|
||||||
{
|
|
||||||
throw StatementException("Satement is not compiled yet");
|
throw StatementException("Satement is not compiled yet");
|
||||||
}
|
|
||||||
|
|
||||||
int res = mysql_stmt_bind_result(h, result);
|
if (mysql_stmt_bind_result(_pHandle, result) != 0)
|
||||||
|
throw StatementException("mysql_stmt_bind_result error ", _pHandle, _query);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw StatementException("mysql_stmt_bind_result error ", h, _query);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StatementExecutor::execute()
|
void StatementExecutor::execute()
|
||||||
{
|
{
|
||||||
if (_state < STMT_COMPILED)
|
if (_state < STMT_COMPILED)
|
||||||
{
|
|
||||||
throw StatementException("Satement is not compiled yet");
|
throw StatementException("Satement is not compiled yet");
|
||||||
}
|
|
||||||
|
|
||||||
int res = mysql_stmt_execute(h);
|
if (mysql_stmt_execute(_pHandle) != 0)
|
||||||
|
throw StatementException("mysql_stmt_execute error", _pHandle, _query);
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
throw StatementException("mysql_stmt_execute error", h, _query);
|
|
||||||
}
|
|
||||||
|
|
||||||
_state = STMT_EXECUTED;
|
_state = STMT_EXECUTED;
|
||||||
}
|
}
|
||||||
@ -154,16 +121,12 @@ void StatementExecutor::execute()
|
|||||||
bool StatementExecutor::fetch()
|
bool StatementExecutor::fetch()
|
||||||
{
|
{
|
||||||
if (_state < STMT_EXECUTED)
|
if (_state < STMT_EXECUTED)
|
||||||
{
|
|
||||||
throw StatementException("Satement is not executed yet");
|
throw StatementException("Satement is not executed yet");
|
||||||
}
|
|
||||||
|
|
||||||
int res = mysql_stmt_fetch(h);
|
int res = mysql_stmt_fetch(_pHandle);
|
||||||
|
|
||||||
if ((res != 0) && (res != MYSQL_NO_DATA))
|
if ((res != 0) && (res != MYSQL_NO_DATA))
|
||||||
{
|
throw StatementException("mysql_stmt_fetch error", _pHandle, _query);
|
||||||
throw StatementException("mysql_stmt_fetch error", h, _query);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (res == 0);
|
return (res == 0);
|
||||||
}
|
}
|
||||||
@ -172,17 +135,15 @@ bool StatementExecutor::fetch()
|
|||||||
bool StatementExecutor::fetchColumn(size_t n, MYSQL_BIND *bind)
|
bool StatementExecutor::fetchColumn(size_t n, MYSQL_BIND *bind)
|
||||||
{
|
{
|
||||||
if (_state < STMT_EXECUTED)
|
if (_state < STMT_EXECUTED)
|
||||||
{
|
|
||||||
throw StatementException("Satement is not executed yet");
|
throw StatementException("Satement is not executed yet");
|
||||||
}
|
|
||||||
|
|
||||||
int res = mysql_stmt_fetch_column(h, bind, static_cast<unsigned int>(n), 0);
|
int res = mysql_stmt_fetch_column(_pHandle, bind, static_cast<unsigned int>(n), 0);
|
||||||
|
|
||||||
if ((res != 0) && (res != MYSQL_NO_DATA))
|
if ((res != 0) && (res != MYSQL_NO_DATA))
|
||||||
{
|
{
|
||||||
std::ostringstream msg;
|
std::ostringstream msg;
|
||||||
msg << "mysql_stmt_fetch_column(" << n << ") error";
|
msg << "mysql_stmt_fetch_column(" << n << ") error";
|
||||||
throw StatementException(msg.str(), h, _query);
|
throw StatementException(msg.str(), _pHandle, _query);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (res == 0);
|
return (res == 0);
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories="..\include;..\..\..\Foundation\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Data\include"
|
AdditionalIncludeDirectories="..\include;..\..\..\Foundation\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Data\include;..\..\MySQL\include\Poco\Data\MySQL\mysql"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;POCO_DLL;WINVER=0x0500"
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;POCO_DLL;WINVER=0x0500"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
|
@ -79,27 +79,6 @@ MySQLTest::MySQLTest(const std::string& name):
|
|||||||
CppUnit::TestCase(name)
|
CppUnit::TestCase(name)
|
||||||
{
|
{
|
||||||
MySQL::Connector::registerConnector();
|
MySQL::Connector::registerConnector();
|
||||||
|
|
||||||
/*static bool beenHere = false;
|
|
||||||
|
|
||||||
|
|
||||||
if (!beenHere)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_pSession = new Session(SessionFactory::instance().create(MySQL::Connector::KEY, _dbConnString));
|
|
||||||
}catch (ConnectionException& ex)
|
|
||||||
{
|
|
||||||
std::cout << "!!! WARNING: Connection failed. MySQL tests will fail !!!" << std::endl;
|
|
||||||
std::cout << ex.toString() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_pSession && _pSession->isConnected())
|
|
||||||
std::cout << "*** Connected to " << '(' << _dbConnString << ')' << std::endl;
|
|
||||||
if (!_pExecutor) _pExecutor = new SQLExecutor("MySQL SQL Executor", _pSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
beenHere = true;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -510,6 +489,24 @@ void MySQLTest::testNull()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MySQLTest::testSessionTransaction()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
recreatePersonBLOBTable();
|
||||||
|
_pExecutor->sessionTransaction(_dbConnString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MySQLTest::testTransaction()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
recreatePersonBLOBTable();
|
||||||
|
_pExecutor->transaction(_dbConnString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MySQLTest::testNullableInt()
|
void MySQLTest::testNullableInt()
|
||||||
{
|
{
|
||||||
if (!_pSession) fail ("Test not available.");
|
if (!_pSession) fail ("Test not available.");
|
||||||
@ -814,6 +811,8 @@ CppUnit::Test* MySQLTest::suite()
|
|||||||
CppUnit_addTest(pSuite, MySQLTest, testNullableInt);
|
CppUnit_addTest(pSuite, MySQLTest, testNullableInt);
|
||||||
CppUnit_addTest(pSuite, MySQLTest, testNullableString);
|
CppUnit_addTest(pSuite, MySQLTest, testNullableString);
|
||||||
CppUnit_addTest(pSuite, MySQLTest, testTupleWithNullable);
|
CppUnit_addTest(pSuite, MySQLTest, testTupleWithNullable);
|
||||||
|
CppUnit_addTest(pSuite, MySQLTest, testSessionTransaction);
|
||||||
|
CppUnit_addTest(pSuite, MySQLTest, testTransaction);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,9 @@ public:
|
|||||||
void testNullableString();
|
void testNullableString();
|
||||||
void testTupleWithNullable();
|
void testTupleWithNullable();
|
||||||
|
|
||||||
|
void testSessionTransaction();
|
||||||
|
void testTransaction();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "Poco/Data/LOB.h"
|
#include "Poco/Data/LOB.h"
|
||||||
#include "Poco/Data/StatementImpl.h"
|
#include "Poco/Data/StatementImpl.h"
|
||||||
#include "Poco/Data/RecordSet.h"
|
#include "Poco/Data/RecordSet.h"
|
||||||
|
#include "Poco/Data/Transaction.h"
|
||||||
#include "Poco/Data/MySQL/Connector.h"
|
#include "Poco/Data/MySQL/Connector.h"
|
||||||
#include "Poco/Data/MySQL/MySQLException.h"
|
#include "Poco/Data/MySQL/MySQLException.h"
|
||||||
|
|
||||||
@ -1518,3 +1519,287 @@ void SQLExecutor::doNull()
|
|||||||
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
poco_assert (str0 == "DEFAULT");
|
poco_assert (str0 == "DEFAULT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::setTransactionIsolation(Session& session, Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
if (session.hasTransactionIsolation(ti))
|
||||||
|
{
|
||||||
|
std::string funct = "setTransactionIsolation()";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Transaction t(session, false);
|
||||||
|
t.setIsolation(ti);
|
||||||
|
|
||||||
|
assert (ti == t.getIsolation());
|
||||||
|
assert (t.isIsolation(ti));
|
||||||
|
|
||||||
|
assert (ti == session.getTransactionIsolation());
|
||||||
|
assert (session.isTransactionIsolation(ti));
|
||||||
|
}
|
||||||
|
catch(Poco::Exception& e){ std::cout << funct << ':' << e.displayText() << std::endl;}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Transaction isolation not supported: ";
|
||||||
|
switch (ti)
|
||||||
|
{
|
||||||
|
case Session::TRANSACTION_READ_COMMITTED:
|
||||||
|
std::cout << "READ COMMITTED"; break;
|
||||||
|
case Session::TRANSACTION_READ_UNCOMMITTED:
|
||||||
|
std::cout << "READ UNCOMMITTED"; break;
|
||||||
|
case Session::TRANSACTION_REPEATABLE_READ:
|
||||||
|
std::cout << "REPEATABLE READ"; break;
|
||||||
|
case Session::TRANSACTION_SERIALIZABLE:
|
||||||
|
std::cout << "SERIALIZABLE"; break;
|
||||||
|
default:
|
||||||
|
std::cout << "UNKNOWN"; break;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::sessionTransaction(const std::string& connect)
|
||||||
|
{
|
||||||
|
if (!_pSession->canTransact())
|
||||||
|
{
|
||||||
|
std::cout << "Session not capable of transactions." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session local("mysql", connect);
|
||||||
|
local.setFeature("autoCommit", true);
|
||||||
|
|
||||||
|
std::string funct = "transaction()";
|
||||||
|
std::vector<std::string> lastNames;
|
||||||
|
std::vector<std::string> firstNames;
|
||||||
|
std::vector<std::string> addresses;
|
||||||
|
std::vector<int> ages;
|
||||||
|
std::string tableName("Person");
|
||||||
|
lastNames.push_back("LN1");
|
||||||
|
lastNames.push_back("LN2");
|
||||||
|
firstNames.push_back("FN1");
|
||||||
|
firstNames.push_back("FN2");
|
||||||
|
addresses.push_back("ADDR1");
|
||||||
|
addresses.push_back("ADDR2");
|
||||||
|
ages.push_back(1);
|
||||||
|
ages.push_back(2);
|
||||||
|
int count = 0, locCount = 0;
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
bool autoCommit = _pSession->getFeature("autoCommit");
|
||||||
|
|
||||||
|
_pSession->setFeature("autoCommit", true);
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
_pSession->setFeature("autoCommit", false);
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
|
||||||
|
setTransactionIsolation((*_pSession), Session::TRANSACTION_READ_UNCOMMITTED);
|
||||||
|
setTransactionIsolation((*_pSession), Session::TRANSACTION_REPEATABLE_READ);
|
||||||
|
setTransactionIsolation((*_pSession), Session::TRANSACTION_SERIALIZABLE);
|
||||||
|
|
||||||
|
setTransactionIsolation((*_pSession), Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
|
||||||
|
_pSession->begin();
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
try { (*_pSession) << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
_pSession->rollback();
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
|
||||||
|
_pSession->begin();
|
||||||
|
try { (*_pSession) << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
_pSession->commit();
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (2 == locCount);
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
_pSession->setFeature("autoCommit", autoCommit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::transaction(const std::string& connect)
|
||||||
|
{
|
||||||
|
if (!_pSession->canTransact())
|
||||||
|
{
|
||||||
|
std::cout << "Session not transaction-capable." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session local("mysql", connect);
|
||||||
|
local.setFeature("autoCommit", true);
|
||||||
|
|
||||||
|
setTransactionIsolation((*_pSession), Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
setTransactionIsolation(local, Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
|
||||||
|
std::string funct = "transaction()";
|
||||||
|
std::vector<std::string> lastNames;
|
||||||
|
std::vector<std::string> firstNames;
|
||||||
|
std::vector<std::string> addresses;
|
||||||
|
std::vector<int> ages;
|
||||||
|
std::string tableName("Person");
|
||||||
|
lastNames.push_back("LN1");
|
||||||
|
lastNames.push_back("LN2");
|
||||||
|
firstNames.push_back("FN1");
|
||||||
|
firstNames.push_back("FN2");
|
||||||
|
addresses.push_back("ADDR1");
|
||||||
|
addresses.push_back("ADDR2");
|
||||||
|
ages.push_back(1);
|
||||||
|
ages.push_back(2);
|
||||||
|
int count = 0, locCount = 0;
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
bool autoCommit = _pSession->getFeature("autoCommit");
|
||||||
|
|
||||||
|
_pSession->setFeature("autoCommit", true);
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
_pSession->setFeature("autoCommit", false);
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
_pSession->setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
|
||||||
|
{
|
||||||
|
Transaction trans((*_pSession));
|
||||||
|
assert (trans.isActive());
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
|
||||||
|
try { (*_pSession) << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
assert (trans.isActive());
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
assert (trans.isActive());
|
||||||
|
}
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
|
||||||
|
{
|
||||||
|
Transaction trans((*_pSession));
|
||||||
|
try { (*_pSession) << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
assert (_pSession->isTransaction());
|
||||||
|
assert (trans.isActive());
|
||||||
|
trans.commit();
|
||||||
|
assert (!_pSession->isTransaction());
|
||||||
|
assert (!trans.isActive());
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (2 == locCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
_pSession->begin();
|
||||||
|
try { (*_pSession) << "DELETE FROM PERSON", now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (2 == locCount);
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
_pSession->commit();
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
std::string sql1 = format("INSERT INTO PERSON VALUES ('%s','%s','%s',%d)", lastNames[0], firstNames[0], addresses[0], ages[0]);
|
||||||
|
std::string sql2 = format("INSERT INTO PERSON VALUES ('%s','%s','%s',%d)", lastNames[1], firstNames[1], addresses[1], ages[1]);
|
||||||
|
std::vector<std::string> sql;
|
||||||
|
sql.push_back(sql1);
|
||||||
|
sql.push_back(sql2);
|
||||||
|
|
||||||
|
Transaction trans((*_pSession));
|
||||||
|
|
||||||
|
trans.execute(sql1, false);
|
||||||
|
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 (1 == count);
|
||||||
|
trans.execute(sql2, false);
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
trans.rollback();
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
|
||||||
|
trans.execute(sql);
|
||||||
|
|
||||||
|
local << "SELECT COUNT(*) FROM PERSON", into(locCount), now;
|
||||||
|
assert (2 == locCount);
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
_pSession->setFeature("autoCommit", autoCommit);
|
||||||
|
}
|
||||||
|
@ -110,7 +110,12 @@ public:
|
|||||||
void internalExtraction();
|
void internalExtraction();
|
||||||
void doNull();
|
void doNull();
|
||||||
|
|
||||||
|
void sessionTransaction(const std::string& connect);
|
||||||
|
void transaction(const std::string& connect);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti);
|
||||||
|
|
||||||
Poco::Data::Session* _pSession;
|
Poco::Data::Session* _pSession;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "Poco/Data/ODBC/ODBCException.h"
|
#include "Poco/Data/ODBC/ODBCException.h"
|
||||||
#include "Poco/Data/AbstractSessionImpl.h"
|
#include "Poco/Data/AbstractSessionImpl.h"
|
||||||
#include "Poco/SharedPtr.h"
|
#include "Poco/SharedPtr.h"
|
||||||
|
#include "Poco/Mutex.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
@ -63,6 +64,13 @@ class ODBC_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl>
|
|||||||
/// Implements SessionImpl interface
|
/// Implements SessionImpl interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum TransactionCapability
|
||||||
|
{
|
||||||
|
ODBC_TXN_CAPABILITY_UNKNOWN = -1,
|
||||||
|
ODBC_TXN_CAPABILITY_FALSE = 0,
|
||||||
|
ODBC_TXN_CAPABILITY_TRUE = 1
|
||||||
|
};
|
||||||
|
|
||||||
SessionImpl(const std::string& connect,
|
SessionImpl(const std::string& connect,
|
||||||
Poco::Any maxFieldSize = std::size_t(1024),
|
Poco::Any maxFieldSize = std::size_t(1024),
|
||||||
bool enforceCapability=false,
|
bool enforceCapability=false,
|
||||||
@ -100,6 +108,20 @@ public:
|
|||||||
bool canTransact();
|
bool canTransact();
|
||||||
/// Returns true if connection is transaction-capable.
|
/// Returns true if connection is transaction-capable.
|
||||||
|
|
||||||
|
void setTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Sets the transaction isolation level.
|
||||||
|
|
||||||
|
Poco::UInt32 getTransactionIsolation();
|
||||||
|
/// Returns the transaction isolation level.
|
||||||
|
|
||||||
|
bool hasTransactionIsolation(Poco::UInt32);
|
||||||
|
/// Returns true iff the transaction isolation level corresponding
|
||||||
|
/// to the supplied bitmask is supported.
|
||||||
|
|
||||||
|
bool isTransactionIsolation(Poco::UInt32);
|
||||||
|
/// Returns true iff the transaction isolation level corresponds
|
||||||
|
/// to the supplied bitmask.
|
||||||
|
|
||||||
void autoCommit(const std::string&, bool val);
|
void autoCommit(const std::string&, bool val);
|
||||||
/// Sets autocommit property for the session.
|
/// Sets autocommit property for the session.
|
||||||
|
|
||||||
@ -144,12 +166,19 @@ private:
|
|||||||
|
|
||||||
void checkError(SQLRETURN rc, const std::string& msg="");
|
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;
|
const ConnectionHandle _db;
|
||||||
Poco::Any _maxFieldSize;
|
Poco::Any _maxFieldSize;
|
||||||
bool _autoBind;
|
bool _autoBind;
|
||||||
bool _autoExtract;
|
bool _autoExtract;
|
||||||
TypeInfo _dataTypes;
|
TypeInfo _dataTypes;
|
||||||
|
char _canTransact;
|
||||||
|
bool _inTransaction;
|
||||||
|
Poco::FastMutex _mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -169,20 +198,6 @@ inline const ConnectionHandle& SessionImpl::dbc() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void SessionImpl::commit()
|
|
||||||
{
|
|
||||||
if (!isAutoCommit())
|
|
||||||
checkError(SQLEndTran(SQL_HANDLE_DBC, _db, SQL_COMMIT));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void SessionImpl::rollback()
|
|
||||||
{
|
|
||||||
if (!isAutoCommit())
|
|
||||||
checkError(SQLEndTran(SQL_HANDLE_DBC, _db, SQL_ROLLBACK));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void SessionImpl::setMaxFieldSize(const std::string& rName, const Poco::Any& rValue)
|
inline void SessionImpl::setMaxFieldSize(const std::string& rName, const Poco::Any& rValue)
|
||||||
{
|
{
|
||||||
_maxFieldSize = rValue;
|
_maxFieldSize = rValue;
|
||||||
@ -237,6 +252,12 @@ inline const std::string& SessionImpl::connectorName()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool SessionImpl::isTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return 0 != (ti & getTransactionIsolation());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
} } } // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
|
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
|
||||||
#include "Poco/Data/ODBC/Error.h"
|
#include "Poco/Data/ODBC/Error.h"
|
||||||
#include "Poco/Data/ODBC/ODBCException.h"
|
#include "Poco/Data/ODBC/ODBCException.h"
|
||||||
|
#include "Poco/Data/Session.h"
|
||||||
#include "Poco/String.h"
|
#include "Poco/String.h"
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
@ -56,7 +57,9 @@ SessionImpl::SessionImpl(const std::string& connect,
|
|||||||
_connector(toLower(Connector::KEY)),
|
_connector(toLower(Connector::KEY)),
|
||||||
_maxFieldSize(maxFieldSize),
|
_maxFieldSize(maxFieldSize),
|
||||||
_autoBind(autoBind),
|
_autoBind(autoBind),
|
||||||
_autoExtract(autoExtract)
|
_autoExtract(autoExtract),
|
||||||
|
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||||
|
_inTransaction(false)
|
||||||
{
|
{
|
||||||
setFeature("bulk", true);
|
setFeature("bulk", true);
|
||||||
open();
|
open();
|
||||||
@ -65,7 +68,14 @@ SessionImpl::SessionImpl(const std::string& connect,
|
|||||||
|
|
||||||
SessionImpl::~SessionImpl()
|
SessionImpl::~SessionImpl()
|
||||||
{
|
{
|
||||||
close();
|
if (isTransaction() && !getFeature("autoCommit"))
|
||||||
|
{
|
||||||
|
try { rollback(); }
|
||||||
|
catch (...) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
try { close(); }
|
||||||
|
catch (...) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -75,11 +85,6 @@ Poco::Data::StatementImpl* SessionImpl::createStatementImpl()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionImpl::begin()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SessionImpl::open()
|
void SessionImpl::open()
|
||||||
{
|
{
|
||||||
SQLCHAR connectOutput[512] = {0};
|
SQLCHAR connectOutput[512] = {0};
|
||||||
@ -128,11 +133,101 @@ void SessionImpl::open()
|
|||||||
|
|
||||||
bool SessionImpl::canTransact()
|
bool SessionImpl::canTransact()
|
||||||
{
|
{
|
||||||
SQLUSMALLINT ret;
|
if (ODBC_TXN_CAPABILITY_UNKNOWN == _canTransact)
|
||||||
checkError(Poco::Data::ODBC::SQLGetInfo(_db, SQL_TXN_CAPABLE, &ret, 0, 0),
|
{
|
||||||
"Failed to obtain transaction capability info.");
|
SQLUSMALLINT ret;
|
||||||
|
checkError(Poco::Data::ODBC::SQLGetInfo(_db, SQL_TXN_CAPABLE, &ret, 0, 0),
|
||||||
|
"Failed to obtain transaction capability info.");
|
||||||
|
|
||||||
return (SQL_TC_NONE != ret);
|
_canTransact = (SQL_TC_NONE != ret) ?
|
||||||
|
ODBC_TXN_CAPABILITY_TRUE :
|
||||||
|
ODBC_TXN_CAPABILITY_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ODBC_TXN_CAPABILITY_TRUE == _canTransact;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::setTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
Poco::UInt32 isolation = 0;
|
||||||
|
|
||||||
|
if (ti & Session::TRANSACTION_READ_UNCOMMITTED)
|
||||||
|
isolation |= SQL_TXN_READ_UNCOMMITTED;
|
||||||
|
|
||||||
|
if (ti & Session::TRANSACTION_READ_COMMITTED)
|
||||||
|
isolation |= SQL_TXN_READ_COMMITTED;
|
||||||
|
|
||||||
|
if (ti & Session::TRANSACTION_REPEATABLE_READ)
|
||||||
|
isolation |= SQL_TXN_REPEATABLE_READ;
|
||||||
|
|
||||||
|
if (ti & Session::TRANSACTION_SERIALIZABLE)
|
||||||
|
isolation |= SQL_TXN_SERIALIZABLE;
|
||||||
|
|
||||||
|
checkError(SQLSetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER) isolation, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 SessionImpl::getTransactionIsolation()
|
||||||
|
{
|
||||||
|
SQLUINTEGER isolation = 0;
|
||||||
|
checkError(SQLGetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION,
|
||||||
|
&isolation,
|
||||||
|
0,
|
||||||
|
0));
|
||||||
|
|
||||||
|
return transactionIsolation(isolation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::hasTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
if (isTransaction()) throw InvalidAccessException();
|
||||||
|
|
||||||
|
bool retval = true;
|
||||||
|
Poco::UInt32 old = getTransactionIsolation();
|
||||||
|
try { setTransactionIsolation(ti); }
|
||||||
|
catch (Poco::Exception&) { retval = false; }
|
||||||
|
setTransactionIsolation(old);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 SessionImpl::getDefaultTransactionIsolation()
|
||||||
|
{
|
||||||
|
SQLUINTEGER isolation = 0;
|
||||||
|
checkError(SQLGetInfo(_db, SQL_DEFAULT_TXN_ISOLATION,
|
||||||
|
&isolation,
|
||||||
|
0,
|
||||||
|
0));
|
||||||
|
|
||||||
|
return transactionIsolation(isolation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 SessionImpl::transactionIsolation(SQLUINTEGER isolation)
|
||||||
|
{
|
||||||
|
if (0 == isolation)
|
||||||
|
throw InvalidArgumentException("transactionIsolation(SQLUINTEGER)");
|
||||||
|
|
||||||
|
Poco::UInt32 ret = 0;
|
||||||
|
|
||||||
|
if (isolation & SQL_TXN_READ_UNCOMMITTED)
|
||||||
|
ret |= Session::TRANSACTION_READ_UNCOMMITTED;
|
||||||
|
|
||||||
|
if (isolation & SQL_TXN_READ_COMMITTED)
|
||||||
|
ret |= Session::TRANSACTION_READ_COMMITTED;
|
||||||
|
|
||||||
|
if (isolation & SQL_TXN_REPEATABLE_READ)
|
||||||
|
ret |= Session::TRANSACTION_REPEATABLE_READ;
|
||||||
|
|
||||||
|
if (isolation & SQL_TXN_SERIALIZABLE)
|
||||||
|
ret |= Session::TRANSACTION_SERIALIZABLE;
|
||||||
|
|
||||||
|
if (0 == ret)
|
||||||
|
throw InvalidArgumentException("transactionIsolation(SQLUINTEGER)");
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -171,21 +266,57 @@ bool SessionImpl::isConnected()
|
|||||||
0)))
|
0)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (0 == value);
|
return (SQL_CD_FALSE == value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SessionImpl::isTransaction()
|
bool SessionImpl::isTransaction()
|
||||||
{
|
{
|
||||||
Poco::UInt32 value = 0;
|
if (!canTransact()) return false;
|
||||||
|
|
||||||
|
Poco::UInt32 value = 0;
|
||||||
checkError(Poco::Data::ODBC::SQLGetConnectAttr(_db,
|
checkError(Poco::Data::ODBC::SQLGetConnectAttr(_db,
|
||||||
SQL_ATTR_AUTOCOMMIT,
|
SQL_ATTR_AUTOCOMMIT,
|
||||||
&value,
|
&value,
|
||||||
0,
|
0,
|
||||||
0));
|
0));
|
||||||
|
|
||||||
return (0 == value);
|
if (0 == value) return _inTransaction;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::begin()
|
||||||
|
{
|
||||||
|
if (isAutoCommit())
|
||||||
|
throw InvalidAccessException("Session in auto commit mode.");
|
||||||
|
|
||||||
|
{
|
||||||
|
Poco::FastMutex::ScopedLock l(_mutex);
|
||||||
|
|
||||||
|
if (_inTransaction)
|
||||||
|
throw InvalidAccessException("Transaction in progress.");
|
||||||
|
|
||||||
|
_inTransaction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::commit()
|
||||||
|
{
|
||||||
|
if (!isAutoCommit())
|
||||||
|
checkError(SQLEndTran(SQL_HANDLE_DBC, _db, SQL_COMMIT));
|
||||||
|
|
||||||
|
_inTransaction = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::rollback()
|
||||||
|
{
|
||||||
|
if (!isAutoCommit())
|
||||||
|
checkError(SQLEndTran(SQL_HANDLE_DBC, _db, SQL_ROLLBACK));
|
||||||
|
|
||||||
|
_inTransaction = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -678,6 +678,9 @@ CppUnit::Test* ODBCDB2Test::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testMultipleResults);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testMultipleResults);
|
||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testSQLChannel);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testSQLChannel);
|
||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testSQLLogger);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testSQLLogger);
|
||||||
|
CppUnit_addTest(pSuite, ODBCDB2Test, testSessionTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCDB2Test, testTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCDB2Test, testTransactor);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -494,6 +494,9 @@ CppUnit::Test* ODBCMySQLTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testMultipleResults);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testMultipleResults);
|
||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testSQLChannel);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testSQLChannel);
|
||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testSQLLogger);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testSQLLogger);
|
||||||
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testSessionTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testTransactor);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -919,6 +919,9 @@ CppUnit::Test* ODBCOracleTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testSQLChannel);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testSQLChannel);
|
||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testSQLLogger);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testSQLLogger);
|
||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testAutoTransaction);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testAutoTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCOracleTest, testSessionTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCOracleTest, testTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCOracleTest, testTransactor);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -656,6 +656,9 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
|||||||
//CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults);
|
//CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults);
|
||||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLChannel);
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLChannel);
|
||||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLLogger);
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLLogger);
|
||||||
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSessionTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransactor);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -806,6 +806,9 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testMultipleResults);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testMultipleResults);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSQLChannel);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSQLChannel);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSQLLogger);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSQLLogger);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSessionTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransactor);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -397,6 +397,9 @@ CppUnit::Test* ODBCSQLiteTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testDynamicAny);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testDynamicAny);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSQLChannel);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSQLChannel);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSQLLogger);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSQLLogger);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSessionTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransaction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTransactor);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,7 @@ ODBCTest::ODBCTest(const std::string& name,
|
|||||||
_rPwd(rPwd),
|
_rPwd(rPwd),
|
||||||
_rConnectString(rConnectString)
|
_rConnectString(rConnectString)
|
||||||
{
|
{
|
||||||
|
_pSession->setFeature("autoCommit", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1141,6 +1142,51 @@ void ODBCTest::testSQLLogger()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ODBCTest::testSessionTransaction()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
for (int i = 0; i < 8;)
|
||||||
|
{
|
||||||
|
recreatePersonTable();
|
||||||
|
_pSession->setFeature("autoBind", bindValue(i));
|
||||||
|
_pSession->setFeature("autoExtract", bindValue(i+1));
|
||||||
|
_pExecutor->sessionTransaction(_rConnectString);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ODBCTest::testTransaction()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
for (int i = 0; i < 8;)
|
||||||
|
{
|
||||||
|
recreatePersonTable();
|
||||||
|
_pSession->setFeature("autoBind", bindValue(i));
|
||||||
|
_pSession->setFeature("autoExtract", bindValue(i+1));
|
||||||
|
_pExecutor->transaction(_rConnectString);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ODBCTest::testTransactor()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
for (int i = 0; i < 8;)
|
||||||
|
{
|
||||||
|
recreatePersonTable();
|
||||||
|
_pSession->setFeature("autoBind", bindValue(i));
|
||||||
|
_pSession->setFeature("autoExtract", bindValue(i+1));
|
||||||
|
_pExecutor->transactor();
|
||||||
|
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,
|
||||||
|
@ -161,9 +161,12 @@ public:
|
|||||||
virtual void testMultipleResults();
|
virtual void testMultipleResults();
|
||||||
|
|
||||||
virtual void testSQLChannel();
|
virtual void testSQLChannel();
|
||||||
|
|
||||||
virtual void testSQLLogger();
|
virtual void testSQLLogger();
|
||||||
|
|
||||||
|
virtual void testSessionTransaction();
|
||||||
|
virtual void testTransaction();
|
||||||
|
virtual void testTransactor();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef Poco::Data::ODBC::Utility::DriverMap Drivers;
|
typedef Poco::Data::ODBC::Utility::DriverMap Drivers;
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
#include "Poco/Data/BulkExtraction.h"
|
#include "Poco/Data/BulkExtraction.h"
|
||||||
#include "Poco/Data/BulkBinding.h"
|
#include "Poco/Data/BulkBinding.h"
|
||||||
#include "Poco/Data/SQLChannel.h"
|
#include "Poco/Data/SQLChannel.h"
|
||||||
|
#include "Poco/Data/Transaction.h"
|
||||||
#include "Poco/Data/ODBC/Connector.h"
|
#include "Poco/Data/ODBC/Connector.h"
|
||||||
#include "Poco/Data/ODBC/Utility.h"
|
#include "Poco/Data/ODBC/Utility.h"
|
||||||
#include "Poco/Data/ODBC/Diagnostics.h"
|
#include "Poco/Data/ODBC/Diagnostics.h"
|
||||||
@ -83,6 +84,7 @@ using Poco::Data::BindingException;
|
|||||||
using Poco::Data::CLOB;
|
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::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;
|
||||||
@ -3376,3 +3378,329 @@ void SQLExecutor::sqlLogger(const std::string& connect)
|
|||||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("sqlChannel()"); }
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("sqlChannel()"); }
|
||||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("sqlChannel()"); }
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("sqlChannel()"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::setTransactionIsolation(Session& session, Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
if (session.hasTransactionIsolation(ti))
|
||||||
|
{
|
||||||
|
std::string funct = "setTransactionIsolation()";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Transaction t(session, false);
|
||||||
|
t.setIsolation(ti);
|
||||||
|
|
||||||
|
assert (ti == t.getIsolation());
|
||||||
|
assert (t.isIsolation(ti));
|
||||||
|
|
||||||
|
assert (ti == session.getTransactionIsolation());
|
||||||
|
assert (session.isTransactionIsolation(ti));
|
||||||
|
}
|
||||||
|
catch(Poco::Exception& e){ std::cout << funct << ':' << e.displayText() << std::endl;}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Transaction isolation not supported: ";
|
||||||
|
switch (ti)
|
||||||
|
{
|
||||||
|
case Session::TRANSACTION_READ_COMMITTED:
|
||||||
|
std::cout << "READ COMMITTED"; break;
|
||||||
|
case Session::TRANSACTION_READ_UNCOMMITTED:
|
||||||
|
std::cout << "READ UNCOMMITTED"; break;
|
||||||
|
case Session::TRANSACTION_REPEATABLE_READ:
|
||||||
|
std::cout << "REPEATABLE READ"; break;
|
||||||
|
case Session::TRANSACTION_SERIALIZABLE:
|
||||||
|
std::cout << "SERIALIZABLE"; break;
|
||||||
|
default:
|
||||||
|
std::cout << "UNKNOWN"; break;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::sessionTransaction(const std::string& connect)
|
||||||
|
{
|
||||||
|
if (!session().canTransact())
|
||||||
|
{
|
||||||
|
std::cout << "Session not capable of transactions." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session local("odbc", connect);
|
||||||
|
local.setFeature("autoCommit", true);
|
||||||
|
|
||||||
|
std::string funct = "transaction()";
|
||||||
|
std::vector<std::string> lastNames;
|
||||||
|
std::vector<std::string> firstNames;
|
||||||
|
std::vector<std::string> addresses;
|
||||||
|
std::vector<int> ages;
|
||||||
|
std::string tableName("Person");
|
||||||
|
lastNames.push_back("LN1");
|
||||||
|
lastNames.push_back("LN2");
|
||||||
|
firstNames.push_back("FN1");
|
||||||
|
firstNames.push_back("FN2");
|
||||||
|
addresses.push_back("ADDR1");
|
||||||
|
addresses.push_back("ADDR2");
|
||||||
|
ages.push_back(1);
|
||||||
|
ages.push_back(2);
|
||||||
|
int count = 0, locCount = 0;
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
bool autoCommit = session().getFeature("autoCommit");
|
||||||
|
|
||||||
|
session().setFeature("autoCommit", true);
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
session().setFeature("autoCommit", false);
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
|
||||||
|
setTransactionIsolation(session(), Session::TRANSACTION_READ_UNCOMMITTED);
|
||||||
|
setTransactionIsolation(session(), Session::TRANSACTION_REPEATABLE_READ);
|
||||||
|
setTransactionIsolation(session(), Session::TRANSACTION_SERIALIZABLE);
|
||||||
|
|
||||||
|
setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
|
||||||
|
session().begin();
|
||||||
|
assert (session().isTransaction());
|
||||||
|
try { session() << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
|
assert (session().isTransaction());
|
||||||
|
|
||||||
|
Statement stmt = (local << "SELECT COUNT(*) FROM PERSON", into(locCount), async, now);
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
assert (session().isTransaction());
|
||||||
|
session().rollback();
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
|
||||||
|
stmt.wait();
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
|
||||||
|
session().begin();
|
||||||
|
try { session() << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
|
assert (session().isTransaction());
|
||||||
|
|
||||||
|
Statement stmt1 = (local << "SELECT COUNT(*) FROM PERSON", into(locCount), async, now);
|
||||||
|
|
||||||
|
session().commit();
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
|
||||||
|
stmt1.wait();
|
||||||
|
assert (2 == locCount);
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
session().setFeature("autoCommit", autoCommit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::transaction(const std::string& connect)
|
||||||
|
{
|
||||||
|
if (!session().canTransact())
|
||||||
|
{
|
||||||
|
std::cout << "Session not transaction-capable." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session local("odbc", connect);
|
||||||
|
local.setFeature("autoCommit", true);
|
||||||
|
|
||||||
|
setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
setTransactionIsolation(local, Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
|
||||||
|
std::string funct = "transaction()";
|
||||||
|
std::vector<std::string> lastNames;
|
||||||
|
std::vector<std::string> firstNames;
|
||||||
|
std::vector<std::string> addresses;
|
||||||
|
std::vector<int> ages;
|
||||||
|
std::string tableName("Person");
|
||||||
|
lastNames.push_back("LN1");
|
||||||
|
lastNames.push_back("LN2");
|
||||||
|
firstNames.push_back("FN1");
|
||||||
|
firstNames.push_back("FN2");
|
||||||
|
addresses.push_back("ADDR1");
|
||||||
|
addresses.push_back("ADDR2");
|
||||||
|
ages.push_back(1);
|
||||||
|
ages.push_back(2);
|
||||||
|
int count = 0, locCount = 0;
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
bool autoCommit = session().getFeature("autoCommit");
|
||||||
|
|
||||||
|
session().setFeature("autoCommit", true);
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
session().setFeature("autoCommit", false);
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
session().setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED);
|
||||||
|
|
||||||
|
{
|
||||||
|
Transaction trans(session());
|
||||||
|
assert (trans.isActive());
|
||||||
|
assert (session().isTransaction());
|
||||||
|
|
||||||
|
try { session() << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
assert (session().isTransaction());
|
||||||
|
assert (trans.isActive());
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
assert (session().isTransaction());
|
||||||
|
assert (trans.isActive());
|
||||||
|
}
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
|
||||||
|
{
|
||||||
|
Transaction trans(session());
|
||||||
|
try { session() << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
Statement stmt1 = (local << "SELECT COUNT(*) FROM PERSON", into(locCount), async, now);
|
||||||
|
|
||||||
|
assert (session().isTransaction());
|
||||||
|
assert (trans.isActive());
|
||||||
|
trans.commit();
|
||||||
|
assert (!session().isTransaction());
|
||||||
|
assert (!trans.isActive());
|
||||||
|
|
||||||
|
stmt1.wait();
|
||||||
|
assert (2 == locCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
try { session() << "DELETE FROM PERSON", now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
Statement stmt1 = (local << "SELECT COUNT(*) FROM PERSON", into(locCount), async, now);
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
session().commit();
|
||||||
|
|
||||||
|
stmt1.wait();
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
std::string sql1 = format("INSERT INTO PERSON VALUES ('%s','%s','%s',%d)", lastNames[0], firstNames[0], addresses[0], ages[0]);
|
||||||
|
std::string sql2 = format("INSERT INTO PERSON VALUES ('%s','%s','%s',%d)", lastNames[1], firstNames[1], addresses[1], ages[1]);
|
||||||
|
std::vector<std::string> sql;
|
||||||
|
sql.push_back(sql1);
|
||||||
|
sql.push_back(sql2);
|
||||||
|
|
||||||
|
Transaction trans(session());
|
||||||
|
|
||||||
|
trans.execute(sql1, false);
|
||||||
|
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 (1 == count);
|
||||||
|
trans.execute(sql2, false);
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
Statement stmt2 = (local << "SELECT COUNT(*) FROM PERSON", into(locCount), async, now);
|
||||||
|
|
||||||
|
trans.rollback();
|
||||||
|
|
||||||
|
stmt2.wait();
|
||||||
|
assert (0 == locCount);
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
|
||||||
|
trans.execute(sql);
|
||||||
|
|
||||||
|
Statement stmt3 = (local << "SELECT COUNT(*) FROM PERSON", into(locCount), now);
|
||||||
|
assert (2 == locCount);
|
||||||
|
|
||||||
|
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 (2 == count);
|
||||||
|
|
||||||
|
session().setFeature("autoCommit", autoCommit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct TestCommitTransaction
|
||||||
|
{
|
||||||
|
void operator () (Session& session) const
|
||||||
|
{
|
||||||
|
session << "INSERT INTO PERSON VALUES (?,?,?,?)", bind("lastName"), bind("firstName"), bind("address"), bind("age"), now;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct TestRollbackTransaction
|
||||||
|
{
|
||||||
|
void operator () (Session& session) const
|
||||||
|
{
|
||||||
|
session << "INSERT INTO PERSON VALUES (?,?,?,?)", bind("lastName"), bind("firstName"), bind("address"), bind("age"), now;
|
||||||
|
throw Poco::Exception("test");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::transactor()
|
||||||
|
{
|
||||||
|
std::string funct = "transaction()";
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
TestCommitTransaction ct;
|
||||||
|
Transaction t1(session());
|
||||||
|
t1.transact(ct);
|
||||||
|
|
||||||
|
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 (1 == count);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TestRollbackTransaction rt;
|
||||||
|
Transaction t2(session());
|
||||||
|
t2.transact(rt);
|
||||||
|
} catch (Poco::Exception&) { }
|
||||||
|
|
||||||
|
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 (0 == count);
|
||||||
|
}
|
@ -514,12 +514,17 @@ public:
|
|||||||
void sqlChannel(const std::string& connect);
|
void sqlChannel(const std::string& connect);
|
||||||
void sqlLogger(const std::string& connect);
|
void sqlLogger(const std::string& connect);
|
||||||
|
|
||||||
|
void sessionTransaction(const std::string& connect);
|
||||||
|
void transaction(const std::string& connect);
|
||||||
|
void transactor();
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
Poco::Data::Session& session();
|
void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti);
|
||||||
|
|
||||||
|
Poco::Data::Session& session();
|
||||||
Poco::Data::Session* _pSession;
|
Poco::Data::Session* _pSession;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,8 +83,25 @@ public:
|
|||||||
bool isConnected();
|
bool isConnected();
|
||||||
/// Returns true if connected, false otherwise.
|
/// Returns true if connected, false otherwise.
|
||||||
|
|
||||||
|
bool canTransact();
|
||||||
|
/// Returns true if session has transaction capabilities.
|
||||||
|
|
||||||
bool isTransaction();
|
bool isTransaction();
|
||||||
/// Returns true iff a transaction is in progress.
|
/// Returns true iff a transaction is a transaction is in progress, false otherwise.
|
||||||
|
|
||||||
|
void setTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Sets the transaction isolation level.
|
||||||
|
|
||||||
|
Poco::UInt32 getTransactionIsolation();
|
||||||
|
/// Returns the transaction isolation level.
|
||||||
|
|
||||||
|
bool hasTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponding
|
||||||
|
/// to the supplied bitmask is supported.
|
||||||
|
|
||||||
|
bool isTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponds
|
||||||
|
/// to the supplied bitmask.
|
||||||
|
|
||||||
const std::string& connectorName();
|
const std::string& connectorName();
|
||||||
/// Returns the name of the connector.
|
/// Returns the name of the connector.
|
||||||
@ -107,6 +124,12 @@ private:
|
|||||||
//
|
//
|
||||||
// inlines
|
// inlines
|
||||||
//
|
//
|
||||||
|
inline bool SessionImpl::canTransact()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool SessionImpl::isTransaction()
|
inline bool SessionImpl::isTransaction()
|
||||||
{
|
{
|
||||||
return _isTransaction;
|
return _isTransaction;
|
||||||
|
@ -38,7 +38,9 @@
|
|||||||
#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/Session.h"
|
||||||
#include "Poco/String.h"
|
#include "Poco/String.h"
|
||||||
|
#include "Poco/Exception.h"
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
@ -104,6 +106,33 @@ void SessionImpl::rollback()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::setTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
if (ti != Session::TRANSACTION_READ_COMMITTED)
|
||||||
|
throw Poco::InvalidArgumentException("setTransactionIsolation()");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 SessionImpl::getTransactionIsolation()
|
||||||
|
{
|
||||||
|
return Session::TRANSACTION_READ_COMMITTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::hasTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
if (ti == Session::TRANSACTION_READ_COMMITTED) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::isTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
if (ti == Session::TRANSACTION_READ_COMMITTED) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SessionImpl::open()
|
void SessionImpl::open()
|
||||||
{
|
{
|
||||||
int rc = sqlite3_open(connectionString().c_str(), &_pDB);
|
int rc = sqlite3_open(connectionString().c_str(), &_pDB);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// Package: Core
|
// Package: Core
|
||||||
// Module: AutoTransaction
|
// Module: AutoTransaction
|
||||||
//
|
//
|
||||||
// Definition of the AutoTransaction class.
|
// Forward header for the Transaction class.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
@ -41,49 +41,14 @@
|
|||||||
#define Data_AutoTransaction_INCLUDED
|
#define Data_AutoTransaction_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/Data.h"
|
#include "Poco/Data/Transaction.h"
|
||||||
#include "Poco/Data/Session.h"
|
|
||||||
#include "Poco/Logger.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
|
|
||||||
class Data_API AutoTransaction
|
typedef Transaction AutoTransaction;
|
||||||
/// AutoTransaction helps with transactions in domain logic.
|
|
||||||
/// When an AutoTransaction object is created, it first checks whether a
|
|
||||||
/// transaction is in progress. If not, a new transaction is created.
|
|
||||||
/// When the AutoTransaction is destroyed, and commit() has been called,
|
|
||||||
/// nothing is done. Otherwise, the current transaction is rolled back.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AutoTransaction(Poco::Data::Session& session, Poco::Logger* pLogger = 0);
|
|
||||||
/// Creates the AutoTransaction, using the given database session and logger.
|
|
||||||
|
|
||||||
~AutoTransaction();
|
|
||||||
/// Destroys the AutoTransaction.
|
|
||||||
/// Rolls back the current database transaction if it has not been commited
|
|
||||||
/// (by calling commit()), or rolled back (by calling rollback()).
|
|
||||||
///
|
|
||||||
/// If an exception is thrown during rollback, the exception is logged
|
|
||||||
/// and no further action is taken.
|
|
||||||
|
|
||||||
void commit();
|
|
||||||
/// Commits the current transaction.
|
|
||||||
|
|
||||||
void rollback();
|
|
||||||
/// Rolls back the current transaction.
|
|
||||||
|
|
||||||
private:
|
|
||||||
AutoTransaction();
|
|
||||||
AutoTransaction(const AutoTransaction&);
|
|
||||||
AutoTransaction& operator = (const AutoTransaction&);
|
|
||||||
|
|
||||||
Session& _session;
|
|
||||||
Logger* _pLogger;
|
|
||||||
bool _mustRollback;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
} } // namespace Poco::Data
|
||||||
|
@ -72,7 +72,12 @@ public:
|
|||||||
void rollback();
|
void rollback();
|
||||||
void close();
|
void close();
|
||||||
bool isConnected();
|
bool isConnected();
|
||||||
|
bool canTransact();
|
||||||
bool isTransaction();
|
bool isTransaction();
|
||||||
|
void setTransactionIsolation(Poco::UInt32);
|
||||||
|
Poco::UInt32 getTransactionIsolation();
|
||||||
|
bool hasTransactionIsolation(Poco::UInt32);
|
||||||
|
bool isTransactionIsolation(Poco::UInt32);
|
||||||
const std::string& connectorName();
|
const std::string& connectorName();
|
||||||
void setFeature(const std::string& name, bool state);
|
void setFeature(const std::string& name, bool state);
|
||||||
bool getFeature(const std::string& name);
|
bool getFeature(const std::string& name);
|
||||||
|
@ -173,6 +173,11 @@ 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 Poco::UInt32 TRANSACTION_READ_UNCOMMITTED = 0x00000001L;
|
||||||
|
static const Poco::UInt32 TRANSACTION_READ_COMMITTED = 0x00000002L;
|
||||||
|
static const Poco::UInt32 TRANSACTION_REPEATABLE_READ = 0x00000004L;
|
||||||
|
static const Poco::UInt32 TRANSACTION_SERIALIZABLE = 0x00000008L;
|
||||||
|
|
||||||
Session(Poco::AutoPtr<SessionImpl> ptrImpl);
|
Session(Poco::AutoPtr<SessionImpl> ptrImpl);
|
||||||
/// Creates the Session.
|
/// Creates the Session.
|
||||||
|
|
||||||
@ -221,9 +226,26 @@ public:
|
|||||||
bool isConnected();
|
bool isConnected();
|
||||||
/// Returns true iff session is connected, false otherwise.
|
/// Returns true iff session is connected, false otherwise.
|
||||||
|
|
||||||
|
bool canTransact();
|
||||||
|
/// Returns true if session has transaction capabilities.
|
||||||
|
|
||||||
bool isTransaction();
|
bool isTransaction();
|
||||||
/// Returns true iff a transaction is in progress, false otherwise.
|
/// Returns true iff a transaction is in progress, false otherwise.
|
||||||
|
|
||||||
|
void setTransactionIsolation(Poco::UInt32);
|
||||||
|
/// Sets the transaction isolation level.
|
||||||
|
|
||||||
|
Poco::UInt32 getTransactionIsolation();
|
||||||
|
/// Returns the transaction isolation level.
|
||||||
|
|
||||||
|
bool hasTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponding
|
||||||
|
/// to the supplied bitmask is supported.
|
||||||
|
|
||||||
|
bool isTransactionIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponds
|
||||||
|
/// to the supplied bitmask.
|
||||||
|
|
||||||
std::string uri();
|
std::string uri();
|
||||||
/// Returns the URI for this session.
|
/// Returns the URI for this session.
|
||||||
|
|
||||||
@ -318,12 +340,42 @@ inline bool Session::isConnected()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Session::canTransact()
|
||||||
|
{
|
||||||
|
return _ptrImpl->canTransact();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool Session::isTransaction()
|
inline bool Session::isTransaction()
|
||||||
{
|
{
|
||||||
return _ptrImpl->isTransaction();
|
return _ptrImpl->isTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Session::setTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
_ptrImpl->setTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Poco::UInt32 Session::getTransactionIsolation()
|
||||||
|
{
|
||||||
|
return _ptrImpl->getTransactionIsolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Session::hasTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return _ptrImpl->hasTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Session::isTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return _ptrImpl->isTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::string Session::uri(const std::string& connector,
|
inline std::string Session::uri(const std::string& connector,
|
||||||
const std::string& connectionString)
|
const std::string& connectionString)
|
||||||
{
|
{
|
||||||
|
@ -83,9 +83,26 @@ public:
|
|||||||
virtual bool isConnected() = 0;
|
virtual bool isConnected() = 0;
|
||||||
/// Returns true if session is connected, false otherwise.
|
/// Returns true if session is connected, false otherwise.
|
||||||
|
|
||||||
|
virtual bool canTransact() = 0;
|
||||||
|
/// Returns true if session has transaction capabilities.
|
||||||
|
|
||||||
virtual bool isTransaction() = 0;
|
virtual bool isTransaction() = 0;
|
||||||
/// Returns true iff a transaction is a transaction is in progress, false otherwise.
|
/// Returns true iff a transaction is a transaction is in progress, false otherwise.
|
||||||
|
|
||||||
|
virtual void setTransactionIsolation(Poco::UInt32) = 0;
|
||||||
|
/// Sets the transaction isolation level.
|
||||||
|
|
||||||
|
virtual Poco::UInt32 getTransactionIsolation() = 0;
|
||||||
|
/// Returns the transaction isolation level.
|
||||||
|
|
||||||
|
virtual bool hasTransactionIsolation(Poco::UInt32) = 0;
|
||||||
|
/// Returns true iff the transaction isolation level corresponding
|
||||||
|
/// to the supplied bitmask is supported.
|
||||||
|
|
||||||
|
virtual bool isTransactionIsolation(Poco::UInt32) = 0;
|
||||||
|
/// Returns true iff the transaction isolation level corresponds
|
||||||
|
/// to the supplied bitmask.
|
||||||
|
|
||||||
virtual const std::string& connectorName() = 0;
|
virtual const std::string& connectorName() = 0;
|
||||||
/// Returns the name of the connector.
|
/// Returns the name of the connector.
|
||||||
|
|
||||||
|
242
Data/include/Poco/Data/Transaction.h
Normal file
242
Data/include/Poco/Data/Transaction.h
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
//
|
||||||
|
// Transaction.h
|
||||||
|
//
|
||||||
|
// $Id: //poco/Main/Data/include/Poco/Data/Transaction.h#2 $
|
||||||
|
//
|
||||||
|
// Library: Data
|
||||||
|
// Package: Core
|
||||||
|
// Module: Transaction
|
||||||
|
//
|
||||||
|
// Definition of the Transaction class.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
// obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
// this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
// execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
// Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
// do so, all subject to the following:
|
||||||
|
//
|
||||||
|
// The copyright notices in the Software and this entire statement, including
|
||||||
|
// the above license grant, this restriction and the following disclaimer,
|
||||||
|
// must be included in all copies of the Software, in whole or in part, and
|
||||||
|
// all derivative works of the Software, unless such copies or derivative
|
||||||
|
// works are solely in the form of machine-executable object code generated by
|
||||||
|
// a source language processor.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Data_Transaction_INCLUDED
|
||||||
|
#define Data_Transaction_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Data/Data.h"
|
||||||
|
#include "Poco/Data/Session.h"
|
||||||
|
#include "Poco/Logger.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
|
||||||
|
class Data_API Transaction
|
||||||
|
/// Transaction helps with transactions in domain logic.
|
||||||
|
/// When an Transaction object is created, it first checks whether a
|
||||||
|
/// transaction is in progress. If not, a new transaction is created.
|
||||||
|
/// When the Transaction is destroyed, and commit() has been called,
|
||||||
|
/// nothing is done. Otherwise, the current transaction is rolled back.
|
||||||
|
/// See Transaction for more detaisl nad purpose of this template.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
class Transactor
|
||||||
|
/// Transactor is a helper functor template.
|
||||||
|
/// It is used to consolidate the C++ code that participates in
|
||||||
|
/// the transaction.
|
||||||
|
///
|
||||||
|
/// Example usage:
|
||||||
|
///
|
||||||
|
/// struct ATransaction
|
||||||
|
/// {
|
||||||
|
/// void operator () (Session& session) const
|
||||||
|
/// {
|
||||||
|
/// // do something ...
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// ATransaction t;
|
||||||
|
/// Transaction at(session, t); // commits, if successful
|
||||||
|
///
|
||||||
|
/// See Transaction for more details on how to use Transactor.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Transactor(T& transactor): _transactor(transactor)
|
||||||
|
/// Creates the Transactor
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void operator () (Poco::Data::Session& session)
|
||||||
|
{
|
||||||
|
_transactor(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void operator () (Poco::Data::Session& session) const
|
||||||
|
{
|
||||||
|
_transactor(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Transactor();
|
||||||
|
Transactor(const Transactor&);
|
||||||
|
Transactor& operator = (const Transactor&);
|
||||||
|
|
||||||
|
T& _transactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
Transaction(Poco::Data::Session& session, Poco::Logger* pLogger = 0);
|
||||||
|
/// Creates the Transaction and starts it, using the given database session and logger.
|
||||||
|
|
||||||
|
Transaction(Poco::Data::Session& session, bool start);
|
||||||
|
/// Creates the Transaction, using the given database session.
|
||||||
|
/// If start is true, transaction is started, otherwise begin() must be called
|
||||||
|
/// to start the transaction.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Transaction(Poco::Data::Session& rSession, T& t, Poco::Logger* pLogger = 0):
|
||||||
|
_rSession(rSession),
|
||||||
|
_pLogger(pLogger)
|
||||||
|
/// Creates the Transaction, using the given database session and logger.
|
||||||
|
/// The type for the second argument must be Transactor-compatible, i.e.
|
||||||
|
/// provide the overload for the operator ().
|
||||||
|
/// When transaction is created using this constructor, it is executed and
|
||||||
|
/// commited automatically. If no error occurs, rollback is disabled and does
|
||||||
|
/// not occur at destruction time.
|
||||||
|
{
|
||||||
|
begin();
|
||||||
|
execute(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Transaction();
|
||||||
|
/// Destroys the Transaction.
|
||||||
|
/// Rolls back the current database transaction if it has not been commited
|
||||||
|
/// (by calling commit()), or rolled back (by calling rollback()).
|
||||||
|
///
|
||||||
|
/// If an exception is thrown during rollback, the exception is logged
|
||||||
|
/// and no further action is taken.
|
||||||
|
|
||||||
|
void setIsolation(Poco::UInt32 ti);
|
||||||
|
/// Sets the transaction isolation level.
|
||||||
|
|
||||||
|
Poco::UInt32 getIsolation();
|
||||||
|
/// Returns the transaction isolation level.
|
||||||
|
|
||||||
|
bool hasIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponding
|
||||||
|
/// to the supplied bitmask is supported.
|
||||||
|
|
||||||
|
bool isIsolation(Poco::UInt32 ti);
|
||||||
|
/// Returns true iff the transaction isolation level corresponds
|
||||||
|
/// to the supplied bitmask.
|
||||||
|
|
||||||
|
void execute(const std::string& sql, bool doCommit = true);
|
||||||
|
/// Executes and, if doCommit is true, commits the transaction.
|
||||||
|
/// Passing true value for commit disables rollback during destruction
|
||||||
|
/// of this Transaction object.
|
||||||
|
|
||||||
|
void execute(const std::vector<std::string>& sql);
|
||||||
|
/// Executes all the SQL statements supplied in the vector and, after the last
|
||||||
|
/// one is sucesfully executed, commits the transaction.
|
||||||
|
/// If an error occurs during execution, transaction is rolled back.
|
||||||
|
/// Passing true value for commit disables rollback during destruction
|
||||||
|
/// of this Transaction object.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void transact(T& t)
|
||||||
|
/// Executes the transactor and, if doCommit is true, commits the transaction.
|
||||||
|
/// Passing true value for commit disables rollback during destruction
|
||||||
|
/// of this Transaction object.
|
||||||
|
{
|
||||||
|
Transactor<T> transactor(t);
|
||||||
|
transactor(_rSession);
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit();
|
||||||
|
/// Commits the current transaction.
|
||||||
|
|
||||||
|
void rollback();
|
||||||
|
/// Rolls back the current transaction.
|
||||||
|
|
||||||
|
bool isActive();
|
||||||
|
/// Returns false after the transaction has been committed or rolled back,
|
||||||
|
/// true if the transaction is ongoing.
|
||||||
|
|
||||||
|
void setLogger(Poco::Logger* pLogger);
|
||||||
|
/// Sets the logger for this transaction.
|
||||||
|
/// Transaction does not take the ownership of the pointer.
|
||||||
|
|
||||||
|
private:
|
||||||
|
Transaction();
|
||||||
|
Transaction(const Transaction&);
|
||||||
|
Transaction& operator = (const Transaction&);
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
/// Begins the transaction if the session is already not in transaction.
|
||||||
|
/// Otherwise does nothing.
|
||||||
|
|
||||||
|
Session _rSession;
|
||||||
|
Logger* _pLogger;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Transaction::isActive()
|
||||||
|
{
|
||||||
|
return _rSession.isTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Transaction::setIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
_rSession.setTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Poco::UInt32 Transaction::getIsolation()
|
||||||
|
{
|
||||||
|
return _rSession.getTransactionIsolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Transaction::hasIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return _rSession.isTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Transaction::isIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return _rSession.isTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Transaction::setLogger(Poco::Logger* pLogger)
|
||||||
|
{
|
||||||
|
_pLogger = pLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} } // namespace Poco::Data
|
||||||
|
|
||||||
|
|
||||||
|
#endif // Data_Transaction_INCLUDED
|
@ -80,12 +80,42 @@ bool PooledSessionImpl::isConnected()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PooledSessionImpl::canTransact()
|
||||||
|
{
|
||||||
|
return access()->canTransact();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PooledSessionImpl::isTransaction()
|
bool PooledSessionImpl::isTransaction()
|
||||||
{
|
{
|
||||||
return access()->isTransaction();
|
return access()->isTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PooledSessionImpl::setTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
access()->setTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 PooledSessionImpl::getTransactionIsolation()
|
||||||
|
{
|
||||||
|
return access()->getTransactionIsolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PooledSessionImpl::hasTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return access()->hasTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PooledSessionImpl::isTransactionIsolation(Poco::UInt32 ti)
|
||||||
|
{
|
||||||
|
return access()->isTransactionIsolation(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PooledSessionImpl::rollback()
|
void PooledSessionImpl::rollback()
|
||||||
{
|
{
|
||||||
return access()->rollback();
|
return access()->rollback();
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
//
|
//
|
||||||
// AutoTransaction.cpp
|
// Transaction.cpp
|
||||||
//
|
//
|
||||||
// $Id: //poco/Main/Data/src/AutoTransaction.cpp#1 $
|
// $Id: //poco/Main/Data/src/Transaction.cpp#1 $
|
||||||
//
|
//
|
||||||
// Library: Data
|
// Library: Data
|
||||||
// Package: DataCore
|
// Package: DataCore
|
||||||
// Module: AutoTransaction
|
// Module: Transaction
|
||||||
//
|
//
|
||||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
@ -34,35 +34,40 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/AutoTransaction.h"
|
#include "Poco/Data/Transaction.h"
|
||||||
|
#include "Poco/Exception.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
|
|
||||||
AutoTransaction::AutoTransaction(Poco::Data::Session& session, Poco::Logger* pLogger):
|
Transaction::Transaction(Poco::Data::Session& rSession, Poco::Logger* pLogger):
|
||||||
_session(session),
|
_rSession(rSession),
|
||||||
_pLogger(pLogger),
|
_pLogger(pLogger)
|
||||||
_mustRollback(true)
|
|
||||||
{
|
{
|
||||||
if (!_session.isTransaction())
|
begin();
|
||||||
{
|
|
||||||
_session.begin();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoTransaction::~AutoTransaction()
|
Transaction::Transaction(Poco::Data::Session& rSession, bool start):
|
||||||
|
_rSession(rSession),
|
||||||
|
_pLogger(0)
|
||||||
{
|
{
|
||||||
if (_mustRollback)
|
if (start) begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Transaction::~Transaction()
|
||||||
|
{
|
||||||
|
if (_rSession.isTransaction())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_pLogger)
|
if (_pLogger)
|
||||||
_pLogger->debug("Rolling back transaction.");
|
_pLogger->debug("Rolling back transaction.");
|
||||||
|
|
||||||
_session.rollback();
|
_rSession.rollback();
|
||||||
}
|
}
|
||||||
catch (Poco::Exception& exc)
|
catch (Poco::Exception& exc)
|
||||||
{
|
{
|
||||||
@ -73,23 +78,56 @@ AutoTransaction::~AutoTransaction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AutoTransaction::commit()
|
void Transaction::begin()
|
||||||
|
{
|
||||||
|
if (!_rSession.isTransaction())
|
||||||
|
_rSession.begin();
|
||||||
|
else
|
||||||
|
throw InvalidAccessException("Transaction in progress.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Transaction::execute(const std::string& sql, bool doCommit)
|
||||||
|
{
|
||||||
|
if (!_rSession.isTransaction()) _rSession.begin();
|
||||||
|
_rSession << sql, Keywords::now;
|
||||||
|
if (doCommit) commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Transaction::execute(const std::vector<std::string>& sql)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::vector<std::string>::const_iterator it = sql.begin();
|
||||||
|
std::vector<std::string>::const_iterator end = sql.end();
|
||||||
|
for (; it != end; ++it) execute(*it, it + 1 == end ? true : false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception& ex)
|
||||||
|
{
|
||||||
|
if (_pLogger) _pLogger->error(ex.displayText());
|
||||||
|
}
|
||||||
|
|
||||||
|
rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Transaction::commit()
|
||||||
{
|
{
|
||||||
if (_pLogger)
|
if (_pLogger)
|
||||||
_pLogger->debug("Committing transaction.");
|
_pLogger->debug("Committing transaction.");
|
||||||
|
|
||||||
_session.commit();
|
_rSession.commit();
|
||||||
_mustRollback = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AutoTransaction::rollback()
|
void Transaction::rollback()
|
||||||
{
|
{
|
||||||
if (_pLogger)
|
if (_pLogger)
|
||||||
_pLogger->debug("Rolling back transaction.");
|
_pLogger->debug("Rolling back transaction.");
|
||||||
|
|
||||||
_session.rollback();
|
_rSession.rollback();
|
||||||
_mustRollback = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,12 +93,41 @@ bool SessionImpl::isConnected()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::canTransact()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SessionImpl::isTransaction()
|
bool SessionImpl::isTransaction()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionImpl::setTransactionIsolation(Poco::UInt32)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 SessionImpl::getTransactionIsolation()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::hasTransactionIsolation(Poco::UInt32)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SessionImpl::isTransactionIsolation(Poco::UInt32)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::string& SessionImpl::connectorName()
|
const std::string& SessionImpl::connectorName()
|
||||||
{
|
{
|
||||||
return Connector::KEY;
|
return Connector::KEY;
|
||||||
|
@ -75,9 +75,26 @@ public:
|
|||||||
/// Returns true if session is connected to the database,
|
/// Returns true if session is connected to the database,
|
||||||
/// false otherwise.
|
/// false otherwise.
|
||||||
|
|
||||||
|
bool canTransact();
|
||||||
|
/// Returns true if session has transaction capabilities.
|
||||||
|
|
||||||
bool isTransaction();
|
bool isTransaction();
|
||||||
/// Returns true iff a transaction is a transaction is in progress, false otherwise.
|
/// Returns true iff a transaction is a transaction is in progress, false otherwise.
|
||||||
|
|
||||||
|
void setTransactionIsolation(Poco::UInt32);
|
||||||
|
/// Sets the transaction isolation level.
|
||||||
|
|
||||||
|
Poco::UInt32 getTransactionIsolation();
|
||||||
|
/// Returns the transaction isolation level.
|
||||||
|
|
||||||
|
bool hasTransactionIsolation(Poco::UInt32);
|
||||||
|
/// Returns true iff the transaction isolation level corresponding
|
||||||
|
/// to the supplied bitmask is supported.
|
||||||
|
|
||||||
|
bool isTransactionIsolation(Poco::UInt32);
|
||||||
|
/// Returns true iff the transaction isolation level corresponds
|
||||||
|
/// to the supplied bitmask.
|
||||||
|
|
||||||
const std::string& connectorName();
|
const std::string& connectorName();
|
||||||
/// Returns the name of the connector.
|
/// Returns the name of the connector.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user