Line data Source code
1 : // Copyright (c) 2020 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 <util/memory.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 : static const char* DATABASE_FILENAME = "wallet.dat";
20 :
21 13037 : static const int32_t WALLET_SCHEMA_VERSION = 0;
22 13037 :
23 : std::atomic<int> g_dbs_open{0};
24 :
25 0 : static void ErrorLogCallback(void* arg, int code, const char* msg)
26 : {
27 0 : assert(arg == nullptr); // That's what we tell it to do during the setup
28 0 : LogPrintf("SQLite Error. Code: %d. Message: %s\n", code, msg);
29 0 : }
30 :
31 200 : SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, bool mock) :
32 200 : WalletDatabase(), m_mock(mock), m_dir_path(dir_path.string()), m_file_path(file_path.string())
33 300 : {
34 100 : LogPrintf("Using SQLite Version %s\n", SQLiteDatabaseVersion());
35 100 : LogPrintf("Using wallet %s\n", m_dir_path);
36 :
37 100 : if (g_dbs_open.fetch_add(1) == 0) {
38 : // Setup logging
39 67 : int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr);
40 67 : if (ret != SQLITE_OK) {
41 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret)));
42 : }
43 : // Force serialized threading mode
44 67 : ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
45 67 : if (ret != SQLITE_OK) {
46 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to configure serialized threading mode: %s\n", sqlite3_errstr(ret)));
47 : }
48 67 : }
49 100 : int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized
50 100 : if (ret != SQLITE_OK) {
51 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret)));
52 : }
53 200 : }
54 :
55 13072 : bool SQLiteDatabase::PrepareDirectory() const
56 : {
57 13072 : if (m_mock) return true;
58 : // Try to create the directory containing the wallet file and lock it
59 13072 : TryCreateDirectories(m_dir_path);
60 13072 : if (!LockDirectory(m_dir_path, ".walletlock")) {
61 0 : LogPrintf("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it.\n", m_dir_path);
62 0 : return false;
63 : }
64 13072 : return true;
65 13072 : }
66 :
67 13037 : void SQLiteDatabase::SetupSQLStatements()
68 : {
69 13037 : std::string read_sql = "SELECT value FROM main WHERE key = ?";
70 13037 : std::string insert_sql = "INSERT INTO main VALUES(?, ?)";
71 13037 : std::string overwrite_sql = "INSERT OR REPLACE INTO main VALUES(?, ?)";
72 13037 : std::string delete_sql = "DELETE FROM main WHERE key = ?";
73 13037 : std::string cursor_sql = "SELECT key, value FROM main";
74 :
75 : int res;
76 13037 : if (!m_read_stmt) {
77 78 : if ((res = sqlite3_prepare_v2(m_db, read_sql.c_str(), -1, &m_read_stmt, nullptr)) != SQLITE_OK) {
78 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
79 : }
80 : }
81 13037 : if (!m_insert_stmt) {
82 78 : if ((res = sqlite3_prepare_v2(m_db, insert_sql.c_str(), -1, &m_insert_stmt, nullptr)) != SQLITE_OK) {
83 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
84 : }
85 : }
86 13037 : if (!m_overwrite_stmt) {
87 78 : if ((res = sqlite3_prepare_v2(m_db, overwrite_sql.c_str(), -1, &m_overwrite_stmt, nullptr)) != SQLITE_OK) {
88 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
89 : }
90 : }
91 13037 : if (!m_delete_stmt) {
92 78 : if ((res = sqlite3_prepare_v2(m_db, delete_sql.c_str(), -1, &m_delete_stmt, nullptr)) != SQLITE_OK) {
93 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
94 : }
95 : }
96 13037 : if (!m_cursor_stmt) {
97 78 : if ((res = sqlite3_prepare_v2(m_db, cursor_sql.c_str(), -1, &m_cursor_stmt, nullptr)) != SQLITE_OK) {
98 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements : %s\n", sqlite3_errstr(res)));
99 : }
100 : }
101 13037 : }
102 :
103 300 : SQLiteDatabase::~SQLiteDatabase()
104 400 : {
105 100 : Close();
106 200 : if (g_dbs_open.fetch_sub(1) == 1) {
107 167 : int ret = sqlite3_shutdown();
108 167 : if (ret != SQLITE_OK) {
109 100 : LogPrintf("SQLiteDatabase: Failed to shutdown SQLite: %s\n", sqlite3_errstr(ret));
110 100 : }
111 67 : }
112 300 : }
113 :
114 35 : bool SQLiteDatabase::Verify(bilingual_str& error)
115 : {
116 35 : if (!PrepareDirectory()) return false;
117 :
118 35 : sqlite3* db = nullptr;
119 35 : int ret = sqlite3_open_v2(m_file_path.c_str(), &db, SQLITE_OPEN_READONLY, nullptr);
120 35 : if (ret == SQLITE_NOTFOUND) {
121 0 : sqlite3_close(db);
122 0 : return true; // Return true if the file doesn't exist
123 35 : } else if (ret != SQLITE_OK) {
124 0 : sqlite3_close(db);
125 0 : error = strprintf(_("SQLiteDatabase: Failed to verify database: %s"), sqlite3_errstr(ret));
126 0 : return false;
127 : }
128 :
129 : // Check the application ID matches our network magic
130 35 : sqlite3_stmt* app_id_stmt;
131 35 : ret = sqlite3_prepare_v2(db, "PRAGMA application_id", -1, &app_id_stmt, nullptr);
132 35 : if (ret != SQLITE_OK) {
133 0 : sqlite3_finalize(app_id_stmt);
134 0 : sqlite3_close(db);
135 0 : error = strprintf(_("SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s"), sqlite3_errstr(ret));
136 0 : return false;
137 : }
138 35 : ret = sqlite3_step(app_id_stmt);
139 35 : if (ret != SQLITE_ROW) {
140 0 : sqlite3_finalize(app_id_stmt);
141 0 : sqlite3_close(db);
142 0 : error = strprintf(_("SQLiteDatabase: Failed to fetch the application id: %s"), sqlite3_errstr(ret));
143 0 : return false;
144 : }
145 35 : uint32_t app_id = (uint32_t)sqlite3_column_int(app_id_stmt, 0);
146 35 : sqlite3_finalize(app_id_stmt);
147 35 : uint32_t net_magic = ReadBE32(Params().MessageStart());
148 35 : if (app_id != net_magic) {
149 0 : sqlite3_close(db);
150 0 : error = strprintf(_("SQLiteDatabase: Unexpected application id. Expected %u, got %u"), net_magic, app_id);
151 0 : return false;
152 : }
153 :
154 : // Check our schema version
155 35 : sqlite3_stmt* user_ver_stmt;
156 35 : ret = sqlite3_prepare_v2(db, "PRAGMA user_version", -1, &user_ver_stmt, nullptr);
157 35 : if (ret != SQLITE_OK) {
158 0 : sqlite3_finalize(user_ver_stmt);
159 0 : sqlite3_close(db);
160 0 : error = strprintf(_("SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s"), sqlite3_errstr(ret));
161 0 : return false;
162 : }
163 35 : ret = sqlite3_step(user_ver_stmt);
164 35 : if (ret != SQLITE_ROW) {
165 0 : sqlite3_finalize(user_ver_stmt);
166 0 : sqlite3_close(db);
167 0 : error = strprintf(_("SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s"), sqlite3_errstr(ret));
168 0 : return false;
169 : }
170 35 : int32_t user_ver = sqlite3_column_int(user_ver_stmt, 0);
171 35 : sqlite3_finalize(user_ver_stmt);
172 35 : if (user_ver != WALLET_SCHEMA_VERSION) {
173 0 : sqlite3_close(db);
174 0 : error = strprintf(_("SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported"), user_ver, WALLET_SCHEMA_VERSION);
175 0 : return false;
176 : }
177 :
178 35 : sqlite3_stmt* stmt;
179 35 : ret = sqlite3_prepare_v2(db, "PRAGMA integrity_check", -1, &stmt, nullptr);
180 35 : if (ret != SQLITE_OK) {
181 0 : sqlite3_finalize(stmt);
182 0 : sqlite3_close(db);
183 0 : error = strprintf(_("SQLiteDatabase: Failed to verify database: %s"), sqlite3_errstr(ret));
184 0 : return false;
185 : }
186 : while (true) {
187 70 : ret = sqlite3_step(stmt);
188 70 : if (ret == SQLITE_DONE) {
189 : break;
190 35 : } else if (ret != SQLITE_ROW) {
191 0 : error = strprintf(_("SQLiteDatabase: Failed to verify database: %s"), sqlite3_errstr(ret));
192 0 : break;
193 : }
194 35 : const char* msg = (const char*)sqlite3_column_text(stmt, 0);
195 35 : if (!msg) {
196 0 : error = strprintf(_("SQLiteDatabase: Failed to verify database: %s"), sqlite3_errstr(ret));
197 0 : break;
198 : }
199 35 : std::string str_msg(msg);
200 35 : if (str_msg == "ok") {
201 35 : continue;
202 : }
203 0 : error += Untranslated("\n" + str_msg);
204 35 : }
205 35 : sqlite3_finalize(stmt);
206 35 : sqlite3_close(db);
207 35 : return error.original.empty();
208 35 : }
209 :
210 13037 : void SQLiteDatabase::Open(const char* mode)
211 : {
212 13037 : if (!PrepareDirectory()) {
213 0 : throw std::runtime_error("Cannot obtain a lock on wallet directory");
214 : }
215 :
216 13037 : bool read_only = (!strchr(mode, '+') && !strchr(mode, 'w'));
217 :
218 13037 : bool create = strchr(mode, 'c') != nullptr;
219 : int flags;
220 13037 : if (read_only) {
221 : flags = SQLITE_OPEN_READONLY;
222 0 : } else {
223 : flags = SQLITE_OPEN_READWRITE;
224 : }
225 13037 : if (create) {
226 78 : flags |= SQLITE_OPEN_CREATE;
227 78 : }
228 13037 : if (m_mock) {
229 0 : flags |= SQLITE_OPEN_MEMORY; // In memory database for mock db
230 0 : }
231 :
232 13037 : if (m_db == nullptr) {
233 78 : sqlite3* db = nullptr;
234 78 : int ret = sqlite3_open_v2(m_file_path.c_str(), &db, flags, nullptr);
235 78 : if (ret != SQLITE_OK) {
236 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to open database: %s\n", sqlite3_errstr(ret)));
237 : }
238 : // TODO: Maybe(?) Check the file wasn't copied and a duplicate opened
239 :
240 78 : if (create) {
241 : bool table_exists;
242 : // Check that the main table exists
243 78 : sqlite3_stmt* check_main_stmt;
244 78 : std::string check_main = "SELECT name FROM sqlite_master WHERE type='table' AND name='main'";
245 78 : ret = sqlite3_prepare_v2(db, check_main.c_str(), -1, &check_main_stmt, nullptr);
246 78 : if (ret != SQLITE_OK) {
247 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to prepare statement to check table existence: %s\n", sqlite3_errstr(ret)));
248 : }
249 78 : ret = sqlite3_step(check_main_stmt);
250 78 : if (sqlite3_finalize(check_main_stmt) != SQLITE_OK) {
251 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to finalize statement checking table existence: %s\n", sqlite3_errstr(ret)));
252 : }
253 78 : if (ret == SQLITE_DONE) {
254 : table_exists = false;
255 78 : } else if (ret == SQLITE_ROW) {
256 : table_exists = true;
257 : } else {
258 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to execute statement to check table existence: %s\n", sqlite3_errstr(ret)));
259 : }
260 :
261 78 : if (!table_exists) {
262 : // Make the table for our key-value pairs
263 43 : std::string create_stmt = "CREATE TABLE main(key BLOB PRIMARY KEY, value BLOB)";
264 43 : ret = sqlite3_exec(db, create_stmt.c_str(), nullptr, nullptr, nullptr);
265 43 : if (ret != SQLITE_OK) {
266 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to create new database: %s\n", sqlite3_errstr(ret)));
267 : }
268 43 : }
269 :
270 : // Enable fullfysnc for the platforms that use it
271 78 : std::string fullfsync_stmt = "PRAGMA fullfsync = true";
272 78 : ret = sqlite3_exec(db, fullfsync_stmt.c_str(), nullptr, nullptr, nullptr);
273 78 : if (ret != SQLITE_OK) {
274 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to enable fullfsync: %s\n", sqlite3_errstr(ret)));
275 : }
276 :
277 : // Set the application id
278 78 : uint32_t app_id = ReadBE32(Params().MessageStart());
279 78 : std::string set_app_id = strprintf("PRAGMA application_id = %d", (int32_t)app_id);
280 78 : ret = sqlite3_exec(db, set_app_id.c_str(), nullptr, nullptr, nullptr);
281 78 : if (ret != SQLITE_OK) {
282 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to set the application id: %s\n", sqlite3_errstr(ret)));
283 : }
284 :
285 : // Set the user version
286 78 : std::string set_user_ver = strprintf("PRAGMA user_version = %d", WALLET_SCHEMA_VERSION);
287 78 : ret = sqlite3_exec(db, set_user_ver.c_str(), nullptr, nullptr, nullptr);
288 78 : if (ret != SQLITE_OK) {
289 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to set the wallet schema version: %s\n", sqlite3_errstr(ret)));
290 : }
291 78 : }
292 :
293 78 : m_db = db;
294 13037 : } else if (!read_only && sqlite3_db_readonly(m_db, "main") != 0) {
295 0 : throw std::runtime_error(strprintf("SQLiteDatabase: SQLiteBatch requested read-write permission but database only has readonly"));
296 : }
297 13037 : SetupSQLStatements();
298 13037 : }
299 :
300 4 : bool SQLiteDatabase::Rewrite(const char* skip)
301 : {
302 4 : while (true) {
303 4 : if (m_refcount == 0) {
304 : break;
305 : }
306 0 : UninterruptibleSleep(std::chrono::milliseconds{100});
307 : }
308 :
309 : // Rewrite the database using the VACUUM command: https://sqlite.org/lang_vacuum.html
310 4 : int ret = sqlite3_exec(m_db, "VACUUM", nullptr, nullptr, nullptr);
311 4 : return ret == SQLITE_OK;
312 : }
313 :
314 95 : bool SQLiteDatabase::PeriodicFlush()
315 : {
316 95 : return true;
317 : }
318 :
319 1 : bool SQLiteDatabase::Backup(const std::string& dest) const
320 : {
321 1 : sqlite3* db_copy;
322 1 : int res = sqlite3_open(dest.c_str(), &db_copy);
323 1 : if (res != SQLITE_OK) {
324 0 : sqlite3_close(db_copy);
325 0 : return false;
326 : }
327 1 : sqlite3_backup* backup = sqlite3_backup_init(db_copy, "main", m_db, "main");
328 1 : if (!backup) {
329 0 : sqlite3_backup_finish(backup);
330 0 : sqlite3_close(db_copy);
331 0 : return false;
332 : }
333 : // Copy all of the pages using -1
334 1 : res = sqlite3_backup_step(backup, -1);
335 1 : if (res != SQLITE_DONE) {
336 : sqlite3_backup_finish(backup);
337 0 : sqlite3_close(db_copy);
338 0 : return false;
339 : }
340 : res = sqlite3_backup_finish(backup);
341 1 : sqlite3_close(db_copy);
342 1 : return res == SQLITE_OK;
343 1 : }
344 :
345 156 : void SQLiteDatabase::Close()
346 : {
347 156 : if (!m_db) return;
348 :
349 78 : assert(m_refcount == 0);
350 :
351 : // Free all of the prepared statements
352 78 : sqlite3_finalize(m_read_stmt);
353 78 : sqlite3_finalize(m_insert_stmt);
354 78 : sqlite3_finalize(m_overwrite_stmt);
355 78 : sqlite3_finalize(m_delete_stmt);
356 78 : sqlite3_finalize(m_cursor_stmt);
357 :
358 78 : int res = sqlite3_close(m_db);
359 78 : if (res != SQLITE_OK) {
360 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to close database: %s\n", sqlite3_errstr(res)));
361 : }
362 78 : m_db = nullptr;
363 :
364 78 : UnlockDirectory(m_dir_path, ".walletlock");
365 156 : }
366 :
367 134 : void SQLiteDatabase::Flush() {}
368 :
369 4 : void SQLiteDatabase::ReloadDbEnv() {}
370 :
371 13037 : void SQLiteDatabase::RemoveRef()
372 : {
373 13037 : m_refcount--;
374 13037 : }
375 :
376 13037 : void SQLiteDatabase::AddRef()
377 : {
378 13037 : m_refcount++;
379 13037 : }
380 :
381 13037 : std::unique_ptr<DatabaseBatch> SQLiteDatabase::MakeBatch(const char* mode, bool flush_on_close)
382 : {
383 : // We ignore flush_on_close because we don't do manual flushing for SQLite
384 13037 : return MakeUnique<SQLiteBatch>(*this, mode);
385 : }
386 :
387 26074 : SQLiteBatch::SQLiteBatch(SQLiteDatabase& database, const char* mode)
388 13037 : : m_database(database)
389 26074 : {
390 13037 : m_read_only = (!strchr(mode, '+') && !strchr(mode, 'w'));
391 13037 : m_database.AddRef();
392 13037 : m_database.Open(mode);
393 26074 : }
394 :
395 6 : void SQLiteBatch::Flush() {}
396 :
397 13037 : void SQLiteBatch::Close()
398 : {
399 13037 : if (m_database.m_db && sqlite3_get_autocommit(m_database.m_db) == 0) {
400 0 : TxnAbort();
401 0 : }
402 13037 : m_database.RemoveRef();
403 13037 : }
404 :
405 304 : bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value)
406 : {
407 304 : if (!m_database.m_db) return false;
408 304 : assert(m_database.m_read_stmt);
409 :
410 : // Bind: leftmost parameter in statement is index 1
411 304 : int res = sqlite3_bind_blob(m_database.m_read_stmt, 1, key.data(), key.size(), SQLITE_STATIC);
412 304 : if (res != SQLITE_OK) {
413 0 : sqlite3_clear_bindings(m_database.m_read_stmt);
414 0 : sqlite3_reset(m_database.m_read_stmt);
415 0 : return false;
416 : }
417 304 : res = sqlite3_step(m_database.m_read_stmt);
418 304 : if (res != SQLITE_ROW) {
419 121 : sqlite3_clear_bindings(m_database.m_read_stmt);
420 121 : sqlite3_reset(m_database.m_read_stmt);
421 121 : return false;
422 : }
423 : // Leftmost column in result is index 0
424 183 : const char* data = (const char*)sqlite3_column_blob(m_database.m_read_stmt, 0);
425 183 : int data_size = sqlite3_column_bytes(m_database.m_read_stmt, 0);
426 183 : value.write(data, data_size);
427 :
428 183 : sqlite3_clear_bindings(m_database.m_read_stmt);
429 183 : sqlite3_reset(m_database.m_read_stmt);
430 : return true;
431 304 : }
432 :
433 16449 : bool SQLiteBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite)
434 : {
435 16449 : if (!m_database.m_db) return false;
436 16449 : if (m_read_only) assert(!"Write called on database in read-only mode");
437 16449 : assert(m_database.m_insert_stmt && m_database.m_overwrite_stmt);
438 :
439 : sqlite3_stmt* stmt;
440 16449 : if (overwrite) {
441 16174 : stmt = m_database.m_overwrite_stmt;
442 16174 : } else {
443 275 : stmt = m_database.m_insert_stmt;
444 : }
445 :
446 : // Bind: leftmost parameter in statement is index 1
447 : // Insert index 1 is key, 2 is value
448 16449 : int res = sqlite3_bind_blob(stmt, 1, key.data(), key.size(), SQLITE_STATIC);
449 16449 : if (res != SQLITE_OK) {
450 0 : sqlite3_clear_bindings(stmt);
451 0 : sqlite3_reset(stmt);
452 0 : return false;
453 : }
454 16449 : res = sqlite3_bind_blob(stmt, 2, value.data(), value.size(), SQLITE_STATIC);
455 16449 : if (res != SQLITE_OK) {
456 0 : sqlite3_clear_bindings(stmt);
457 0 : sqlite3_reset(stmt);
458 0 : return false;
459 : }
460 :
461 : // Execute
462 16449 : res = sqlite3_step(stmt);
463 16449 : sqlite3_clear_bindings(stmt);
464 16449 : sqlite3_reset(stmt);
465 16449 : return res == SQLITE_DONE;
466 16449 : }
467 :
468 51 : bool SQLiteBatch::EraseKey(CDataStream&& key)
469 : {
470 51 : if (!m_database.m_db) return false;
471 51 : if (m_read_only) assert(!"Erase called on database in read-only mode");
472 51 : assert(m_database.m_delete_stmt);
473 :
474 : // Bind: leftmost parameter in statement is index 1
475 51 : int res = sqlite3_bind_blob(m_database.m_delete_stmt, 1, key.data(), key.size(), SQLITE_STATIC);
476 51 : if (res != SQLITE_OK) {
477 0 : sqlite3_clear_bindings(m_database.m_delete_stmt);
478 0 : sqlite3_reset(m_database.m_delete_stmt);
479 0 : return false;
480 : }
481 :
482 : // Execute
483 51 : res = sqlite3_step(m_database.m_delete_stmt);
484 51 : sqlite3_clear_bindings(m_database.m_delete_stmt);
485 51 : sqlite3_reset(m_database.m_delete_stmt);
486 51 : return res == SQLITE_DONE;
487 51 : }
488 :
489 0 : bool SQLiteBatch::HasKey(CDataStream&& key)
490 : {
491 0 : if (!m_database.m_db) return false;
492 0 : assert(m_database.m_read_stmt);
493 :
494 : // Bind: leftmost parameter in statement is index 1
495 : bool ret = false;
496 0 : int res = sqlite3_bind_blob(m_database.m_read_stmt, 1, key.data(), key.size(), SQLITE_STATIC);
497 0 : if (res == SQLITE_OK) {
498 0 : res = sqlite3_step(m_database.m_read_stmt);
499 0 : if (res == SQLITE_ROW) {
500 : ret = true;
501 0 : }
502 : }
503 :
504 0 : sqlite3_clear_bindings(m_database.m_read_stmt);
505 0 : sqlite3_reset(m_database.m_read_stmt);
506 0 : return ret;
507 0 : }
508 :
509 78 : bool SQLiteBatch::StartCursor()
510 : {
511 78 : assert(!m_cursor_init);
512 78 : if (!m_database.m_db) return false;
513 78 : m_cursor_init = true;
514 78 : return true;
515 78 : }
516 :
517 2906 : bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete)
518 : {
519 2906 : complete = false;
520 :
521 2906 : if (!m_cursor_init) return false;
522 :
523 2906 : int res = sqlite3_step(m_database.m_cursor_stmt);
524 2906 : if (res == SQLITE_DONE) {
525 78 : complete = true;
526 78 : return true;
527 2828 : } else if (res != SQLITE_ROW) {
528 0 : return false;
529 : }
530 :
531 : // Leftmost column in result is index 0
532 2828 : const char* key_data = (const char*)sqlite3_column_blob(m_database.m_cursor_stmt, 0);
533 2828 : int key_data_size = sqlite3_column_bytes(m_database.m_cursor_stmt, 0);
534 2828 : key.write(key_data, key_data_size);
535 2828 : const char* value_data = (const char*)sqlite3_column_blob(m_database.m_cursor_stmt, 1);
536 2828 : int value_data_size = sqlite3_column_bytes(m_database.m_cursor_stmt, 1);
537 2828 : value.write(value_data, value_data_size);
538 : return true;
539 2906 : }
540 :
541 78 : void SQLiteBatch::CloseCursor()
542 : {
543 78 : sqlite3_reset(m_database.m_cursor_stmt);
544 78 : m_cursor_init = false;
545 78 : }
546 :
547 4 : bool SQLiteBatch::TxnBegin()
548 : {
549 4 : if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) == 0) return false;
550 4 : int res = sqlite3_exec(m_database.m_db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
551 4 : return res == SQLITE_OK;
552 4 : }
553 :
554 4 : bool SQLiteBatch::TxnCommit()
555 : {
556 4 : if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) != 0) return false;
557 4 : int res = sqlite3_exec(m_database.m_db, "COMMIT TRANSACTION", nullptr, nullptr, nullptr);
558 4 : return res == SQLITE_OK;
559 4 : }
560 :
561 0 : bool SQLiteBatch::TxnAbort()
562 : {
563 0 : if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) != 0) return false;
564 0 : int res = sqlite3_exec(m_database.m_db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr);
565 0 : return res == SQLITE_OK;
566 0 : }
567 :
568 959 : bool ExistsSQLiteDatabase(const fs::path& path)
569 : {
570 959 : fs::path file = path / DATABASE_FILENAME;
571 959 : return fs::symlink_status(file).type() == fs::regular_file && IsSQLiteFile(file);
572 959 : }
573 :
574 100 : std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
575 : {
576 100 : fs::path file = path / DATABASE_FILENAME;
577 100 : auto db = MakeUnique<SQLiteDatabase>(path, file);
578 100 : if (options.verify && fs::is_regular_file(file) && !db->Verify(error)) {
579 0 : status = DatabaseStatus::FAILED_VERIFY;
580 0 : return nullptr;
581 : }
582 100 : return db;
583 100 : }
584 :
585 100 : std::string SQLiteDatabaseVersion()
586 : {
587 100 : return std::string(sqlite3_libversion());
588 : }
589 :
590 500 : bool IsSQLiteFile(const fs::path& path)
591 : {
592 500 : if (!fs::exists(path)) return false;
593 :
594 : // A SQLite Database file is at least 512 bytes.
595 500 : boost::system::error_code ec;
596 500 : auto size = fs::file_size(path, ec);
597 500 : if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
598 500 : if (size < 512) return false;
599 :
600 500 : fsbridge::ifstream file(path, std::ios::binary);
601 500 : if (!file.is_open()) return false;
602 :
603 : // Magic is at beginning and is 16 bytes long
604 500 : char magic[16];
605 500 : file.read(magic, 16);
606 :
607 : // Application id is at offset 68 and 4 bytes long
608 500 : file.seekg(68, std::ios::beg);
609 500 : char app_id[4];
610 500 : file.read(app_id, 4);
611 :
612 500 : file.close();
613 :
614 : // Check the magic, see https://sqlite.org/fileformat2.html
615 500 : std::string magic_str(magic);
616 500 : if (magic_str != std::string("SQLite format 3")) {
617 443 : return false;
618 : }
619 :
620 : // Check the application id matches our network magic
621 57 : return memcmp(Params().MessageStart(), app_id, 4) == 0;
622 500 : }
|