LCOV - code coverage report
Current view: top level - src/wallet - sqlite.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 297 374 79.4 %
Date: 2026-06-25 07:23:43 Functions: 35 36 97.2 %

          Line data    Source code
       1             : // Copyright (c) 2020-2021 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <wallet/sqlite.h>
       6             : 
       7             : #include <chainparams.h>
       8             : #include <crypto/common.h>
       9             : #include <logging.h>
      10             : #include <sync.h>
      11             : #include <util/strencodings.h>
      12             : #include <util/system.h>
      13             : #include <util/translation.h>
      14             : #include <wallet/db.h>
      15             : 
      16             : #include <sqlite3.h>
      17             : #include <stdint.h>
      18             : 
      19             : #include <optional>
      20             : #include <utility>
      21             : #include <vector>
      22             : 
      23             : namespace wallet {
      24             : static constexpr int32_t WALLET_SCHEMA_VERSION = 0;
      25             : 
      26       68636 : static Span<const std::byte> SpanFromBlob(sqlite3_stmt* stmt, int col)
      27             : {
      28      137272 :     return {reinterpret_cast<const std::byte*>(sqlite3_column_blob(stmt, col)),
      29       68636 :             static_cast<size_t>(sqlite3_column_bytes(stmt, col))};
      30             : }
      31             : 
      32          12 : static void ErrorLogCallback(void* arg, int code, const char* msg)
      33             : {
      34             :     // From sqlite3_config() documentation for the SQLITE_CONFIG_LOG option:
      35             :     // "The void pointer that is the second argument to SQLITE_CONFIG_LOG is passed through as
      36             :     // the first parameter to the application-defined logger function whenever that function is
      37             :     // invoked."
      38             :     // Assert that this is the case:
      39          12 :     assert(arg == nullptr);
      40          12 :     LogPrintf("SQLite Error. Code: %d. Message: %s\n", code, msg);
      41          12 : }
      42             : 
      43      251212 : static int TraceSqlCallback(unsigned code, void* context, void* param1, void* param2)
      44             : {
      45      251212 :     auto* db = static_cast<SQLiteDatabase*>(context);
      46      251212 :     if (code == SQLITE_TRACE_STMT) {
      47      251212 :         auto* stmt = static_cast<sqlite3_stmt*>(param1);
      48             :         // To be conservative and avoid leaking potentially secret information
      49             :         // in the log file, only expand statements that query the database, not
      50             :         // statements that update the database.
      51      251212 :         char* expanded{sqlite3_stmt_readonly(stmt) ? sqlite3_expanded_sql(stmt) : nullptr};
      52      251212 :         LogPrintf("[%s] SQLite Statement: %s\n", db->Filename(), expanded ? expanded : sqlite3_sql(stmt));
      53      251212 :         if (expanded) sqlite3_free(expanded);
      54      251212 :     }
      55      251212 :     return SQLITE_OK;
      56           0 : }
      57             : 
      58      460516 : static bool BindBlobToStatement(sqlite3_stmt* stmt,
      59             :                                 int index,
      60             :                                 Span<const std::byte> blob,
      61             :                                 const std::string& description)
      62             : {
      63      460516 :     int res = sqlite3_bind_blob(stmt, index, blob.data(), blob.size(), SQLITE_STATIC);
      64      460516 :     if (res != SQLITE_OK) {
      65           0 :         LogPrintf("Unable to bind %s to statement: %s\n", description, sqlite3_errstr(res));
      66           0 :         sqlite3_clear_bindings(stmt);
      67           0 :         sqlite3_reset(stmt);
      68           0 :         return false;
      69             :     }
      70             : 
      71      460516 :     return true;
      72      460516 : }
      73             : 
      74        1692 : static std::optional<int> ReadPragmaInteger(sqlite3* db, const std::string& key, const std::string& description, bilingual_str& error)
      75             : {
      76        1692 :     std::string stmt_text = strprintf("PRAGMA %s", key);
      77        1692 :     sqlite3_stmt* pragma_read_stmt{nullptr};
      78        1692 :     int ret = sqlite3_prepare_v2(db, stmt_text.c_str(), -1, &pragma_read_stmt, nullptr);
      79        1692 :     if (ret != SQLITE_OK) {
      80           0 :         sqlite3_finalize(pragma_read_stmt);
      81           0 :         error = Untranslated(strprintf("SQLiteDatabase: Failed to prepare the statement to fetch %s: %s", description, sqlite3_errstr(ret)));
      82           0 :         return std::nullopt;
      83             :     }
      84        1692 :     ret = sqlite3_step(pragma_read_stmt);
      85        1692 :     if (ret != SQLITE_ROW) {
      86           0 :         sqlite3_finalize(pragma_read_stmt);
      87           0 :         error = Untranslated(strprintf("SQLiteDatabase: Failed to fetch %s: %s", description, sqlite3_errstr(ret)));
      88           0 :         return std::nullopt;
      89             :     }
      90        1692 :     int result = sqlite3_column_int(pragma_read_stmt, 0);
      91        1692 :     sqlite3_finalize(pragma_read_stmt);
      92        1692 :     return result;
      93        1692 : }
      94             : 
      95        4084 : static void SetPragma(sqlite3* db, const std::string& key, const std::string& value, const std::string& err_msg)
      96             : {
      97        4084 :     std::string stmt_text = strprintf("PRAGMA %s = %s", key, value);
      98        4084 :     int ret = sqlite3_exec(db, stmt_text.c_str(), nullptr, nullptr, nullptr);
      99        4084 :     if (ret != SQLITE_OK) {
     100           0 :         throw std::runtime_error(strprintf("SQLiteDatabase: %s: %s\n", err_msg, sqlite3_errstr(ret)));
     101             :     }
     102        4084 : }
     103             : 
     104             : Mutex SQLiteDatabase::g_sqlite_mutex;
     105             : int SQLiteDatabase::g_sqlite_count = 0;
     106             : 
     107        2154 : SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options, bool mock)
     108        2154 :     : WalletDatabase(), m_mock(mock), m_dir_path(fs::PathToString(dir_path)), m_file_path(fs::PathToString(file_path)), m_use_unsafe_sync(options.use_unsafe_sync)
     109        2154 : {
     110             :     {
     111             :         LOCK(g_sqlite_mutex);
     112             :         LogPrintf("Using SQLite Version %s\n", SQLiteDatabaseVersion());
     113             :         LogPrintf("Using wallet %s\n", m_dir_path);
     114             : 
     115             :         if (++g_sqlite_count == 1) {
     116             :             // Setup logging
     117             :             int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr);
     118             :             if (ret != SQLITE_OK) {
     119             :                 throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret)));
     120             :             }
     121             :             // Force serialized threading mode
     122             :             ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
     123             :             if (ret != SQLITE_OK) {
     124             :                 throw std::runtime_error(strprintf("SQLiteDatabase: Failed to configure serialized threading mode: %s\n", sqlite3_errstr(ret)));
     125             :             }
     126             :         }
     127             :         int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized
     128             :         if (ret != SQLITE_OK) {
     129             :             throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret)));
     130             :         }
     131             :     }
     132             : 
     133             :     try {
     134             :         Open();
     135             :     } catch (const std::runtime_error&) {
     136             :         // If open fails, cleanup this object and rethrow the exception
     137             :         Cleanup();
     138             :         throw;
     139             :     }
     140        1077 : }
     141             : 
     142      208864 : void SQLiteBatch::SetupSQLStatements()
     143             : {
     144     1253184 :     const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
     145      208864 :         {&m_read_stmt, "SELECT value FROM main WHERE key = ?"},
     146      208864 :         {&m_insert_stmt, "INSERT INTO main VALUES(?, ?)"},
     147      208864 :         {&m_overwrite_stmt, "INSERT or REPLACE into main values(?, ?)"},
     148      208864 :         {&m_delete_stmt, "DELETE FROM main WHERE key = ?"},
     149      208864 :         {&m_cursor_stmt, "SELECT key, value FROM main"},
     150      208864 :         {&m_delete_prefix_stmt, "DELETE FROM main WHERE instr(key, ?) = 1"},
     151             :     };
     152             : 
     153     1462048 :     for (const auto& [stmt_prepared, stmt_text] : statements) {
     154     1253184 :         if (*stmt_prepared == nullptr) {
     155     3759552 :             int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, stmt_prepared, nullptr);
     156     1253184 :             if (res != SQLITE_OK) {
     157           0 :                 throw std::runtime_error(strprintf(
     158           0 :                     "SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
     159             :             }
     160     1253184 :         }
     161             :     }
     162      208864 : }
     163             : 
     164        3201 : SQLiteDatabase::~SQLiteDatabase()
     165        3201 : {
     166        1067 :     Cleanup();
     167        3201 : }
     168             : 
     169        1077 : void SQLiteDatabase::Cleanup() noexcept
     170             : {
     171        1077 :     AssertLockNotHeld(g_sqlite_mutex);
     172             : 
     173        1077 :     Close();
     174             : 
     175        1077 :     LOCK(g_sqlite_mutex);
     176        1077 :     if (--g_sqlite_count == 0) {
     177         669 :         int ret = sqlite3_shutdown();
     178         669 :         if (ret != SQLITE_OK) {
     179           0 :             LogPrintf("SQLiteDatabase: Failed to shutdown SQLite: %s\n", sqlite3_errstr(ret));
     180           0 :         }
     181         669 :     }
     182        1077 : }
     183             : 
     184         846 : bool SQLiteDatabase::Verify(bilingual_str& error)
     185             : {
     186         846 :     assert(m_db);
     187             : 
     188             :     // Check the application ID matches our network magic
     189         846 :     auto read_result = ReadPragmaInteger(m_db, "application_id", "the application id", error);
     190         846 :     if (!read_result.has_value()) return false;
     191         846 :     uint32_t app_id = static_cast<uint32_t>(read_result.value());
     192         846 :     uint32_t net_magic = ReadBE32(Params().MessageStart());
     193         846 :     if (app_id != net_magic) {
     194           0 :         error = strprintf(_("SQLiteDatabase: Unexpected application id. Expected %u, got %u"), net_magic, app_id);
     195           0 :         return false;
     196             :     }
     197             : 
     198             :     // Check our schema version
     199         846 :     read_result = ReadPragmaInteger(m_db, "user_version", "sqlite wallet schema version", error);
     200         846 :     if (!read_result.has_value()) return false;
     201         846 :     int32_t user_ver = read_result.value();
     202         846 :     if (user_ver != WALLET_SCHEMA_VERSION) {
     203           0 :         error = strprintf(_("SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported"), user_ver, WALLET_SCHEMA_VERSION);
     204           0 :         return false;
     205             :     }
     206             : 
     207         846 :     sqlite3_stmt* stmt{nullptr};
     208         846 :     int ret = sqlite3_prepare_v2(m_db, "PRAGMA integrity_check", -1, &stmt, nullptr);
     209         846 :     if (ret != SQLITE_OK) {
     210           0 :         sqlite3_finalize(stmt);
     211           0 :         error = strprintf(_("SQLiteDatabase: Failed to prepare statement to verify database: %s"), sqlite3_errstr(ret));
     212           0 :         return false;
     213             :     }
     214         846 :     while (true) {
     215        1692 :         ret = sqlite3_step(stmt);
     216        1692 :         if (ret == SQLITE_DONE) {
     217         846 :             break;
     218             :         }
     219         846 :         if (ret != SQLITE_ROW) {
     220           0 :             error = strprintf(_("SQLiteDatabase: Failed to execute statement to verify database: %s"), sqlite3_errstr(ret));
     221           0 :             break;
     222             :         }
     223         846 :         const char* msg = (const char*)sqlite3_column_text(stmt, 0);
     224         846 :         if (!msg) {
     225           0 :             error = strprintf(_("SQLiteDatabase: Failed to read database verification error: %s"), sqlite3_errstr(ret));
     226           0 :             break;
     227             :         }
     228         846 :         std::string str_msg(msg);
     229         846 :         if (str_msg == "ok") {
     230         846 :             continue;
     231             :         }
     232           0 :         if (error.empty()) {
     233           0 :             error = _("Failed to verify database") + Untranslated("\n");
     234           0 :         }
     235           0 :         error += Untranslated(strprintf("%s\n", str_msg));
     236         846 :     }
     237         846 :     sqlite3_finalize(stmt);
     238         846 :     return error.empty();
     239         846 : }
     240             : 
     241        1077 : void SQLiteDatabase::Open()
     242             : {
     243        1077 :     int flags = SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
     244        1077 :     if (m_mock) {
     245          36 :         flags |= SQLITE_OPEN_MEMORY; // In memory database for mock db
     246          36 :     }
     247             : 
     248        1077 :     if (m_db == nullptr) {
     249        1077 :         if (!m_mock) {
     250        1041 :             TryCreateDirectories(fs::PathFromString(m_dir_path));
     251        1039 :         }
     252        1075 :         int ret = sqlite3_open_v2(m_file_path.c_str(), &m_db, flags, nullptr);
     253        1075 :         if (ret != SQLITE_OK) {
     254           0 :             throw std::runtime_error(strprintf("SQLiteDatabase: Failed to open database: %s\n", sqlite3_errstr(ret)));
     255             :         }
     256        1075 :         ret = sqlite3_extended_result_codes(m_db, 1);
     257        1075 :         if (ret != SQLITE_OK) {
     258           0 :             throw std::runtime_error(strprintf("SQLiteDatabase: Failed to enable extended result codes: %s\n", sqlite3_errstr(ret)));
     259             :         }
     260             :         // Trace SQL statements if tracing is enabled with -debug=walletdb -loglevel=walletdb:trace
     261        1075 :         if (LogAcceptCategory(BCLog::WALLETDB, BCLog::Level::Trace)) {
     262        1041 :            ret = sqlite3_trace_v2(m_db, SQLITE_TRACE_STMT, TraceSqlCallback, this);
     263        1041 :            if (ret != SQLITE_OK) {
     264           0 :                LogPrintf("Failed to enable SQL tracing for %s\n", Filename());
     265           0 :            }
     266        1041 :         }
     267        1075 :     }
     268             : 
     269        1075 :     if (sqlite3_db_readonly(m_db, "main") != 0) {
     270           0 :         throw std::runtime_error("SQLiteDatabase: Database opened in readonly mode but read-write permissions are needed");
     271             :     }
     272             : 
     273             :     // Acquire an exclusive lock on the database
     274             :     // First change the locking mode to exclusive
     275        1075 :     SetPragma(m_db, "locking_mode", "exclusive", "Unable to change database locking mode to exclusive");
     276             :     // Now begin a transaction to acquire the exclusive lock. This lock won't be released until we close because of the exclusive locking mode.
     277        1075 :     int ret = sqlite3_exec(m_db, "BEGIN EXCLUSIVE TRANSACTION", nullptr, nullptr, nullptr);
     278        1075 :     if (ret != SQLITE_OK) {
     279           8 :         throw std::runtime_error("SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of " PACKAGE_NAME "?\n");
     280             :     }
     281        1067 :     ret = sqlite3_exec(m_db, "COMMIT", nullptr, nullptr, nullptr);
     282        1067 :     if (ret != SQLITE_OK) {
     283           0 :         throw std::runtime_error(strprintf("SQLiteDatabase: Unable to end exclusive lock transaction: %s\n", sqlite3_errstr(ret)));
     284             :     }
     285             : 
     286             :     // Enable fullfsync for the platforms that use it
     287        1067 :     SetPragma(m_db, "fullfsync", "true", "Failed to enable fullfsync");
     288             : 
     289        1067 :     if (m_use_unsafe_sync) {
     290             :         // Use normal synchronous mode for the journal
     291         936 :         LogPrintf("WARNING SQLite is configured to not wait for data to be flushed to disk. Data loss and corruption may occur.\n");
     292         936 :         SetPragma(m_db, "synchronous", "OFF", "Failed to set synchronous mode to OFF");
     293         936 :     }
     294             : 
     295             :     // Make the table for our key-value pairs
     296             :     // First check that the main table exists
     297        1067 :     sqlite3_stmt* check_main_stmt{nullptr};
     298        1067 :     ret = sqlite3_prepare_v2(m_db, "SELECT name FROM sqlite_master WHERE type='table' AND name='main'", -1, &check_main_stmt, nullptr);
     299        1067 :     if (ret != SQLITE_OK) {
     300           0 :         throw std::runtime_error(strprintf("SQLiteDatabase: Failed to prepare statement to check table existence: %s\n", sqlite3_errstr(ret)));
     301             :     }
     302        1067 :     ret = sqlite3_step(check_main_stmt);
     303        1067 :     if (sqlite3_finalize(check_main_stmt) != SQLITE_OK) {
     304           0 :         throw std::runtime_error(strprintf("SQLiteDatabase: Failed to finalize statement checking table existence: %s\n", sqlite3_errstr(ret)));
     305             :     }
     306             :     bool table_exists;
     307        1067 :     if (ret == SQLITE_DONE) {
     308         503 :         table_exists = false;
     309        1067 :     } else if (ret == SQLITE_ROW) {
     310         564 :         table_exists = true;
     311         564 :     } else {
     312           0 :         throw std::runtime_error(strprintf("SQLiteDatabase: Failed to execute statement to check table existence: %s\n", sqlite3_errstr(ret)));
     313             :     }
     314             : 
     315             :     // Do the db setup things because the table doesn't exist only when we are creating a new wallet
     316        1067 :     if (!table_exists) {
     317         503 :         ret = sqlite3_exec(m_db, "CREATE TABLE main(key BLOB PRIMARY KEY NOT NULL, value BLOB NOT NULL)", nullptr, nullptr, nullptr);
     318         503 :         if (ret != SQLITE_OK) {
     319           0 :             throw std::runtime_error(strprintf("SQLiteDatabase: Failed to create new database: %s\n", sqlite3_errstr(ret)));
     320             :         }
     321             : 
     322             :         // Set the application id
     323         503 :         uint32_t app_id = ReadBE32(Params().MessageStart());
     324        1006 :         SetPragma(m_db, "application_id", strprintf("%d", static_cast<int32_t>(app_id)),
     325         503 :                   "Failed to set the application id");
     326             : 
     327             :         // Set the user version
     328        1006 :         SetPragma(m_db, "user_version", strprintf("%d", WALLET_SCHEMA_VERSION),
     329         503 :                   "Failed to set the wallet schema version");
     330         503 :     }
     331        1069 : }
     332             : 
     333          35 : bool SQLiteDatabase::Rewrite(const char* skip)
     334             : {
     335             :     // Rewrite the database using the VACUUM command: https://sqlite.org/lang_vacuum.html
     336          35 :     int ret = sqlite3_exec(m_db, "VACUUM", nullptr, nullptr, nullptr);
     337          35 :     return ret == SQLITE_OK;
     338             : }
     339             : 
     340          44 : bool SQLiteDatabase::Backup(const std::string& dest) const
     341             : {
     342             :     sqlite3* db_copy;
     343          44 :     int res = sqlite3_open(dest.c_str(), &db_copy);
     344          44 :     if (res != SQLITE_OK) {
     345           6 :         sqlite3_close(db_copy);
     346           6 :         return false;
     347             :     }
     348          38 :     sqlite3_backup* backup = sqlite3_backup_init(db_copy, "main", m_db, "main");
     349          38 :     if (!backup) {
     350           0 :         LogPrintf("%s: Unable to begin backup: %s\n", __func__, sqlite3_errmsg(m_db));
     351           0 :         sqlite3_close(db_copy);
     352           0 :         return false;
     353             :     }
     354             :     // Specifying -1 will copy all of the pages
     355          38 :     res = sqlite3_backup_step(backup, -1);
     356          38 :     if (res != SQLITE_DONE) {
     357           6 :         LogPrintf("%s: Unable to backup: %s\n", __func__, sqlite3_errstr(res));
     358           6 :         sqlite3_backup_finish(backup);
     359           6 :         sqlite3_close(db_copy);
     360           6 :         return false;
     361             :     }
     362          32 :     res = sqlite3_backup_finish(backup);
     363          32 :     sqlite3_close(db_copy);
     364          32 :     return res == SQLITE_OK;
     365          44 : }
     366             : 
     367        1753 : void SQLiteDatabase::Close()
     368             : {
     369        1753 :     int res = sqlite3_close(m_db);
     370        1753 :     if (res != SQLITE_OK) {
     371           0 :         throw std::runtime_error(strprintf("SQLiteDatabase: Failed to close database: %s\n", sqlite3_errstr(res)));
     372             :     }
     373        1753 :     m_db = nullptr;
     374        1753 : }
     375             : 
     376      208864 : std::unique_ptr<DatabaseBatch> SQLiteDatabase::MakeBatch(bool flush_on_close)
     377             : {
     378             :     // We ignore flush_on_close because we don't do manual flushing for SQLite
     379      208864 :     return std::make_unique<SQLiteBatch>(*this);
     380             : }
     381             : 
     382      417728 : SQLiteBatch::SQLiteBatch(SQLiteDatabase& database)
     383      208864 :     : m_database(database)
     384      417728 : {
     385             :     // Make sure we have a db handle
     386             :     assert(m_database.m_db);
     387             : 
     388             :     SetupSQLStatements();
     389      208864 : }
     390             : 
     391      208864 : void SQLiteBatch::Close()
     392             : {
     393             :     // If this batch started a transaction that was never committed/aborted,
     394             :     // abort it now. We intentionally only abort transactions this batch owns:
     395             :     // nested WalletBatches sharing the SQLite connection must not roll back an
     396             :     // outer transaction started by a different batch.
     397      208864 :     if (m_txn_started && m_database.m_db && sqlite3_get_autocommit(m_database.m_db) == 0) {
     398           0 :         if (TxnAbort()) {
     399           0 :             LogPrintf("SQLiteBatch: Batch closed unexpectedly without the transaction being explicitly committed or aborted\n");
     400           0 :         } else {
     401           0 :             LogPrintf("SQLiteBatch: Batch closed and failed to abort transaction\n");
     402             :         }
     403           0 :     }
     404             : 
     405             :     // Free all of the prepared statements
     406     1253184 :     const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
     407      208864 :         {&m_read_stmt, "read"},
     408      208864 :         {&m_insert_stmt, "insert"},
     409      208864 :         {&m_overwrite_stmt, "overwrite"},
     410      208864 :         {&m_delete_stmt, "delete"},
     411      208864 :         {&m_cursor_stmt, "cursor"},
     412      208864 :         {&m_delete_prefix_stmt, "delete prefix"},
     413             :     };
     414             : 
     415     2715230 :     for (const auto& [stmt_prepared, stmt_description] : statements) {
     416     1253183 :         int res = sqlite3_finalize(*stmt_prepared);
     417     1253183 :         if (res != SQLITE_OK) {
     418           0 :             LogPrintf("SQLiteBatch: Batch closed but could not finalize %s statement: %s\n",
     419             :                       stmt_description, sqlite3_errstr(res));
     420           0 :         }
     421     1253183 :         *stmt_prepared = nullptr;
     422             :     }
     423      208864 : }
     424             : 
     425       13353 : bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value)
     426             : {
     427       13353 :     if (!m_database.m_db) return false;
     428       13353 :     assert(m_read_stmt);
     429             : 
     430             :     // Bind: leftmost parameter in statement is index 1
     431       13353 :     if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false;
     432       13353 :     int res = sqlite3_step(m_read_stmt);
     433       13353 :     if (res != SQLITE_ROW) {
     434        2389 :         if (res != SQLITE_DONE) {
     435             :             // SQLITE_DONE means "not found", don't log an error in that case.
     436           0 :             LogPrintf("%s: Unable to execute statement: %s\n", __func__, sqlite3_errstr(res));
     437           0 :         }
     438        2389 :         sqlite3_clear_bindings(m_read_stmt);
     439        2389 :         sqlite3_reset(m_read_stmt);
     440        2389 :         return false;
     441             :     }
     442             :     // Leftmost column in result is index 0
     443       10964 :     value.clear();
     444       10964 :     value.write(SpanFromBlob(m_read_stmt, 0));
     445             : 
     446       10964 :     sqlite3_clear_bindings(m_read_stmt);
     447       10964 :     sqlite3_reset(m_read_stmt);
     448       10964 :     return true;
     449       13353 : }
     450             : 
     451      220009 : bool SQLiteBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite)
     452             : {
     453      220009 :     if (!m_database.m_db) return false;
     454      220009 :     assert(m_insert_stmt && m_overwrite_stmt);
     455             : 
     456             :     sqlite3_stmt* stmt;
     457      220009 :     if (overwrite) {
     458      199603 :         stmt = m_overwrite_stmt;
     459      199603 :     } else {
     460       20406 :         stmt = m_insert_stmt;
     461             :     }
     462             : 
     463             :     // Bind: leftmost parameter in statement is index 1
     464             :     // Insert index 1 is key, 2 is value
     465      220009 :     if (!BindBlobToStatement(stmt, 1, key, "key")) return false;
     466      220009 :     if (!BindBlobToStatement(stmt, 2, value, "value")) return false;
     467             : 
     468             :     // Execute
     469      220009 :     int res = sqlite3_step(stmt);
     470      220009 :     sqlite3_clear_bindings(stmt);
     471      220009 :     sqlite3_reset(stmt);
     472      220009 :     if (res != SQLITE_DONE) {
     473           0 :         LogPrintf("%s: Unable to execute statement: %s\n", __func__, sqlite3_errstr(res));
     474           0 :     }
     475      220009 :     return res == SQLITE_DONE;
     476      220009 : }
     477             : 
     478        7145 : bool SQLiteBatch::ExecStatement(sqlite3_stmt* stmt, Span<const std::byte> blob)
     479             : {
     480        7145 :     if (!m_database.m_db) return false;
     481        7145 :     assert(stmt);
     482             : 
     483             :     // Bind: leftmost parameter in statement is index 1
     484        7145 :     if (!BindBlobToStatement(stmt, 1, blob, "key")) return false;
     485             : 
     486             :     // Execute
     487        7145 :     int res = sqlite3_step(stmt);
     488        7145 :     sqlite3_clear_bindings(stmt);
     489        7145 :     sqlite3_reset(stmt);
     490        7145 :     if (res != SQLITE_DONE) {
     491           0 :         LogPrintf("%s: Unable to execute statement: %s\n", __func__, sqlite3_errstr(res));
     492           0 :     }
     493        7145 :     return res == SQLITE_DONE;
     494        7145 : }
     495             : 
     496        7138 : bool SQLiteBatch::EraseKey(CDataStream&& key)
     497             : {
     498        7138 :     return ExecStatement(m_delete_stmt, key);
     499             : }
     500             : 
     501           7 : bool SQLiteBatch::ErasePrefix(Span<const std::byte> prefix)
     502             : {
     503           7 :     return ExecStatement(m_delete_prefix_stmt, prefix);
     504             : }
     505             : 
     506           0 : bool SQLiteBatch::HasKey(CDataStream&& key)
     507             : {
     508           0 :     if (!m_database.m_db) return false;
     509           0 :     assert(m_read_stmt);
     510             : 
     511             :     // Bind: leftmost parameter in statement is index 1
     512           0 :     if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false;
     513           0 :     int res = sqlite3_step(m_read_stmt);
     514           0 :     sqlite3_clear_bindings(m_read_stmt);
     515           0 :     sqlite3_reset(m_read_stmt);
     516           0 :     return res == SQLITE_ROW;
     517           0 : }
     518             : 
     519         886 : bool SQLiteBatch::StartCursor()
     520             : {
     521         886 :     assert(!m_cursor_init);
     522         886 :     if (!m_database.m_db) return false;
     523         886 :     m_cursor_init = true;
     524         886 :     return true;
     525         886 : }
     526             : 
     527       29722 : bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete)
     528             : {
     529       29722 :     complete = false;
     530             : 
     531       29722 :     if (!m_cursor_init) return false;
     532             : 
     533       29722 :     int res = sqlite3_step(m_cursor_stmt);
     534       29722 :     if (res == SQLITE_DONE) {
     535         886 :         complete = true;
     536         886 :         return true;
     537             :     }
     538       28836 :     if (res != SQLITE_ROW) {
     539           0 :         LogPrintf("SQLiteBatch::ReadAtCursor: Unable to execute cursor step: %s\n", sqlite3_errstr(res));
     540           0 :         return false;
     541             :     }
     542             : 
     543       28836 :     key.clear();
     544       28836 :     value.clear();
     545             : 
     546             :     // Leftmost column in result is index 0
     547       28836 :     key.write(SpanFromBlob(m_cursor_stmt, 0));
     548       28836 :     value.write(SpanFromBlob(m_cursor_stmt, 1));
     549       28836 :     return true;
     550       29722 : }
     551             : 
     552         886 : void SQLiteBatch::CloseCursor()
     553             : {
     554         886 :     sqlite3_reset(m_cursor_stmt);
     555         886 :     m_cursor_init = false;
     556         886 : }
     557             : 
     558         129 : bool SQLiteBatch::TxnBegin()
     559             : {
     560         129 :     if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) == 0) return false;
     561         129 :     int res = sqlite3_exec(m_database.m_db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
     562         129 :     if (res != SQLITE_OK) {
     563           0 :         LogPrintf("SQLiteBatch: Failed to begin the transaction\n");
     564           0 :     } else {
     565         129 :         m_txn_started = true;
     566             :     }
     567         129 :     return res == SQLITE_OK;
     568         129 : }
     569             : 
     570         119 : bool SQLiteBatch::TxnCommit()
     571             : {
     572             :     // Refuse to operate on a transaction this batch does not own, so a nested
     573             :     // batch whose TxnBegin() failed cannot accidentally commit an outer
     574             :     // transaction started by a different batch on the shared connection.
     575         119 :     if (!m_txn_started) return false;
     576         119 :     if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) != 0) return false;
     577         119 :     int res = sqlite3_exec(m_database.m_db, "COMMIT TRANSACTION", nullptr, nullptr, nullptr);
     578         119 :     if (res != SQLITE_OK) {
     579           0 :         LogPrintf("SQLiteBatch: Failed to commit the transaction\n");
     580           0 :     } else {
     581         119 :         m_txn_started = false;
     582             :     }
     583         119 :     return res == SQLITE_OK;
     584         119 : }
     585             : 
     586          10 : bool SQLiteBatch::TxnAbort()
     587             : {
     588             :     // Refuse to operate on a transaction this batch does not own; see TxnCommit.
     589          10 :     if (!m_txn_started) return false;
     590          10 :     if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) != 0) return false;
     591          10 :     int res = sqlite3_exec(m_database.m_db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr);
     592          10 :     if (res != SQLITE_OK) {
     593           0 :         LogPrintf("SQLiteBatch: Failed to abort the transaction\n");
     594           0 :     } else {
     595          10 :         m_txn_started = false;
     596             :     }
     597          10 :     return res == SQLITE_OK;
     598          10 : }
     599             : 
     600        1041 : std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
     601             : {
     602             :     try {
     603        1041 :         fs::path data_file = SQLiteDataFile(path);
     604        1041 :         auto db = std::make_unique<SQLiteDatabase>(data_file.parent_path(), data_file, options);
     605        1031 :         if (options.verify && !db->Verify(error)) {
     606           0 :             status = DatabaseStatus::FAILED_VERIFY;
     607           0 :             return nullptr;
     608             :         }
     609        1031 :         status = DatabaseStatus::SUCCESS;
     610        1031 :         return db;
     611        1041 :     } catch (const std::runtime_error& e) {
     612          10 :         status = DatabaseStatus::FAILED_LOAD;
     613          10 :         error = Untranslated(e.what());
     614          10 :         return nullptr;
     615          10 :     }
     616        1051 : }
     617             : 
     618        1077 : std::string SQLiteDatabaseVersion()
     619             : {
     620        1077 :     return std::string(sqlite3_libversion());
     621             : }
     622             : } // namespace wallet

Generated by: LCOV version 1.16