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