mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-26 14:59:16 +02:00
Merge bitcoin/bitcoin#26690: wallet: Refactor database cursor into its own object with proper return codes
4aebd832a4db: Change DatabaseCursor::Next to return status enum (Andrew Chow)d79e8dcf29wallet: Have cursor users use DatabaseCursor directly (Andrew Chow)7a198bba0awallet: Introduce DatabaseCursor RAII class for managing cursor (Andrew Chow)69efbc011bMove SafeDbt out of BerkeleyBatch (Andrew Chow) Pull request description: Instead of having database cursors be tied to a particular `DatabaseBatch` object and requiring its setup and teardown be separate functions in that batch, we can have cursors be separate RAII classes. This makes it easier to create and destroy cursors as well as having cursors that have slightly different behaviors. Additionally, since reading data from a cursor is a tri-state, this PR changes the return value of the `Next` function (formerly `ReadAtCursor`) to return an Enum rather than the current system of 2 booleans. This greatly simplifies and unifies the code that deals with cursors as now there is no confusion as to what the function returns when there are no records left to be read. Extracted from #24914 ACKs for top commit: furszy: diff ACK4aebd83theStack: Code-review ACK4aebd832a4Tree-SHA512: 5d0be56a18de5b08c777dd5a73ba5a6ef1e696fdb07d1dca952a88ded07887b7c5c04342f9a76feb2f6fe24a45dc31f094f1f5d9500e6bdf4a44f4edb66dcaa1
This commit is contained in:
@@ -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,28 +470,15 @@ bool SQLiteBatch::HasKey(CDataStream&& key)
|
||||
return res == SQLITE_ROW;
|
||||
}
|
||||
|
||||
bool SQLiteBatch::StartCursor()
|
||||
DatabaseCursor::Status SQLiteCursor::Next(CDataStream& key, CDataStream& value)
|
||||
{
|
||||
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)
|
||||
{
|
||||
complete = false;
|
||||
|
||||
if (!m_cursor_init) return false;
|
||||
|
||||
int res = sqlite3_step(m_cursor_stmt);
|
||||
if (res == SQLITE_DONE) {
|
||||
complete = true;
|
||||
return true;
|
||||
return Status::DONE;
|
||||
}
|
||||
if (res != SQLITE_ROW) {
|
||||
LogPrintf("SQLiteBatch::ReadAtCursor: Unable to execute cursor step: %s\n", sqlite3_errstr(res));
|
||||
return false;
|
||||
LogPrintf("%s: Unable to execute cursor step: %s\n", __func__, sqlite3_errstr(res));
|
||||
return Status::FAIL;
|
||||
}
|
||||
|
||||
// Leftmost column in result is index 0
|
||||
@@ -503,13 +488,32 @@ bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& compl
|
||||
const std::byte* value_data{AsBytePtr(sqlite3_column_blob(m_cursor_stmt, 1))};
|
||||
size_t value_data_size(sqlite3_column_bytes(m_cursor_stmt, 1));
|
||||
value.write({value_data, value_data_size});
|
||||
return true;
|
||||
return Status::MORE;
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user