From f2ea61052e40b46e0e9da60147d43ee0bd46f551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20A=C3=9Fmann?= Date: Tue, 30 May 2017 00:17:08 +0200 Subject: [PATCH 1/5] Add an option to set a transaction isolation level to the generic transaction interface and the connecctor api --- connector_api/connection.h | 3 ++- include/sqlpp11/transaction.h | 31 +++++++++++++++++++++++++++++-- tests/MockDb.h | 17 +++++++++++++++++ tests/Select.cpp | 3 +++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/connector_api/connection.h b/connector_api/connection.h index dc2f81c2..440704ac 100644 --- a/connector_api/connection.h +++ b/connector_api/connection.h @@ -29,6 +29,7 @@ #include #include +#include #include // You may use char result or bind result or both #include // to represent results of select and prepared select @@ -130,7 +131,7 @@ namespace sqlpp } //! start transaction - void start_transaction(); + void start_transaction(isolation_level isolation = isolation_level::undefined); //! commit transaction (or throw transaction if the transaction has been finished already) void commit_transaction(); diff --git a/include/sqlpp11/transaction.h b/include/sqlpp11/transaction.h index 130a664b..317c3483 100644 --- a/include/sqlpp11/transaction.h +++ b/include/sqlpp11/transaction.h @@ -34,6 +34,14 @@ namespace sqlpp static constexpr bool quiet_auto_rollback = false; static constexpr bool report_auto_rollback = true; + enum class isolation_level { + undefined, // use the current database default + serializable, // highest level, stronguest guarantee + repeatable_read, // DBMS holds read and write locks + read_committed, // DMBS holds read locks, non-repeatable reads can occur + read_uncommitted // lowest isolation level, dirty reads may occur + }; + template class transaction_t { @@ -48,6 +56,12 @@ namespace sqlpp _db.start_transaction(); } + transaction_t(Db& db, bool report_unfinished_transaction, isolation_level isolation) + : _db(db), _report_unfinished_transaction(report_unfinished_transaction) + { + _db.start_transaction(isolation); + } + transaction_t(const transaction_t&) = delete; transaction_t(transaction_t&&) = default; transaction_t& operator=(const transaction_t&) = delete; @@ -86,9 +100,22 @@ namespace sqlpp }; template - transaction_t start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback) + transaction_t start_transaction(Db& db, bool report_unfinished_transaction) { - return {db, report_unfinished_transaction}; + return {db, report_unfinished_transaction}; + } + + template + transaction_t start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback, + isolation_level isolation = isolation_level::undefined) + { + return {db, report_unfinished_transaction, isolation}; + } + + template + transaction_t start_transaction(Db& db, isolation_level isolation, bool report_unfinished_transaction = report_auto_rollback) + { + return {db, report_unfinished_transaction, isolation}; } } diff --git a/tests/MockDb.h b/tests/MockDb.h index 6e9dece4..1da2d555 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -244,6 +245,22 @@ struct MockDbT : public sqlpp::connection { return {name}; } + + void start_transaction(sqlpp::isolation_level level) + { + _current_isolation_level = level; + } + + void rollback_transaction(bool) + {} + + void commit_transaction() + {} + + void report_rollback_failure(std::string) + {} + + sqlpp::isolation_level _current_isolation_level; }; using MockDb = MockDbT; diff --git a/tests/Select.cpp b/tests/Select.cpp index 268488f2..da5a63eb 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -183,5 +183,8 @@ int Select(int, char* []) for_each_field(row, to_cerr{}); } + auto transaction = start_transaction(db, sqlpp::report_auto_rollback, sqlpp::isolation_level::read_committed); + std::cout << (db._current_isolation_level == sqlpp::isolation_level::read_committed) << std::endl; + return 0; } From c92571862d7966ae84d0a094cb554f501b268edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20A=C3=9Fmann?= Date: Thu, 1 Jun 2017 12:47:14 +0200 Subject: [PATCH 2/5] Replace "not" with "!" to fix Visual C++ issue --- include/sqlpp11/transaction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sqlpp11/transaction.h b/include/sqlpp11/transaction.h index 317c3483..0ca3073f 100644 --- a/include/sqlpp11/transaction.h +++ b/include/sqlpp11/transaction.h @@ -69,7 +69,7 @@ namespace sqlpp ~transaction_t() { - if (not _finished) + if (!_finished) { try { From b51714eb48b7412f0d89aa38aa35212e5bfda0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20A=C3=9Fmann?= Date: Thu, 1 Jun 2017 23:18:15 +0200 Subject: [PATCH 3/5] Cleaned up start_transaction overloads --- include/sqlpp11/transaction.h | 9 +-------- tests/Select.cpp | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/include/sqlpp11/transaction.h b/include/sqlpp11/transaction.h index 0ca3073f..30580a26 100644 --- a/include/sqlpp11/transaction.h +++ b/include/sqlpp11/transaction.h @@ -100,18 +100,11 @@ namespace sqlpp }; template - transaction_t start_transaction(Db& db, bool report_unfinished_transaction) + transaction_t start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback) { return {db, report_unfinished_transaction}; } - template - transaction_t start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback, - isolation_level isolation = isolation_level::undefined) - { - return {db, report_unfinished_transaction, isolation}; - } - template transaction_t start_transaction(Db& db, isolation_level isolation, bool report_unfinished_transaction = report_auto_rollback) { diff --git a/tests/Select.cpp b/tests/Select.cpp index da5a63eb..78b1daca 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -183,7 +183,7 @@ int Select(int, char* []) for_each_field(row, to_cerr{}); } - auto transaction = start_transaction(db, sqlpp::report_auto_rollback, sqlpp::isolation_level::read_committed); + auto transaction = start_transaction(db, sqlpp::isolation_level::read_committed); std::cout << (db._current_isolation_level == sqlpp::isolation_level::read_committed) << std::endl; return 0; From ee20a8be6759f03ab537cfa5484dd6726ab0800f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20A=C3=9Fmann?= Date: Thu, 1 Jun 2017 23:26:07 +0200 Subject: [PATCH 4/5] Fix missing `not` correctly by including ciso646 --- include/sqlpp11/transaction.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/transaction.h b/include/sqlpp11/transaction.h index 30580a26..0d2a16be 100644 --- a/include/sqlpp11/transaction.h +++ b/include/sqlpp11/transaction.h @@ -28,6 +28,7 @@ #define SQLPP_TRANSACTION_H #include +#include namespace sqlpp { @@ -69,7 +70,7 @@ namespace sqlpp ~transaction_t() { - if (!_finished) + if (not _finished) { try { From 9413206bd1f4d9b0c7543ebb2eb1bb469303a32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20A=C3=9Fmann?= Date: Sat, 3 Jun 2017 11:20:18 +0200 Subject: [PATCH 5/5] Hide the "isolation_level" member of the MockDb to make it explicit that this is only used for mock validation --- tests/MockDb.h | 10 ++++++++-- tests/Select.cpp | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/MockDb.h b/tests/MockDb.h index 1da2d555..91ab34d0 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -35,6 +35,11 @@ #include #include +// an object to store internal Mock flags and values to validate in tests +struct InternalMockData { + sqlpp::isolation_level _last_isolation_level; +}; + template struct MockDbT : public sqlpp::connection { @@ -248,7 +253,8 @@ struct MockDbT : public sqlpp::connection void start_transaction(sqlpp::isolation_level level) { - _current_isolation_level = level; + // store temporarily to verify the expected level was used in testcases + _mock_data._last_isolation_level = level; } void rollback_transaction(bool) @@ -260,7 +266,7 @@ struct MockDbT : public sqlpp::connection void report_rollback_failure(std::string) {} - sqlpp::isolation_level _current_isolation_level; + InternalMockData _mock_data; }; using MockDb = MockDbT; diff --git a/tests/Select.cpp b/tests/Select.cpp index 78b1daca..b475b642 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -184,7 +184,7 @@ int Select(int, char* []) } auto transaction = start_transaction(db, sqlpp::isolation_level::read_committed); - std::cout << (db._current_isolation_level == sqlpp::isolation_level::read_committed) << std::endl; + std::cout << (db._mock_data._last_isolation_level == sqlpp::isolation_level::read_committed) << std::endl; return 0; }