sqlite.cpp raw

   1  // Copyright (c) 2020-2022 The Limenka 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 <limenka-build-config.h> // IWYU pragma: keep
   6  
   7  #include <wallet/sqlite.h>
   8  
   9  #include <chainparams.h>
  10  #include <crypto/common.h>
  11  #include <logging.h>
  12  #include <sync.h>
  13  #include <util/fs_helpers.h>
  14  #include <util/check.h>
  15  #include <util/strencodings.h>
  16  #include <util/translation.h>
  17  #include <wallet/db.h>
  18  
  19  #include <sqlite3.h>
  20  #include <stdint.h>
  21  
  22  #include <optional>
  23  #include <utility>
  24  #include <vector>
  25  
  26  namespace wallet {
  27  static constexpr int32_t WALLET_SCHEMA_VERSION = 0;
  28  
  29  static Span<const std::byte> SpanFromBlob(sqlite3_stmt* stmt, int col)
  30  {
  31      return {reinterpret_cast<const std::byte*>(sqlite3_column_blob(stmt, col)),
  32              static_cast<size_t>(sqlite3_column_bytes(stmt, col))};
  33  }
  34  
  35  static void ErrorLogCallback(void* arg, int code, const char* msg)
  36  {
  37      // From sqlite3_config() documentation for the SQLITE_CONFIG_LOG option:
  38      // "The void pointer that is the second argument to SQLITE_CONFIG_LOG is passed through as
  39      // the first parameter to the application-defined logger function whenever that function is
  40      // invoked."
  41      // Assert that this is the case:
  42      assert(arg == nullptr);
  43      LogWarning("SQLite Error. Code: %d. Message: %s", code, msg);
  44  }
  45  
  46  static int TraceSqlCallback(unsigned code, void* context, void* param1, void* param2)
  47  {
  48      auto* db = static_cast<SQLiteDatabase*>(context);
  49      if (code == SQLITE_TRACE_STMT) {
  50          auto* stmt = static_cast<sqlite3_stmt*>(param1);
  51          // To be conservative and avoid leaking potentially secret information
  52          // in the log file, only expand statements that query the database, not
  53          // statements that update the database.
  54          char* expanded{sqlite3_stmt_readonly(stmt) ? sqlite3_expanded_sql(stmt) : nullptr};
  55          LogTrace(BCLog::WALLETDB, "[%s] SQLite Statement: %s\n", db->Filename(), expanded ? expanded : sqlite3_sql(stmt));
  56          if (expanded) sqlite3_free(expanded);
  57      }
  58      return SQLITE_OK;
  59  }
  60  
  61  static bool BindBlobToStatement(sqlite3_stmt* stmt,
  62                                  int index,
  63                                  Span<const std::byte> blob,
  64                                  const std::string& description)
  65  {
  66      // Pass a pointer to the empty string "" below instead of passing the
  67      // blob.data() pointer if the blob.data() pointer is null. Passing a null
  68      // data pointer to bind_blob would cause sqlite to bind the SQL NULL value
  69      // instead of the empty blob value X'', which would mess up SQL comparisons.
  70      int res = sqlite3_bind_blob(stmt, index, blob.data() ? static_cast<const void*>(blob.data()) : "", blob.size(), SQLITE_STATIC);
  71      if (res != SQLITE_OK) {
  72          LogWarning("Unable to bind %s to statement: %s", description, sqlite3_errstr(res));
  73          sqlite3_clear_bindings(stmt);
  74          sqlite3_reset(stmt);
  75          return false;
  76      }
  77  
  78      return true;
  79  }
  80  
  81  static std::optional<int> ReadPragmaInteger(sqlite3* db, const std::string& key, const std::string& description, bilingual_str& error)
  82  {
  83      std::string stmt_text = strprintf("PRAGMA %s", key);
  84      sqlite3_stmt* pragma_read_stmt{nullptr};
  85      int ret = sqlite3_prepare_v2(db, stmt_text.c_str(), -1, &pragma_read_stmt, nullptr);
  86      if (ret != SQLITE_OK) {
  87          sqlite3_finalize(pragma_read_stmt);
  88          error = Untranslated(strprintf("SQLiteDatabase: Failed to prepare the statement to fetch %s: %s", description, sqlite3_errstr(ret)));
  89          return std::nullopt;
  90      }
  91      ret = sqlite3_step(pragma_read_stmt);
  92      if (ret != SQLITE_ROW) {
  93          sqlite3_finalize(pragma_read_stmt);
  94          error = Untranslated(strprintf("SQLiteDatabase: Failed to fetch %s: %s", description, sqlite3_errstr(ret)));
  95          return std::nullopt;
  96      }
  97      int result = sqlite3_column_int(pragma_read_stmt, 0);
  98      sqlite3_finalize(pragma_read_stmt);
  99      return result;
 100  }
 101  
 102  static void SetPragma(sqlite3* db, const std::string& key, const std::string& value, const std::string& err_msg)
 103  {
 104      std::string stmt_text = strprintf("PRAGMA %s = %s", key, value);
 105      int ret = sqlite3_exec(db, stmt_text.c_str(), nullptr, nullptr, nullptr);
 106      if (ret != SQLITE_OK) {
 107          throw std::runtime_error(strprintf("SQLiteDatabase: %s: %s\n", err_msg, sqlite3_errstr(ret)));
 108      }
 109  }
 110  
 111  Mutex SQLiteDatabase::g_sqlite_mutex;
 112  int SQLiteDatabase::g_sqlite_count = 0;
 113  
 114  SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options, bool mock)
 115      : WalletDatabase(), m_mock(mock), m_dir_path(dir_path), m_file_path(fs::PathToString(file_path)), m_write_semaphore(1), m_use_unsafe_sync(options.use_unsafe_sync)
 116  {
 117      {
 118          LOCK(g_sqlite_mutex);
 119          LogPrintf("Using SQLite Version %s\n", SQLiteDatabaseVersion());
 120          LogPrintf("Using wallet %s\n", fs::PathToString(m_dir_path));
 121  
 122          if (++g_sqlite_count == 1) {
 123              // Setup logging
 124              int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr);
 125              if (ret != SQLITE_OK) {
 126                  throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret)));
 127              }
 128              // Force serialized threading mode
 129              ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
 130              if (ret != SQLITE_OK) {
 131                  throw std::runtime_error(strprintf("SQLiteDatabase: Failed to configure serialized threading mode: %s\n", sqlite3_errstr(ret)));
 132              }
 133          }
 134          int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized
 135          if (ret != SQLITE_OK) {
 136              throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret)));
 137          }
 138      }
 139  
 140      try {
 141          Open();
 142      } catch (const std::runtime_error&) {
 143          // If open fails, cleanup this object and rethrow the exception
 144          Cleanup();
 145          throw;
 146      }
 147  }
 148  
 149  void SQLiteBatch::SetupSQLStatements()
 150  {
 151      const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
 152          {&m_read_stmt, "SELECT value FROM main WHERE key = ?"},
 153          {&m_insert_stmt, "INSERT INTO main VALUES(?, ?)"},
 154          {&m_overwrite_stmt, "INSERT or REPLACE into main values(?, ?)"},
 155          {&m_delete_stmt, "DELETE FROM main WHERE key = ?"},
 156          {&m_delete_prefix_stmt, "DELETE FROM main WHERE instr(key, ?) = 1"},
 157      };
 158  
 159      for (const auto& [stmt_prepared, stmt_text] : statements) {
 160          if (*stmt_prepared == nullptr) {
 161              int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, stmt_prepared, nullptr);
 162              if (res != SQLITE_OK) {
 163                  throw std::runtime_error(strprintf(
 164                      "SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
 165              }
 166          }
 167      }
 168  }
 169  
 170  SQLiteDatabase::~SQLiteDatabase()
 171  {
 172      Cleanup();
 173  }
 174  
 175  void SQLiteDatabase::Cleanup() noexcept
 176  {
 177      AssertLockNotHeld(g_sqlite_mutex);
 178  
 179      Close();
 180  
 181      LOCK(g_sqlite_mutex);
 182      if (--g_sqlite_count == 0) {
 183          int ret = sqlite3_shutdown();
 184          if (ret != SQLITE_OK) {
 185              LogWarning("SQLiteDatabase: Failed to shutdown SQLite: %s", sqlite3_errstr(ret));
 186          }
 187      }
 188  }
 189  
 190  bool SQLiteDatabase::Verify(bilingual_str& error)
 191  {
 192      assert(m_db);
 193  
 194      // Check the application ID matches our network magic
 195      auto read_result = ReadPragmaInteger(m_db, "application_id", "the application id", error);
 196      if (!read_result.has_value()) return false;
 197      uint32_t app_id = static_cast<uint32_t>(read_result.value());
 198      uint32_t net_magic = ReadBE32(Params().MessageStart().data());
 199      if (app_id != net_magic) {
 200          error = strprintf(_("SQLiteDatabase: Unexpected application id. Expected %u, got %u"), net_magic, app_id);
 201          return false;
 202      }
 203  
 204      // Check our schema version
 205      read_result = ReadPragmaInteger(m_db, "user_version", "sqlite wallet schema version", error);
 206      if (!read_result.has_value()) return false;
 207      int32_t user_ver = read_result.value();
 208      if (user_ver != WALLET_SCHEMA_VERSION) {
 209          error = strprintf(_("SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported"), user_ver, WALLET_SCHEMA_VERSION);
 210          return false;
 211      }
 212  
 213      sqlite3_stmt* stmt{nullptr};
 214      int ret = sqlite3_prepare_v2(m_db, "PRAGMA integrity_check", -1, &stmt, nullptr);
 215      if (ret != SQLITE_OK) {
 216          sqlite3_finalize(stmt);
 217          error = strprintf(_("SQLiteDatabase: Failed to prepare statement to verify database: %s"), sqlite3_errstr(ret));
 218          return false;
 219      }
 220      while (true) {
 221          ret = sqlite3_step(stmt);
 222          if (ret == SQLITE_DONE) {
 223              break;
 224          }
 225          if (ret != SQLITE_ROW) {
 226              error = strprintf(_("SQLiteDatabase: Failed to execute statement to verify database: %s"), sqlite3_errstr(ret));
 227              break;
 228          }
 229          const char* msg = (const char*)sqlite3_column_text(stmt, 0);
 230          if (!msg) {
 231              error = strprintf(_("SQLiteDatabase: Failed to read database verification error: %s"), sqlite3_errstr(ret));
 232              break;
 233          }
 234          std::string str_msg(msg);
 235          if (str_msg == "ok") {
 236              continue;
 237          }
 238          if (error.empty()) {
 239              error = _("Failed to verify database") + Untranslated("\n");
 240          }
 241          error += Untranslated(strprintf("%s\n", str_msg));
 242      }
 243      sqlite3_finalize(stmt);
 244      return error.empty();
 245  }
 246  
 247  void SQLiteDatabase::Open()
 248  {
 249      int flags = SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
 250      if (m_mock) {
 251          flags |= SQLITE_OPEN_MEMORY; // In memory database for mock db
 252      }
 253  
 254      if (m_db == nullptr) {
 255          if (!m_mock) {
 256              TryCreateDirectories(m_dir_path);
 257              if (!IsDirWritable(m_dir_path)) {
 258                  throw std::runtime_error(strprintf("SQLiteDatabase: Failed to open database in directory '%s': directory is not writable", fs::PathToString(m_dir_path)));
 259              }
 260          }
 261  
 262          int ret = sqlite3_open_v2(m_file_path.c_str(), &m_db, flags, nullptr);
 263          if (ret != SQLITE_OK) {
 264              throw std::runtime_error(strprintf("SQLiteDatabase: Failed to open database: %s\n", sqlite3_errstr(ret)));
 265          }
 266          ret = sqlite3_extended_result_codes(m_db, 1);
 267          if (ret != SQLITE_OK) {
 268              throw std::runtime_error(strprintf("SQLiteDatabase: Failed to enable extended result codes: %s\n", sqlite3_errstr(ret)));
 269          }
 270          // Trace SQL statements if tracing is enabled with -debug=walletdb -loglevel=walletdb:trace
 271          if (LogAcceptCategory(BCLog::WALLETDB, BCLog::Level::Trace)) {
 272             ret = sqlite3_trace_v2(m_db, SQLITE_TRACE_STMT, TraceSqlCallback, this);
 273             if (ret != SQLITE_OK) {
 274                 LogWarning("Failed to enable SQL tracing for %s", Filename());
 275             }
 276          }
 277      }
 278  
 279      if (sqlite3_db_readonly(m_db, "main") != 0) {
 280          throw std::runtime_error("SQLiteDatabase: Database opened in readonly mode but read-write permissions are needed");
 281      }
 282  
 283      // Acquire an exclusive lock on the database
 284      // First change the locking mode to exclusive
 285      SetPragma(m_db, "locking_mode", "exclusive", "Unable to change database locking mode to exclusive");
 286      // Now begin a transaction to acquire the exclusive lock. This lock won't be released until we close because of the exclusive locking mode.
 287      int ret = sqlite3_exec(m_db, "BEGIN EXCLUSIVE TRANSACTION", nullptr, nullptr, nullptr);
 288      if (ret != SQLITE_OK) {
 289          throw std::runtime_error("SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of " CLIENT_NAME "?\n");
 290      }
 291      ret = sqlite3_exec(m_db, "COMMIT", nullptr, nullptr, nullptr);
 292      if (ret != SQLITE_OK) {
 293          throw std::runtime_error(strprintf("SQLiteDatabase: Unable to end exclusive lock transaction: %s\n", sqlite3_errstr(ret)));
 294      }
 295  
 296      // Enable fullfsync for the platforms that use it
 297      SetPragma(m_db, "fullfsync", "true", "Failed to enable fullfsync");
 298  
 299      if (m_use_unsafe_sync) {
 300          // Use normal synchronous mode for the journal
 301          LogWarning("SQLite is configured with reduced durability. Data loss may occur on power failure.");
 302          SetPragma(m_db, "synchronous", "NORMAL", "Failed to set synchronous mode to NORMAL");
 303      }
 304  
 305      // Make the table for our key-value pairs
 306      // First check that the main table exists
 307      sqlite3_stmt* check_main_stmt{nullptr};
 308      ret = sqlite3_prepare_v2(m_db, "SELECT name FROM sqlite_master WHERE type='table' AND name='main'", -1, &check_main_stmt, nullptr);
 309      if (ret != SQLITE_OK) {
 310          throw std::runtime_error(strprintf("SQLiteDatabase: Failed to prepare statement to check table existence: %s\n", sqlite3_errstr(ret)));
 311      }
 312      ret = sqlite3_step(check_main_stmt);
 313      if (sqlite3_finalize(check_main_stmt) != SQLITE_OK) {
 314          throw std::runtime_error(strprintf("SQLiteDatabase: Failed to finalize statement checking table existence: %s\n", sqlite3_errstr(ret)));
 315      }
 316      bool table_exists;
 317      if (ret == SQLITE_DONE) {
 318          table_exists = false;
 319      } else if (ret == SQLITE_ROW) {
 320          table_exists = true;
 321      } else {
 322          throw std::runtime_error(strprintf("SQLiteDatabase: Failed to execute statement to check table existence: %s\n", sqlite3_errstr(ret)));
 323      }
 324  
 325      // Do the db setup things because the table doesn't exist only when we are creating a new wallet
 326      if (!table_exists) {
 327          ret = sqlite3_exec(m_db, "CREATE TABLE main(key BLOB PRIMARY KEY NOT NULL, value BLOB NOT NULL)", nullptr, nullptr, nullptr);
 328          if (ret != SQLITE_OK) {
 329              throw std::runtime_error(strprintf("SQLiteDatabase: Failed to create new database: %s\n", sqlite3_errstr(ret)));
 330          }
 331  
 332          // Set the application id
 333          uint32_t app_id = ReadBE32(Params().MessageStart().data());
 334          SetPragma(m_db, "application_id", strprintf("%d", static_cast<int32_t>(app_id)),
 335                    "Failed to set the application id");
 336  
 337          // Set the user version
 338          SetPragma(m_db, "user_version", strprintf("%d", WALLET_SCHEMA_VERSION),
 339                    "Failed to set the wallet schema version");
 340      }
 341  }
 342  
 343  bool SQLiteDatabase::Rewrite(const char* skip)
 344  {
 345      // Rewrite the database using the VACUUM command: https://sqlite.org/lang_vacuum.html
 346      int ret = sqlite3_exec(m_db, "VACUUM", nullptr, nullptr, nullptr);
 347      return ret == SQLITE_OK;
 348  }
 349  
 350  bool SQLiteDatabase::Backup(const std::string& dest) const
 351  {
 352      sqlite3* db_copy;
 353      int res = sqlite3_open(dest.c_str(), &db_copy);
 354      if (res != SQLITE_OK) {
 355          sqlite3_close(db_copy);
 356          return false;
 357      }
 358      sqlite3_backup* backup = sqlite3_backup_init(db_copy, "main", m_db, "main");
 359      if (!backup) {
 360          LogWarning("Unable to begin sqlite backup: %s", sqlite3_errmsg(m_db));
 361          sqlite3_close(db_copy);
 362          return false;
 363      }
 364      // Specifying -1 will copy all of the pages
 365      res = sqlite3_backup_step(backup, -1);
 366      if (res != SQLITE_DONE) {
 367          LogWarning("Unable to continue sqlite backup: %s", sqlite3_errstr(res));
 368          sqlite3_backup_finish(backup);
 369          sqlite3_close(db_copy);
 370          return false;
 371      }
 372      res = sqlite3_backup_finish(backup);
 373      sqlite3_close(db_copy);
 374      return res == SQLITE_OK;
 375  }
 376  
 377  void SQLiteDatabase::Close()
 378  {
 379      int res = sqlite3_close(m_db);
 380      if (res != SQLITE_OK) {
 381          throw std::runtime_error(strprintf("SQLiteDatabase: Failed to close database: %s\n", sqlite3_errstr(res)));
 382      }
 383      m_db = nullptr;
 384  }
 385  
 386  bool SQLiteDatabase::HasActiveTxn()
 387  {
 388      // 'sqlite3_get_autocommit' returns true by default, and false if a transaction has begun and not been committed or rolled back.
 389      return m_db && sqlite3_get_autocommit(m_db) == 0;
 390  }
 391  
 392  int SQliteExecHandler::Exec(SQLiteDatabase& database, const std::string& statement)
 393  {
 394      return sqlite3_exec(database.m_db, statement.data(), nullptr, nullptr, nullptr);
 395  }
 396  
 397  std::unique_ptr<DatabaseBatch> SQLiteDatabase::MakeBatch(bool flush_on_close)
 398  {
 399      // We ignore flush_on_close because we don't do manual flushing for SQLite
 400      return std::make_unique<SQLiteBatch>(*this);
 401  }
 402  
 403  SQLiteBatch::SQLiteBatch(SQLiteDatabase& database)
 404      : m_database(database)
 405  {
 406      // Make sure we have a db handle
 407      assert(m_database.m_db);
 408  
 409      SetupSQLStatements();
 410  }
 411  
 412  void SQLiteBatch::Close()
 413  {
 414      bool force_conn_refresh = false;
 415  
 416      // If we began a transaction, and it wasn't committed, abort the transaction in progress
 417      if (m_txn) {
 418          if (TxnAbort()) {
 419              LogWarning("SQLiteBatch: Batch closed unexpectedly without the transaction being explicitly committed or aborted");
 420          } else {
 421              // If transaction cannot be aborted, it means there is a bug or there has been data corruption. Try to recover in this case
 422              // by closing and reopening the database. Closing the database should also ensure that any changes made since the transaction
 423              // was opened will be rolled back and future transactions can succeed without committing old data.
 424              force_conn_refresh = true;
 425              LogWarning("SQLiteBatch: Batch closed and failed to abort transaction, resetting db connection..");
 426          }
 427      }
 428  
 429      // Free all of the prepared statements
 430      const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
 431          {&m_read_stmt, "read"},
 432          {&m_insert_stmt, "insert"},
 433          {&m_overwrite_stmt, "overwrite"},
 434          {&m_delete_stmt, "delete"},
 435          {&m_delete_prefix_stmt, "delete prefix"},
 436      };
 437  
 438      for (const auto& [stmt_prepared, stmt_description] : statements) {
 439          int res = sqlite3_finalize(*stmt_prepared);
 440          if (res != SQLITE_OK) {
 441              LogWarning("SQLiteBatch: Batch closed but could not finalize %s statement: %s",
 442                        stmt_description, sqlite3_errstr(res));
 443          }
 444          *stmt_prepared = nullptr;
 445      }
 446  
 447      if (force_conn_refresh) {
 448          m_database.Close();
 449          try {
 450              m_database.Open();
 451              // If TxnAbort failed and we refreshed the connection, the semaphore was not released, so release it here to avoid deadlocks on future writes.
 452              m_database.m_write_semaphore.post();
 453          } catch (const std::runtime_error&) {
 454              // If open fails, cleanup this object and rethrow the exception
 455              m_database.Close();
 456              throw;
 457          }
 458      }
 459  }
 460  
 461  bool SQLiteBatch::ReadKey(DataStream&& key, DataStream& value)
 462  {
 463      if (!m_database.m_db) return false;
 464      assert(m_read_stmt);
 465  
 466      // Bind: leftmost parameter in statement is index 1
 467      if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false;
 468      int res = sqlite3_step(m_read_stmt);
 469      if (res != SQLITE_ROW) {
 470          if (res != SQLITE_DONE) {
 471              // SQLITE_DONE means "not found", don't log an error in that case.
 472              LogWarning("Unable to execute read statement: %s", sqlite3_errstr(res));
 473          }
 474          sqlite3_clear_bindings(m_read_stmt);
 475          sqlite3_reset(m_read_stmt);
 476          return false;
 477      }
 478      // Leftmost column in result is index 0
 479      value.clear();
 480      value.write(SpanFromBlob(m_read_stmt, 0));
 481  
 482      sqlite3_clear_bindings(m_read_stmt);
 483      sqlite3_reset(m_read_stmt);
 484      return true;
 485  }
 486  
 487  bool SQLiteBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
 488  {
 489      if (!m_database.m_db) return false;
 490      assert(m_insert_stmt && m_overwrite_stmt);
 491  
 492      sqlite3_stmt* stmt;
 493      if (overwrite) {
 494          stmt = m_overwrite_stmt;
 495      } else {
 496          stmt = m_insert_stmt;
 497      }
 498  
 499      // Bind: leftmost parameter in statement is index 1
 500      // Insert index 1 is key, 2 is value
 501      if (!BindBlobToStatement(stmt, 1, key, "key")) return false;
 502      if (!BindBlobToStatement(stmt, 2, value, "value")) return false;
 503  
 504      // Acquire semaphore if not previously acquired when creating a transaction.
 505      if (!m_txn) m_database.m_write_semaphore.wait();
 506  
 507      // Execute
 508      int res = sqlite3_step(stmt);
 509      sqlite3_clear_bindings(stmt);
 510      sqlite3_reset(stmt);
 511      if (res != SQLITE_DONE) {
 512          LogWarning("Unable to execute write statement: %s", sqlite3_errstr(res));
 513      }
 514  
 515      if (!m_txn) m_database.m_write_semaphore.post();
 516  
 517      return res == SQLITE_DONE;
 518  }
 519  
 520  bool SQLiteBatch::ExecStatement(sqlite3_stmt* stmt, Span<const std::byte> blob)
 521  {
 522      if (!m_database.m_db) return false;
 523      assert(stmt);
 524  
 525      // Bind: leftmost parameter in statement is index 1
 526      if (!BindBlobToStatement(stmt, 1, blob, "key")) return false;
 527  
 528      // Acquire semaphore if not previously acquired when creating a transaction.
 529      if (!m_txn) m_database.m_write_semaphore.wait();
 530  
 531      // Execute
 532      int res = sqlite3_step(stmt);
 533      sqlite3_clear_bindings(stmt);
 534      sqlite3_reset(stmt);
 535      if (res != SQLITE_DONE) {
 536          LogWarning("Unable to execute exec statement: %s", sqlite3_errstr(res));
 537      }
 538  
 539      if (!m_txn) m_database.m_write_semaphore.post();
 540  
 541      return res == SQLITE_DONE;
 542  }
 543  
 544  bool SQLiteBatch::EraseKey(DataStream&& key)
 545  {
 546      return ExecStatement(m_delete_stmt, key);
 547  }
 548  
 549  bool SQLiteBatch::ErasePrefix(Span<const std::byte> prefix)
 550  {
 551      return ExecStatement(m_delete_prefix_stmt, prefix);
 552  }
 553  
 554  bool SQLiteBatch::HasKey(DataStream&& key)
 555  {
 556      if (!m_database.m_db) return false;
 557      assert(m_read_stmt);
 558  
 559      // Bind: leftmost parameter in statement is index 1
 560      if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false;
 561      int res = sqlite3_step(m_read_stmt);
 562      sqlite3_clear_bindings(m_read_stmt);
 563      sqlite3_reset(m_read_stmt);
 564      return res == SQLITE_ROW;
 565  }
 566  
 567  DatabaseCursor::Status SQLiteCursor::Next(DataStream& key, DataStream& value)
 568  {
 569      int res = sqlite3_step(m_cursor_stmt);
 570      if (res == SQLITE_DONE) {
 571          return Status::DONE;
 572      }
 573      if (res != SQLITE_ROW) {
 574          LogWarning("Unable to execute cursor step: %s", sqlite3_errstr(res));
 575          return Status::FAIL;
 576      }
 577  
 578      key.clear();
 579      value.clear();
 580  
 581      // Leftmost column in result is index 0
 582      key.write(SpanFromBlob(m_cursor_stmt, 0));
 583      value.write(SpanFromBlob(m_cursor_stmt, 1));
 584      return Status::MORE;
 585  }
 586  
 587  SQLiteCursor::~SQLiteCursor()
 588  {
 589      sqlite3_clear_bindings(m_cursor_stmt);
 590      sqlite3_reset(m_cursor_stmt);
 591      int res = sqlite3_finalize(m_cursor_stmt);
 592      if (res != SQLITE_OK) {
 593          LogWarning("Cursor closed but could not finalize cursor statement: %s",
 594                     sqlite3_errstr(res));
 595      }
 596  }
 597  
 598  std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewCursor()
 599  {
 600      if (!m_database.m_db) return nullptr;
 601      auto cursor = std::make_unique<SQLiteCursor>();
 602  
 603      const char* stmt_text = "SELECT key, value FROM main";
 604      int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, &cursor->m_cursor_stmt, nullptr);
 605      if (res != SQLITE_OK) {
 606          throw std::runtime_error(strprintf(
 607              "%s: Failed to setup cursor SQL statement: %s\n", __func__, sqlite3_errstr(res)));
 608      }
 609  
 610      return cursor;
 611  }
 612  
 613  std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewPrefixCursor(Span<const std::byte> prefix)
 614  {
 615      if (!m_database.m_db) return nullptr;
 616  
 617      // To get just the records we want, the SQL statement does a comparison of the binary data
 618      // where the data must be greater than or equal to the prefix, and less than
 619      // the prefix incremented by one (when interpreted as an integer)
 620      std::vector<std::byte> start_range(prefix.begin(), prefix.end());
 621      std::vector<std::byte> end_range(prefix.begin(), prefix.end());
 622      auto it = end_range.rbegin();
 623      for (; it != end_range.rend(); ++it) {
 624          if (*it == std::byte(std::numeric_limits<unsigned char>::max())) {
 625              *it = std::byte(0);
 626              continue;
 627          }
 628          *it = std::byte(std::to_integer<unsigned char>(*it) + 1);
 629          break;
 630      }
 631      if (it == end_range.rend()) {
 632          // If the prefix is all 0xff bytes, clear end_range as we won't need it
 633          end_range.clear();
 634      }
 635  
 636      auto cursor = std::make_unique<SQLiteCursor>(start_range, end_range);
 637      if (!cursor) return nullptr;
 638  
 639      const char* stmt_text = end_range.empty() ? "SELECT key, value FROM main WHERE key >= ?" :
 640                              "SELECT key, value FROM main WHERE key >= ? AND key < ?";
 641      int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, &cursor->m_cursor_stmt, nullptr);
 642      if (res != SQLITE_OK) {
 643          throw std::runtime_error(strprintf(
 644              "SQLiteDatabase: Failed to setup cursor SQL statement: %s\n", sqlite3_errstr(res)));
 645      }
 646  
 647      if (!BindBlobToStatement(cursor->m_cursor_stmt, 1, cursor->m_prefix_range_start, "prefix_start")) return nullptr;
 648      if (!end_range.empty()) {
 649          if (!BindBlobToStatement(cursor->m_cursor_stmt, 2, cursor->m_prefix_range_end, "prefix_end")) return nullptr;
 650      }
 651  
 652      return cursor;
 653  }
 654  
 655  bool SQLiteBatch::TxnBegin()
 656  {
 657      if (!m_database.m_db || m_txn) return false;
 658      m_database.m_write_semaphore.wait();
 659      Assert(!m_database.HasActiveTxn());
 660      int res = Assert(m_exec_handler)->Exec(m_database, "BEGIN TRANSACTION");
 661      if (res != SQLITE_OK) {
 662          LogWarning("SQLiteBatch: Failed to begin the transaction");
 663          m_database.m_write_semaphore.post();
 664      } else {
 665          m_txn = true;
 666      }
 667      return res == SQLITE_OK;
 668  }
 669  
 670  bool SQLiteBatch::TxnCommit()
 671  {
 672      if (!m_database.m_db || !m_txn) return false;
 673      Assert(m_database.HasActiveTxn());
 674      int res = Assert(m_exec_handler)->Exec(m_database, "COMMIT TRANSACTION");
 675      if (res != SQLITE_OK) {
 676          LogWarning("SQLiteBatch: Failed to commit the transaction");
 677      } else {
 678          m_txn = false;
 679          m_database.m_write_semaphore.post();
 680      }
 681      return res == SQLITE_OK;
 682  }
 683  
 684  bool SQLiteBatch::TxnAbort()
 685  {
 686      if (!m_database.m_db || !m_txn) return false;
 687      Assert(m_database.HasActiveTxn());
 688      int res = Assert(m_exec_handler)->Exec(m_database, "ROLLBACK TRANSACTION");
 689      if (res != SQLITE_OK) {
 690          LogWarning("SQLiteBatch: Failed to abort the transaction");
 691      } else {
 692          m_txn = false;
 693          m_database.m_write_semaphore.post();
 694      }
 695      return res == SQLITE_OK;
 696  }
 697  
 698  std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
 699  {
 700      try {
 701          fs::path data_file = SQLiteDataFile(path);
 702          auto db = std::make_unique<SQLiteDatabase>(data_file.parent_path(), data_file, options);
 703          if (options.verify && !db->Verify(error)) {
 704              status = DatabaseStatus::FAILED_VERIFY;
 705              return nullptr;
 706          }
 707          status = DatabaseStatus::SUCCESS;
 708          return db;
 709      } catch (const std::runtime_error& e) {
 710          status = DatabaseStatus::FAILED_LOAD;
 711          error = Untranslated(e.what());
 712          return nullptr;
 713      }
 714  }
 715  
 716  std::string SQLiteDatabaseVersion()
 717  {
 718      return std::string(sqlite3_libversion());
 719  }
 720  } // namespace wallet
 721