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