Branch data 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 : : }
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
|