Merge #21540: wallet: refactor: dedup sqlite statement preparations/deletions

ea19cc844e wallet: refactor: dedup sqlite statement deletions (Sebastian Falbesoner)
9a3670930e wallet: refactor: dedup sqlite statement preparations (Sebastian Falbesoner)

Pull request description:

  This refactoring PR deduplicates repeated SQLite statement preparation calls (`sqlite3_prepare_v2(...)`) / deletions (`sqlite3_finalize(...)`) and its surrounding logic by putting each prepared statement and its corresponding text representation into a ~std::map~ ~`std::array`~ `std::vector`. This should be more readable and less error-prone, e.g. in case an additional statement needs to be added in the  future or the error handling has to be adapted.

ACKs for top commit:
  achow101:
    ACK ea19cc844e
  meshcollider:
    utACK ea19cc844e

Tree-SHA512: ced89869b2147e088e7a4cda2acbbdd4a806f66dbc2d6999953d0d702c0655aa53c0eb699cc7e5e3732f2d24206d577a9d9e1b5de7f439100dead2696ade1092
This commit is contained in:
fanquake 2021-04-07 14:09:13 +08:00
commit c0160ea52e
No known key found for this signature in database
GPG key ID: 2EEB9F5CC09526C1

View file

@ -16,6 +16,9 @@
#include <sqlite3.h> #include <sqlite3.h>
#include <stdint.h> #include <stdint.h>
#include <utility>
#include <vector>
static constexpr int32_t WALLET_SCHEMA_VERSION = 0; static constexpr int32_t WALLET_SCHEMA_VERSION = 0;
static Mutex g_sqlite_mutex; static Mutex g_sqlite_mutex;
@ -69,30 +72,21 @@ SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_pa
void SQLiteBatch::SetupSQLStatements() void SQLiteBatch::SetupSQLStatements()
{ {
int res; const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
if (!m_read_stmt) { {&m_read_stmt, "SELECT value FROM main WHERE key = ?"},
if ((res = sqlite3_prepare_v2(m_database.m_db, "SELECT value FROM main WHERE key = ?", -1, &m_read_stmt, nullptr)) != SQLITE_OK) { {&m_insert_stmt, "INSERT INTO main VALUES(?, ?)"},
throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res))); {&m_overwrite_stmt, "INSERT or REPLACE into main values(?, ?)"},
} {&m_delete_stmt, "DELETE FROM main WHERE key = ?"},
} {&m_cursor_stmt, "SELECT key, value FROM main"},
if (!m_insert_stmt) { };
if ((res = sqlite3_prepare_v2(m_database.m_db, "INSERT INTO main VALUES(?, ?)", -1, &m_insert_stmt, nullptr)) != SQLITE_OK) {
throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res))); for (const auto& [stmt_prepared, stmt_text] : statements) {
} if (*stmt_prepared == nullptr) {
} int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, stmt_prepared, nullptr);
if (!m_overwrite_stmt) { if (res != SQLITE_OK) {
if ((res = sqlite3_prepare_v2(m_database.m_db, "INSERT or REPLACE into main values(?, ?)", -1, &m_overwrite_stmt, nullptr)) != SQLITE_OK) { throw std::runtime_error(strprintf(
throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res))); "SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
} }
}
if (!m_delete_stmt) {
if ((res = sqlite3_prepare_v2(m_database.m_db, "DELETE FROM main WHERE key = ?", -1, &m_delete_stmt, nullptr)) != SQLITE_OK) {
throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
}
}
if (!m_cursor_stmt) {
if ((res = sqlite3_prepare_v2(m_database.m_db, "SELECT key, value FROM main", -1, &m_cursor_stmt, nullptr)) != SQLITE_OK) {
throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements : %s\n", sqlite3_errstr(res)));
} }
} }
} }
@ -353,31 +347,22 @@ void SQLiteBatch::Close()
} }
// Free all of the prepared statements // Free all of the prepared statements
int ret = sqlite3_finalize(m_read_stmt); const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
if (ret != SQLITE_OK) { {&m_read_stmt, "read"},
LogPrintf("SQLiteBatch: Batch closed but could not finalize read statement: %s\n", sqlite3_errstr(ret)); {&m_insert_stmt, "insert"},
{&m_overwrite_stmt, "overwrite"},
{&m_delete_stmt, "delete"},
{&m_cursor_stmt, "cursor"},
};
for (const auto& [stmt_prepared, stmt_description] : statements) {
int res = sqlite3_finalize(*stmt_prepared);
if (res != SQLITE_OK) {
LogPrintf("SQLiteBatch: Batch closed but could not finalize %s statement: %s\n",
stmt_description, sqlite3_errstr(res));
}
*stmt_prepared = nullptr;
} }
ret = sqlite3_finalize(m_insert_stmt);
if (ret != SQLITE_OK) {
LogPrintf("SQLiteBatch: Batch closed but could not finalize insert statement: %s\n", sqlite3_errstr(ret));
}
ret = sqlite3_finalize(m_overwrite_stmt);
if (ret != SQLITE_OK) {
LogPrintf("SQLiteBatch: Batch closed but could not finalize overwrite statement: %s\n", sqlite3_errstr(ret));
}
ret = sqlite3_finalize(m_delete_stmt);
if (ret != SQLITE_OK) {
LogPrintf("SQLiteBatch: Batch closed but could not finalize delete statement: %s\n", sqlite3_errstr(ret));
}
ret = sqlite3_finalize(m_cursor_stmt);
if (ret != SQLITE_OK) {
LogPrintf("SQLiteBatch: Batch closed but could not finalize cursor statement: %s\n", sqlite3_errstr(ret));
}
m_read_stmt = nullptr;
m_insert_stmt = nullptr;
m_overwrite_stmt = nullptr;
m_delete_stmt = nullptr;
m_cursor_stmt = nullptr;
} }
bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value) bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value)