diff options
-rw-r--r-- | libdbpp/connection.cpp | 16 | ||||
-rw-r--r-- | libdbpp/connection.h | 14 | ||||
-rw-r--r-- | libdbpp/unittests/testConnection.cpp | 30 |
3 files changed, 55 insertions, 5 deletions
diff --git a/libdbpp/connection.cpp b/libdbpp/connection.cpp index 333becb..1624ce6 100644 --- a/libdbpp/connection.cpp +++ b/libdbpp/connection.cpp @@ -74,6 +74,22 @@ DB::TransactionRequired::TransactionRequired() : { } +DB::TransactionScope::TransactionScope(DB::Connection * c) : + conn(c) +{ + conn->beginTx(); +} + +DB::TransactionScope::~TransactionScope() +{ + if (std::uncaught_exception()) { + conn->rollbackTx(); + } + else { + conn->commitTx(); + } +} + INSTANTIATEFACTORY(DB::Connection, std::string); PLUGINRESOLVER(DB::ConnectionFactory, DB::Connection::resolvePlugin); diff --git a/libdbpp/connection.h b/libdbpp/connection.h index a15a9ab..e34315a 100644 --- a/libdbpp/connection.h +++ b/libdbpp/connection.h @@ -133,6 +133,20 @@ namespace DB { private: }; + /// Helper class for beginning/committing/rolling back transactions in accordance with scope and exceptions. + class DLL_PUBLIC TransactionScope { + public: + /// Create a new helper and associated transaction on the given connection. + TransactionScope(DB::Connection *); + ~TransactionScope(); + + private: + TransactionScope(const TransactionScope &) = delete; + void operator=(const TransactionScope &) = delete; + + Connection * conn; + }; + typedef boost::shared_ptr<Connection> ConnectionPtr; typedef AdHoc::Factory<Connection, std::string> ConnectionFactory; } diff --git a/libdbpp/unittests/testConnection.cpp b/libdbpp/unittests/testConnection.cpp index 159e5a2..76758a7 100644 --- a/libdbpp/unittests/testConnection.cpp +++ b/libdbpp/unittests/testConnection.cpp @@ -12,13 +12,13 @@ // LCOV_EXCL_START class MockDb : public DB::Connection { public: - MockDb(const std::string &) {} + MockDb(const std::string &) : txDepth(0) {} void finish() const {} - int beginTx() const { return 0; } - int commitTx() const { return 0; } - int rollbackTx() const { return 0; } - bool inTx() const { return false; } + int beginTx() const { return ++txDepth; } + int commitTx() const { return --txDepth; } + int rollbackTx() const { return --txDepth; } + bool inTx() const { return txDepth > 0; } void ping() const {} DB::BulkDeleteStyle bulkDeleteStyle() const { return DB::BulkDeleteUsingUsing; } DB::BulkUpdateStyle bulkUpdateStyle() const { return DB::BulkUpdateUsingJoin; } @@ -34,6 +34,7 @@ class MockDb : public DB::Connection { size_t bulkUploadData(const char *, size_t) const {return 0;} mutable std::vector<std::string> executed; + mutable unsigned int txDepth; }; // LCOV_EXCL_STOP @@ -126,6 +127,25 @@ BOOST_AUTO_TEST_CASE( parse2 ) s.close(); } +BOOST_AUTO_TEST_CASE( txscope ) +{ + auto mock = DB::ConnectionFactory::createNew("MockDb", "doesn't matter"); + BOOST_REQUIRE(mock); + BOOST_REQUIRE_EQUAL(false, mock->inTx()); + { + DB::TransactionScope tx(mock); + BOOST_REQUIRE_EQUAL(true, mock->inTx()); + } + BOOST_REQUIRE_EQUAL(false, mock->inTx()); + try { + DB::TransactionScope tx(mock); + BOOST_REQUIRE_EQUAL(true, mock->inTx()); + throw std::exception(); + } + catch (...) { + BOOST_REQUIRE_EQUAL(false, mock->inTx()); + } +} BOOST_AUTO_TEST_CASE( savepoints ) { |