mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 04:47:18 +08:00
Add is_transaction_active() to all connectors (#550)
* Document the connector API method is_transaction_active() * Move mysql::connection_base::is_transaction_active() to the other transaction-handling methods. * Add more tests for mysql::connection::is_transaction_active() * Add postgresql::connection_base::is_transaction_active() * Add tests for postgresql::connection_base::is_transaction_active() * Change the type of the SQLite3 transaction status from transaction_status_type to a boolean flag. * Add sqlite3::connection_base::is_transaction_active() * Add tests for sqlite3::connection_base::is_transaction_active() * When closing a transaction do it in the following order: report (if any), execute SQL command, set transaction active flag to false.
This commit is contained in:
parent
3474a4fa5d
commit
9b49afa306
@ -180,7 +180,6 @@ namespace sqlpp
|
|||||||
return t._prepare(*this);
|
return t._prepare(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! set the transaction isolation level for the current connection
|
//! set the transaction isolation level for the current connection
|
||||||
/// time of effect is connector-specific, for most is will only affect new transactions
|
/// time of effect is connector-specific, for most is will only affect new transactions
|
||||||
void set_default_isolation_level(sqlpp::isolation_level);
|
void set_default_isolation_level(sqlpp::isolation_level);
|
||||||
@ -204,6 +203,9 @@ namespace sqlpp
|
|||||||
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
|
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
|
||||||
void report_rollback_failure(const std::string message) noexcept;
|
void report_rollback_failure(const std::string message) noexcept;
|
||||||
|
|
||||||
|
//! check if transaction is active
|
||||||
|
bool is_transaction_active();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Low-level connection handle
|
// Low-level connection handle
|
||||||
_handle_ptr_t _handle;
|
_handle_ptr_t _handle;
|
||||||
|
@ -291,11 +291,6 @@ namespace sqlpp
|
|||||||
return _handle->config;
|
return _handle->config;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_transaction_active()
|
|
||||||
{
|
|
||||||
return _transaction_active;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Select>
|
template <typename Select>
|
||||||
char_result_t select(const Select& s)
|
char_result_t select(const Select& s)
|
||||||
{
|
{
|
||||||
@ -462,8 +457,8 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
throw sqlpp::exception{"MySQL: Cannot commit a finished or failed transaction"};
|
throw sqlpp::exception{"MySQL: Cannot commit a finished or failed transaction"};
|
||||||
}
|
}
|
||||||
_transaction_active = false;
|
|
||||||
execute_statement(_handle, "COMMIT");
|
execute_statement(_handle, "COMMIT");
|
||||||
|
_transaction_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! rollback transaction (or throw if the transaction has been finished already)
|
//! rollback transaction (or throw if the transaction has been finished already)
|
||||||
@ -477,8 +472,8 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
std::cerr << "MySQL warning: Rolling back unfinished transaction" << std::endl;
|
std::cerr << "MySQL warning: Rolling back unfinished transaction" << std::endl;
|
||||||
}
|
}
|
||||||
_transaction_active = false;
|
|
||||||
execute_statement(_handle, "ROLLBACK");
|
execute_statement(_handle, "ROLLBACK");
|
||||||
|
_transaction_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
|
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
|
||||||
@ -487,6 +482,12 @@ namespace sqlpp
|
|||||||
std::cerr << "MySQL message:" << message << std::endl;
|
std::cerr << "MySQL message:" << message << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! check if transaction is active
|
||||||
|
bool is_transaction_active()
|
||||||
|
{
|
||||||
|
return _transaction_active;
|
||||||
|
}
|
||||||
|
|
||||||
MYSQL* native_handle()
|
MYSQL* native_handle()
|
||||||
{
|
{
|
||||||
return _handle->native_handle();
|
return _handle->native_handle();
|
||||||
|
@ -542,9 +542,8 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
throw sqlpp::exception{"PostgreSQL error: transaction failed or finished."};
|
throw sqlpp::exception{"PostgreSQL error: transaction failed or finished."};
|
||||||
}
|
}
|
||||||
|
|
||||||
_transaction_active = false;
|
|
||||||
execute("COMMIT");
|
execute("COMMIT");
|
||||||
|
_transaction_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! rollback transaction
|
//! rollback transaction
|
||||||
@ -554,12 +553,11 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
throw sqlpp::exception{"PostgreSQL error: transaction failed or finished."};
|
throw sqlpp::exception{"PostgreSQL error: transaction failed or finished."};
|
||||||
}
|
}
|
||||||
execute("ROLLBACK");
|
|
||||||
if (report)
|
if (report)
|
||||||
{
|
{
|
||||||
std::cerr << "PostgreSQL warning: rolling back unfinished transaction" << std::endl;
|
std::cerr << "PostgreSQL warning: rolling back unfinished transaction" << std::endl;
|
||||||
}
|
}
|
||||||
|
execute("ROLLBACK");
|
||||||
_transaction_active = false;
|
_transaction_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,6 +567,12 @@ namespace sqlpp
|
|||||||
std::cerr << "PostgreSQL error: " << message << std::endl;
|
std::cerr << "PostgreSQL error: " << message << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! check if transaction is active
|
||||||
|
bool is_transaction_active()
|
||||||
|
{
|
||||||
|
return _transaction_active;
|
||||||
|
}
|
||||||
|
|
||||||
//! get the last inserted id for a certain table
|
//! get the last inserted id for a certain table
|
||||||
uint64_t last_insert_id(const std::string& table, const std::string& fieldname)
|
uint64_t last_insert_id(const std::string& table, const std::string& fieldname)
|
||||||
{
|
{
|
||||||
|
@ -146,14 +146,7 @@ namespace sqlpp
|
|||||||
class SQLPP11_SQLITE3_EXPORT connection_base : public sqlpp::connection
|
class SQLPP11_SQLITE3_EXPORT connection_base : public sqlpp::connection
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
enum class transaction_status_type
|
bool _transaction_active{false};
|
||||||
{
|
|
||||||
none,
|
|
||||||
maybe,
|
|
||||||
active
|
|
||||||
};
|
|
||||||
|
|
||||||
transaction_status_type _transaction_status{transaction_status_type::none};
|
|
||||||
|
|
||||||
// direct execution
|
// direct execution
|
||||||
bind_result_t select_impl(const std::string& statement)
|
bind_result_t select_impl(const std::string& statement)
|
||||||
@ -470,35 +463,33 @@ namespace sqlpp
|
|||||||
//! start transaction
|
//! start transaction
|
||||||
void start_transaction()
|
void start_transaction()
|
||||||
{
|
{
|
||||||
if (_transaction_status == transaction_status_type::active)
|
if (_transaction_active)
|
||||||
{
|
{
|
||||||
throw sqlpp::exception{"Sqlite3 error: Cannot have more than one open transaction per connection"};
|
throw sqlpp::exception{"Sqlite3 error: Cannot have more than one open transaction per connection"};
|
||||||
}
|
}
|
||||||
|
|
||||||
_transaction_status = transaction_status_type::maybe;
|
|
||||||
auto prepared = prepare_statement(_handle, "BEGIN");
|
auto prepared = prepare_statement(_handle, "BEGIN");
|
||||||
execute_statement(_handle, prepared);
|
execute_statement(_handle, prepared);
|
||||||
_transaction_status = transaction_status_type::active;
|
_transaction_active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! commit transaction (or throw if the transaction has been finished already)
|
//! commit transaction (or throw if the transaction has been finished already)
|
||||||
void commit_transaction()
|
void commit_transaction()
|
||||||
{
|
{
|
||||||
if (_transaction_status == transaction_status_type::none)
|
if (!_transaction_active)
|
||||||
{
|
{
|
||||||
throw sqlpp::exception{"Sqlite3 error: Cannot commit a finished or failed transaction"};
|
throw sqlpp::exception{"Sqlite3 error: Cannot commit a finished or failed transaction"};
|
||||||
}
|
}
|
||||||
_transaction_status = transaction_status_type::maybe;
|
|
||||||
auto prepared = prepare_statement(_handle, "COMMIT");
|
auto prepared = prepare_statement(_handle, "COMMIT");
|
||||||
execute_statement(_handle, prepared);
|
execute_statement(_handle, prepared);
|
||||||
_transaction_status = transaction_status_type::none;
|
_transaction_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! rollback transaction with or without reporting the rollback (or throw if the transaction has been finished
|
//! rollback transaction with or without reporting the rollback (or throw if the transaction has been finished
|
||||||
// already)
|
// already)
|
||||||
void rollback_transaction(bool report)
|
void rollback_transaction(bool report)
|
||||||
{
|
{
|
||||||
if (_transaction_status == transaction_status_type::none)
|
if (!_transaction_active)
|
||||||
{
|
{
|
||||||
throw sqlpp::exception{"Sqlite3 error: Cannot rollback a finished or failed transaction"};
|
throw sqlpp::exception{"Sqlite3 error: Cannot rollback a finished or failed transaction"};
|
||||||
}
|
}
|
||||||
@ -506,10 +497,9 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
std::cerr << "Sqlite3 warning: Rolling back unfinished transaction" << std::endl;
|
std::cerr << "Sqlite3 warning: Rolling back unfinished transaction" << std::endl;
|
||||||
}
|
}
|
||||||
_transaction_status = transaction_status_type::maybe;
|
|
||||||
auto prepared = prepare_statement(_handle, "ROLLBACK");
|
auto prepared = prepare_statement(_handle, "ROLLBACK");
|
||||||
execute_statement(_handle, prepared);
|
execute_statement(_handle, prepared);
|
||||||
_transaction_status = transaction_status_type::none;
|
_transaction_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
|
//! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor)
|
||||||
@ -518,6 +508,12 @@ namespace sqlpp
|
|||||||
std::cerr << "Sqlite3 message:" << message << std::endl;
|
std::cerr << "Sqlite3 message:" << message << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! check if transaction is active
|
||||||
|
bool is_transaction_active()
|
||||||
|
{
|
||||||
|
return _transaction_active;
|
||||||
|
}
|
||||||
|
|
||||||
//! get the last inserted id
|
//! get the last inserted id
|
||||||
uint64_t last_insert_id() noexcept
|
uint64_t last_insert_id() noexcept
|
||||||
{
|
{
|
||||||
|
@ -55,6 +55,7 @@ int MoveConstructor(int, char*[])
|
|||||||
gamma bool DEFAULT NULL
|
gamma bool DEFAULT NULL
|
||||||
))");
|
))");
|
||||||
|
|
||||||
|
assert(connections.at(0).is_transaction_active() == false);
|
||||||
connections.at(0).start_transaction();
|
connections.at(0).start_transaction();
|
||||||
auto db = std::move(connections.at(0));
|
auto db = std::move(connections.at(0));
|
||||||
assert(db.is_transaction_active());
|
assert(db.is_transaction_active());
|
||||||
@ -74,6 +75,7 @@ int MoveConstructor(int, char*[])
|
|||||||
std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.at("beta") << std::endl;
|
std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.at("beta") << std::endl;
|
||||||
};
|
};
|
||||||
db.commit_transaction();
|
db.commit_transaction();
|
||||||
|
assert(db.is_transaction_active() == false);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -94,6 +94,7 @@ int Transaction(int, char*[])
|
|||||||
{
|
{
|
||||||
|
|
||||||
{
|
{
|
||||||
|
require_equal(__LINE__, db.is_transaction_active(), false);
|
||||||
auto current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
|
auto current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
|
||||||
.with_result_type_of(select(sqlpp::value("").as(level))))
|
.with_result_type_of(select(sqlpp::value("").as(level))))
|
||||||
.front()
|
.front()
|
||||||
@ -102,14 +103,16 @@ int Transaction(int, char*[])
|
|||||||
std::cerr << "isolation level outside transaction: " << current_level << "\n";
|
std::cerr << "isolation level outside transaction: " << current_level << "\n";
|
||||||
|
|
||||||
auto tx = start_transaction(db, sqlpp::isolation_level::serializable);
|
auto tx = start_transaction(db, sqlpp::isolation_level::serializable);
|
||||||
|
require_equal(__LINE__, db.is_transaction_active(), true);
|
||||||
current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
|
current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
|
||||||
.with_result_type_of(select(sqlpp::value("").as(level))))
|
.with_result_type_of(select(sqlpp::value("").as(level))))
|
||||||
.front()
|
.front()
|
||||||
.level;
|
.level;
|
||||||
require_equal(__LINE__, current_level, "serializable");
|
require_equal(__LINE__, current_level, "serializable");
|
||||||
std::cerr << "isolation level in transaction(serializable) : " << current_level << "\n";
|
std::cerr << "isolation level in transaction(serializable) : " << current_level << "\n";
|
||||||
|
|
||||||
tx.commit();
|
tx.commit();
|
||||||
|
require_equal(__LINE__, db.is_transaction_active(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_equal(__LINE__, db.get_default_isolation_level(), sqlpp::isolation_level::read_committed);
|
require_equal(__LINE__, db.get_default_isolation_level(), sqlpp::isolation_level::read_committed);
|
||||||
|
@ -53,6 +53,8 @@ int Transaction(int, char*[])
|
|||||||
|
|
||||||
std::cerr << "--------------------------------------" << std::endl;
|
std::cerr << "--------------------------------------" << std::endl;
|
||||||
|
|
||||||
|
assert(db.is_transaction_active() == false);
|
||||||
|
|
||||||
auto current_level = db.get_default_isolation_level();
|
auto current_level = db.get_default_isolation_level();
|
||||||
std::cout << "Expecting default isolation level = 1, is " << static_cast<int>(current_level) << std::endl;
|
std::cout << "Expecting default isolation level = 1, is " << static_cast<int>(current_level) << std::endl;
|
||||||
assert(current_level == sqlpp::isolation_level::serializable);
|
assert(current_level == sqlpp::isolation_level::serializable);
|
||||||
@ -66,6 +68,7 @@ int Transaction(int, char*[])
|
|||||||
std::cerr << "Expecting read_uncommitted = 0, is: " << pragmaValue << std::endl;
|
std::cerr << "Expecting read_uncommitted = 0, is: " << pragmaValue << std::endl;
|
||||||
db.set_default_isolation_level(sqlpp::isolation_level::read_uncommitted);
|
db.set_default_isolation_level(sqlpp::isolation_level::read_uncommitted);
|
||||||
auto tx = start_transaction(db);
|
auto tx = start_transaction(db);
|
||||||
|
assert(db.is_transaction_active());
|
||||||
pragmaValue = db(custom_query(sqlpp::verbatim("PRAGMA read_uncommitted"))
|
pragmaValue = db(custom_query(sqlpp::verbatim("PRAGMA read_uncommitted"))
|
||||||
.with_result_type_of(select(sqlpp::value(1).as(pragma))))
|
.with_result_type_of(select(sqlpp::value(1).as(pragma))))
|
||||||
.front()
|
.front()
|
||||||
@ -78,6 +81,7 @@ int Transaction(int, char*[])
|
|||||||
assert(current_level == sqlpp::isolation_level::read_uncommitted);
|
assert(current_level == sqlpp::isolation_level::read_uncommitted);
|
||||||
|
|
||||||
tx.commit();
|
tx.commit();
|
||||||
|
assert(db.is_transaction_active() == false);
|
||||||
std::cerr << "--------------------------------------" << std::endl;
|
std::cerr << "--------------------------------------" << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user