mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Bug 796117 - Connecting 3.1 to an existing mysql db drops all data
Provide a backup recovery function that instead of dropping primaries and restoring backups merges the primaries and backups. This should handle a worst-case safe-save failure where the backup tables don't have a complete set of rows for some reason.
This commit is contained in:
parent
f8045b2735
commit
3b3074c28d
@ -53,7 +53,8 @@ enum TableOpType
|
||||
{
|
||||
backup = 0,
|
||||
rollback,
|
||||
drop_backup
|
||||
drop_backup,
|
||||
recover
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -232,7 +232,16 @@ GncDbiSqlConnection::check_and_rollback_failed_save()
|
||||
auto backup_tables = m_provider->get_table_list(m_conn, "%back");
|
||||
if (backup_tables.empty())
|
||||
return true;
|
||||
return table_operation(rollback);
|
||||
auto merge_tables{m_provider->get_table_list(m_conn, "%_merge")};
|
||||
if (!merge_tables.empty())
|
||||
{
|
||||
PERR("Merge tables exist in the database indicating a previous"
|
||||
"attempt to recover from a failed safe-save. Automatic"
|
||||
"recovery is beyond GnuCash's ability, you must recover"
|
||||
"by hand or restore from a good backup.");
|
||||
return false;
|
||||
}
|
||||
return table_operation(recover);
|
||||
}
|
||||
|
||||
GncDbiSqlConnection::~GncDbiSqlConnection()
|
||||
@ -610,6 +619,23 @@ GncDbiSqlConnection::drop_table(const std::string& table)
|
||||
return execute_nonselect_statement(stmt) >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
GncDbiSqlConnection::merge_tables(const std::string& table,
|
||||
const std::string& other)
|
||||
{
|
||||
auto merge_table = table + "_merge";
|
||||
std::string sql = "CREATE TABLE " + merge_table + " AS SELECT * FROM " +
|
||||
table + " UNION SELECT * FROM " + other;
|
||||
auto stmt = create_statement_from_sql(sql);
|
||||
if (execute_nonselect_statement(stmt) < 0)
|
||||
return false;
|
||||
if (!drop_table(table))
|
||||
return false;
|
||||
if (!rename_table(merge_table, table))
|
||||
return false;
|
||||
return drop_table(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a specified SQL operation on every table in a
|
||||
* database. Possible operations are:
|
||||
@ -662,15 +688,15 @@ GncDbiSqlConnection::table_operation(TableOpType op) noexcept
|
||||
return false; /* Error, trigger rollback. */
|
||||
break;
|
||||
case drop_backup:
|
||||
for (auto table : backup_tables)
|
||||
{
|
||||
auto data_table = table.substr(0, table.find("_back"));
|
||||
if (std::find(data_tables.begin(), data_tables.end(),
|
||||
data_table) != data_tables.end())
|
||||
drop_table(table); /* Other table exists, OK. */
|
||||
else /* No data table, restore the backup */
|
||||
rename_table(table, data_table);
|
||||
}
|
||||
for (auto table : backup_tables)
|
||||
{
|
||||
auto data_table = table.substr(0, table.find("_back"));
|
||||
if (std::find(data_tables.begin(), data_tables.end(),
|
||||
data_table) != data_tables.end())
|
||||
drop_table(table); /* Other table exists, OK. */
|
||||
else /* No data table, restore the backup */
|
||||
rename_table(table, data_table);
|
||||
}
|
||||
break;
|
||||
case rollback:
|
||||
for (auto table : backup_tables)
|
||||
@ -682,6 +708,23 @@ GncDbiSqlConnection::table_operation(TableOpType op) noexcept
|
||||
rename_table(table, data_table);
|
||||
}
|
||||
break;
|
||||
case recover:
|
||||
for (auto table : backup_tables)
|
||||
{
|
||||
auto data_table = table.substr(0, table.find("_back"));
|
||||
if (std::find(data_tables.begin(), data_tables.end(),
|
||||
data_table) != data_tables.end())
|
||||
{
|
||||
if (!merge_tables(data_table, table))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rename_table(table, data_table))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ private:
|
||||
void unlock_database();
|
||||
bool rename_table(const std::string& old_name, const std::string& new_name);
|
||||
bool drop_table(const std::string& table);
|
||||
bool merge_tables(const std::string& table, const std::string& other);
|
||||
bool check_and_rollback_failed_save();
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user