diff --git a/include/SQLiteCpp/Transaction.h b/include/SQLiteCpp/Transaction.h index b4392e5..1a19552 100644 --- a/include/SQLiteCpp/Transaction.h +++ b/include/SQLiteCpp/Transaction.h @@ -20,6 +20,16 @@ namespace SQLite // Forward declaration class Database; +/** + * @brief Transaction behaviors when opening an SQLite transaction. + * Names correspond directly to the behavior. + */ +enum class TransactionBehavior { + DEFERRED, + IMMEDIATE, + EXCLUSIVE, +}; + /** * @brief RAII encapsulation of a SQLite Transaction. * @@ -44,7 +54,7 @@ class Transaction { public: /** - * @brief Begins the SQLite transaction + * @brief Begins the SQLite transaction using the default transaction behavior. * * @param[in] aDatabase the SQLite Database Connection * @@ -52,6 +62,16 @@ public: */ explicit Transaction(Database& aDatabase); + /** + * @brief Begins the SQLite transaction with the specified behavior. + * + * @param[in] aDatabase the SQLite Database Connection + * @param[in] behavior the requested transaction behavior + * + * Exception is thrown in case of error, then the Transaction is NOT initiated. + */ + explicit Transaction(Database& aDatabase, TransactionBehavior behavior); + // Transaction is non-copyable Transaction(const Transaction&) = delete; Transaction& operator=(const Transaction&) = delete; diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 6f7d5b0..2a8857a 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -13,13 +13,36 @@ #include #include +#include namespace SQLite { // Begins the SQLite transaction -Transaction::Transaction(Database& aDatabase) : +Transaction::Transaction(Database& aDatabase, TransactionBehavior behavior) : + mDatabase(aDatabase), + mbCommited(false) +{ + const char *stmt; + switch (behavior) { + case TransactionBehavior::DEFERRED: + stmt = "BEGIN DEFERRED"; + break; + case TransactionBehavior::IMMEDIATE: + stmt = "BEGIN IMMEDIATE"; + break; + case TransactionBehavior::EXCLUSIVE: + stmt = "BEGIN EXCLUSIVE"; + break; + default: + throw SQLite::Exception("invalid/unknown transaction behavior", SQLITE_ERROR); + } + mDatabase.exec(stmt); +} + +// Begins the SQLite transaction +Transaction::Transaction(Database &aDatabase) : mDatabase(aDatabase), mbCommited(false) { diff --git a/tests/Transaction_test.cpp b/tests/Transaction_test.cpp index 674d383..9ef4531 100644 --- a/tests/Transaction_test.cpp +++ b/tests/Transaction_test.cpp @@ -42,6 +42,20 @@ TEST(Transaction, commitRollback) EXPECT_THROW(transaction.commit(), SQLite::Exception); } + // ensure transactions with different types are well-formed + { + for (auto behavior : { + SQLite::TransactionBehavior::DEFERRED, + SQLite::TransactionBehavior::IMMEDIATE, + SQLite::TransactionBehavior::EXCLUSIVE }) + { + SQLite::Transaction transaction(db, behavior); + transaction.commit(); + } + + EXPECT_THROW(SQLite::Transaction(db, static_cast(-1)), SQLite::Exception); + } + // Auto rollback if no commit() before the end of scope { // Begin transaction