mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Add SAVEPOINT support to enable nested gnc_dbi_transaction calls.
This commit is contained in:
parent
9f0b086546
commit
2a2369b297
@ -31,6 +31,7 @@ extern "C"
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
#include "gnc-dbisqlconnection.hpp"
|
||||
|
||||
@ -86,7 +87,7 @@ GncDbiSqlConnection::GncDbiSqlConnection (DbType type, QofBackend* qbe,
|
||||
make_dbi_provider<DbType::DBI_MYSQL>() :
|
||||
make_dbi_provider<DbType::DBI_PGSQL>()},
|
||||
m_conn_ok{true}, m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0},
|
||||
m_retry{false}
|
||||
m_retry{false}, m_sql_savepoint{0}
|
||||
{
|
||||
if (!lock_database(ignore_lock))
|
||||
throw std::runtime_error("Failed to lock database!");
|
||||
@ -185,7 +186,7 @@ GncDbiSqlConnection::unlock_database ()
|
||||
"SELECT * FROM %s WHERE Hostname = '%s' "
|
||||
"AND PID = '%d'", lock_table.c_str(),
|
||||
hostname,
|
||||
(int)GETPID ());
|
||||
(int)GETPID ());
|
||||
if (result && dbi_result_get_numrows (result))
|
||||
{
|
||||
if (result)
|
||||
@ -303,75 +304,104 @@ GncDbiSqlConnection::begin_transaction () noexcept
|
||||
{
|
||||
PERR ("gnc_dbi_verify_conn() failed\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
init_error ();
|
||||
result = dbi_conn_queryf (m_conn, "BEGIN");
|
||||
if (m_sql_savepoint == 0)
|
||||
result = dbi_conn_queryf (m_conn, "BEGIN");
|
||||
else
|
||||
{
|
||||
std::ostringstream savepoint("savepoint_");
|
||||
savepoint << m_sql_savepoint;
|
||||
result = dbi_conn_queryf(m_conn, "SAVEPOINT %s",
|
||||
savepoint.str().c_str());
|
||||
}
|
||||
}
|
||||
while (m_retry);
|
||||
|
||||
auto success = (result != nullptr);
|
||||
auto status = dbi_result_free (result);
|
||||
if (status < 0)
|
||||
{
|
||||
PERR ("Error in dbi_result_free() result\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
}
|
||||
if (!success)
|
||||
if (!result)
|
||||
{
|
||||
PERR ("BEGIN transaction failed()\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
GncDbiSqlConnection::rollback_transaction () const noexcept
|
||||
{
|
||||
DEBUG ("ROLLBACK\n");
|
||||
const char* command = "ROLLBACK";
|
||||
auto result = dbi_conn_query (m_conn, command);
|
||||
auto success = (result != nullptr);
|
||||
|
||||
auto status = dbi_result_free (result);
|
||||
if (status < 0)
|
||||
if (dbi_result_free (result) < 0)
|
||||
{
|
||||
PERR ("Error in dbi_result_free() result\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
return false;
|
||||
}
|
||||
if (!success)
|
||||
++m_sql_savepoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GncDbiSqlConnection::rollback_transaction () noexcept
|
||||
{
|
||||
DEBUG ("ROLLBACK\n");
|
||||
if (m_sql_savepoint == 0) return false;
|
||||
dbi_result result;
|
||||
if (m_sql_savepoint == 1)
|
||||
result = dbi_conn_query (m_conn, "ROLLBACK");
|
||||
else
|
||||
{
|
||||
std::ostringstream savepoint("savepoint_");
|
||||
savepoint << m_sql_savepoint;
|
||||
result = dbi_conn_queryf(m_conn, "ROLLBACK TO SAVEPOINT %s",
|
||||
savepoint.str().c_str());
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
PERR ("Error in conn_rollback_transaction()\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
GncDbiSqlConnection::commit_transaction () const noexcept
|
||||
{
|
||||
DEBUG ("COMMIT\n");
|
||||
auto result = dbi_conn_queryf (m_conn, "COMMIT");
|
||||
auto success = (result != nullptr);
|
||||
|
||||
auto status = dbi_result_free (result);
|
||||
if (status < 0)
|
||||
if (dbi_result_free (result) < 0)
|
||||
{
|
||||
PERR ("Error in dbi_result_free() result\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
return false;
|
||||
}
|
||||
if (!success)
|
||||
|
||||
--m_sql_savepoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GncDbiSqlConnection::commit_transaction () noexcept
|
||||
{
|
||||
DEBUG ("COMMIT\n");
|
||||
if (m_sql_savepoint == 0) return false;
|
||||
dbi_result result;
|
||||
if (m_sql_savepoint == 1)
|
||||
result = dbi_conn_queryf (m_conn, "COMMIT");
|
||||
else
|
||||
{
|
||||
std::ostringstream savepoint("savepoint_");
|
||||
savepoint << m_sql_savepoint;
|
||||
result = dbi_conn_queryf(m_conn, "RELEASE SAVEPOINT %s",
|
||||
savepoint.str().c_str());
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
PERR ("Error in conn_commit_transaction()\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
if (dbi_result_free (result) < 0)
|
||||
{
|
||||
PERR ("Error in dbi_result_free() result\n");
|
||||
qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR);
|
||||
return false;
|
||||
}
|
||||
--m_sql_savepoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,8 +52,8 @@ public:
|
||||
const noexcept override;
|
||||
bool does_table_exist (const std::string&) const noexcept override;
|
||||
bool begin_transaction () noexcept override;
|
||||
bool rollback_transaction () const noexcept override;
|
||||
bool commit_transaction () const noexcept override;
|
||||
bool rollback_transaction () noexcept override;
|
||||
bool commit_transaction () noexcept override;
|
||||
bool create_table (const std::string&, const ColVec&) const noexcept override;
|
||||
bool create_index (const std::string&, const std::string&, const EntryVec&)
|
||||
const noexcept override;
|
||||
@ -65,7 +65,7 @@ public:
|
||||
QofBackend* qbe () const noexcept { return m_qbe; }
|
||||
dbi_conn conn() const noexcept { return m_conn; }
|
||||
inline void set_error(int error, unsigned int repeat,
|
||||
bool retry) noexcept override
|
||||
bool retry) noexcept override
|
||||
{
|
||||
m_last_error = error;
|
||||
m_error_repeat = repeat;
|
||||
@ -103,10 +103,11 @@ private:
|
||||
*/
|
||||
unsigned int m_error_repeat;
|
||||
/** Signals the calling function that it should retry (the error handler
|
||||
* detected transient error and managed to resolve it, but it can't run the
|
||||
* original query)
|
||||
* detected a transient error and managed to resolve it, but it can't run
|
||||
* the original query)
|
||||
*/
|
||||
gboolean m_retry;
|
||||
bool m_retry;
|
||||
unsigned int m_sql_savepoint;
|
||||
bool lock_database(bool ignore_lock);
|
||||
void unlock_database();
|
||||
|
||||
|
@ -75,9 +75,9 @@ public:
|
||||
/** Returns TRUE if successful, false if error */
|
||||
virtual bool begin_transaction () noexcept = 0;
|
||||
/** Returns TRUE if successful, FALSE if error */
|
||||
virtual bool rollback_transaction () const noexcept = 0;
|
||||
virtual bool rollback_transaction () noexcept = 0;
|
||||
/** Returns TRUE if successful, FALSE if error */
|
||||
virtual bool commit_transaction () const noexcept = 0;
|
||||
virtual bool commit_transaction () noexcept = 0;
|
||||
/** Returns TRUE if successful, FALSE if error */
|
||||
virtual bool create_table (const std::string&, const ColVec&)
|
||||
const noexcept = 0;
|
||||
|
@ -107,8 +107,8 @@ public:
|
||||
bool does_table_exist (const std::string&) const noexcept override {
|
||||
return true; }
|
||||
bool begin_transaction () noexcept override { return true;}
|
||||
bool rollback_transaction () const noexcept override { return true; }
|
||||
bool commit_transaction () const noexcept override { return true; }
|
||||
bool rollback_transaction () noexcept override { return true; }
|
||||
bool commit_transaction () noexcept override { return true; }
|
||||
bool create_table (const std::string&, const ColVec&)
|
||||
const noexcept override { return false; }
|
||||
bool create_index (const std::string&, const std::string&,
|
||||
|
Loading…
Reference in New Issue
Block a user