LCOV - code coverage report
Current view: top level - src/wallet - sqlite.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 305 411 74.2 %
Date: 2022-04-21 14:51:19 Functions: 27 28 96.4 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 90 152 59.2 %

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

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a