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..0d2a16be 100644 --- a/include/sqlpp11/transaction.h +++ b/include/sqlpp11/transaction.h @@ -28,12 +28,21 @@ #define SQLPP_TRANSACTION_H #include +#include 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 +57,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; @@ -88,7 +103,13 @@ namespace sqlpp template transaction_t start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback) { - return {db, report_unfinished_transaction}; + return {db, report_unfinished_transaction}; + } + + 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..91ab34d0 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -28,12 +28,18 @@ #include #include +#include #include #include #include #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 { @@ -244,6 +250,23 @@ struct MockDbT : public sqlpp::connection { return {name}; } + + void start_transaction(sqlpp::isolation_level level) + { + // store temporarily to verify the expected level was used in testcases + _mock_data._last_isolation_level = level; + } + + void rollback_transaction(bool) + {} + + void commit_transaction() + {} + + void report_rollback_failure(std::string) + {} + + InternalMockData _mock_data; }; using MockDb = MockDbT; diff --git a/tests/Select.cpp b/tests/Select.cpp index 81307846..eee074e3 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -207,5 +207,8 @@ int Select(int, char* []) for_each_field(row, to_cerr{}); } + auto transaction = start_transaction(db, sqlpp::isolation_level::read_committed); + std::cout << (db._mock_data._last_isolation_level == sqlpp::isolation_level::read_committed) << std::endl; + return 0; }