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
|