LCOV - code coverage report
Current view: top level - src/wallet - sqlite.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 303 427 71.0 %
Date: 2021-06-29 14:35:33 Functions: 26 27 96.3 %
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: 86 150 57.3 %

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

Generated by: LCOV version 1.14