wallet: Introduce DatabaseCursor RAII class for managing cursor

Instead of having DatabaseBatch deal with opening and closing database
cursors, have a separate RAII class that deals with those.

For now, DatabaseBatch manages DatabaseCursor, but this will change
later.
This commit is contained in:
Andrew Chow
2022-04-11 15:14:24 -04:00
committed by Andrew Chow
parent 69efbc011b
commit 7a198bba0a
6 changed files with 108 additions and 44 deletions

View File

@@ -125,7 +125,6 @@ void SQLiteBatch::SetupSQLStatements()
{&m_insert_stmt, "INSERT INTO main VALUES(?, ?)"},
{&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"},
};
for (const auto& [stmt_prepared, stmt_text] : statements) {
@@ -374,7 +373,6 @@ void SQLiteBatch::Close()
{&m_insert_stmt, "insert"},
{&m_overwrite_stmt, "overwrite"},
{&m_delete_stmt, "delete"},
{&m_cursor_stmt, "cursor"},
};
for (const auto& [stmt_prepared, stmt_description] : statements) {
@@ -472,27 +470,17 @@ bool SQLiteBatch::HasKey(CDataStream&& key)
return res == SQLITE_ROW;
}
bool SQLiteBatch::StartCursor()
{
assert(!m_cursor_init);
if (!m_database.m_db) return false;
m_cursor_init = true;
return true;
}
bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete)
bool SQLiteCursor::Next(CDataStream& key, CDataStream& value, bool& complete)
{
complete = false;
if (!m_cursor_init) return false;
int res = sqlite3_step(m_cursor_stmt);
if (res == SQLITE_DONE) {
complete = true;
return true;
}
if (res != SQLITE_ROW) {
LogPrintf("SQLiteBatch::ReadAtCursor: Unable to execute cursor step: %s\n", sqlite3_errstr(res));
LogPrintf("%s: Unable to execute cursor step: %s\n", __func__, sqlite3_errstr(res));
return false;
}
@@ -506,10 +494,29 @@ bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& compl
return true;
}
void SQLiteBatch::CloseCursor()
SQLiteCursor::~SQLiteCursor()
{
sqlite3_reset(m_cursor_stmt);
m_cursor_init = false;
int res = sqlite3_finalize(m_cursor_stmt);
if (res != SQLITE_OK) {
LogPrintf("%s: cursor closed but could not finalize cursor statement: %s\n",
__func__, sqlite3_errstr(res));
}
}
std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewCursor()
{
if (!m_database.m_db) return nullptr;
auto cursor = std::make_unique<SQLiteCursor>();
const char* stmt_text = "SELECT key, value FROM main";
int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, &cursor->m_cursor_stmt, nullptr);
if (res != SQLITE_OK) {
throw std::runtime_error(strprintf(
"%s: Failed to setup cursor SQL statement: %s\n", __func__, sqlite3_errstr(res)));
}
return cursor;
}
bool SQLiteBatch::TxnBegin()