16
16
#include < sqlite3.h>
17
17
#include < stdint.h>
18
18
19
+ #include < optional>
19
20
#include < utility>
20
21
#include < vector>
21
22
@@ -35,6 +36,36 @@ static void ErrorLogCallback(void* arg, int code, const char* msg)
35
36
LogPrintf (" SQLite Error. Code: %d. Message: %s\n " , code, msg);
36
37
}
37
38
39
+ static std::optional<int > ReadPragmaInteger (sqlite3* db, const std::string& key, const std::string& description, bilingual_str& error)
40
+ {
41
+ std::string stmt_text = strprintf (" PRAGMA %s" , key);
42
+ sqlite3_stmt* pragma_read_stmt{nullptr };
43
+ int ret = sqlite3_prepare_v2 (db, stmt_text.c_str (), -1 , &pragma_read_stmt, nullptr );
44
+ if (ret != SQLITE_OK) {
45
+ sqlite3_finalize (pragma_read_stmt);
46
+ error = Untranslated (strprintf (" SQLiteDatabase: Failed to prepare the statement to fetch %s: %s" , description, sqlite3_errstr (ret)));
47
+ return std::nullopt;
48
+ }
49
+ ret = sqlite3_step (pragma_read_stmt);
50
+ if (ret != SQLITE_ROW) {
51
+ sqlite3_finalize (pragma_read_stmt);
52
+ error = Untranslated (strprintf (" SQLiteDatabase: Failed to fetch %s: %s" , description, sqlite3_errstr (ret)));
53
+ return std::nullopt;
54
+ }
55
+ int result = sqlite3_column_int (pragma_read_stmt, 0 );
56
+ sqlite3_finalize (pragma_read_stmt);
57
+ return result;
58
+ }
59
+
60
+ static void SetPragma (sqlite3* db, const std::string& key, const std::string& value, const std::string& err_msg)
61
+ {
62
+ std::string stmt_text = strprintf (" PRAGMA %s = %s" , key, value);
63
+ int ret = sqlite3_exec (db, stmt_text.c_str (), nullptr , nullptr , nullptr );
64
+ if (ret != SQLITE_OK) {
65
+ throw std::runtime_error (strprintf (" SQLiteDatabase: %s: %s\n " , err_msg, sqlite3_errstr (ret)));
66
+ }
67
+ }
68
+
38
69
SQLiteDatabase::SQLiteDatabase (const fs::path& dir_path, const fs::path& file_path, bool mock)
39
70
: WalletDatabase(), m_mock(mock), m_dir_path(dir_path.string()), m_file_path(file_path.string())
40
71
{
@@ -114,50 +145,26 @@ bool SQLiteDatabase::Verify(bilingual_str& error)
114
145
assert (m_db);
115
146
116
147
// Check the application ID matches our network magic
117
- sqlite3_stmt* app_id_stmt{nullptr };
118
- int ret = sqlite3_prepare_v2 (m_db, " PRAGMA application_id" , -1 , &app_id_stmt, nullptr );
119
- if (ret != SQLITE_OK) {
120
- sqlite3_finalize (app_id_stmt);
121
- error = strprintf (_ (" SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s" ), sqlite3_errstr (ret));
122
- return false ;
123
- }
124
- ret = sqlite3_step (app_id_stmt);
125
- if (ret != SQLITE_ROW) {
126
- sqlite3_finalize (app_id_stmt);
127
- error = strprintf (_ (" SQLiteDatabase: Failed to fetch the application id: %s" ), sqlite3_errstr (ret));
128
- return false ;
129
- }
130
- uint32_t app_id = static_cast <uint32_t >(sqlite3_column_int (app_id_stmt, 0 ));
131
- sqlite3_finalize (app_id_stmt);
148
+ auto read_result = ReadPragmaInteger (m_db, " application_id" , " the application id" , error);
149
+ if (!read_result.has_value ()) return false ;
150
+ uint32_t app_id = static_cast <uint32_t >(read_result.value ());
132
151
uint32_t net_magic = ReadBE32 (Params ().MessageStart ());
133
152
if (app_id != net_magic) {
134
153
error = strprintf (_ (" SQLiteDatabase: Unexpected application id. Expected %u, got %u" ), net_magic, app_id);
135
154
return false ;
136
155
}
137
156
138
157
// Check our schema version
139
- sqlite3_stmt* user_ver_stmt{nullptr };
140
- ret = sqlite3_prepare_v2 (m_db, " PRAGMA user_version" , -1 , &user_ver_stmt, nullptr );
141
- if (ret != SQLITE_OK) {
142
- sqlite3_finalize (user_ver_stmt);
143
- error = strprintf (_ (" SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s" ), sqlite3_errstr (ret));
144
- return false ;
145
- }
146
- ret = sqlite3_step (user_ver_stmt);
147
- if (ret != SQLITE_ROW) {
148
- sqlite3_finalize (user_ver_stmt);
149
- error = strprintf (_ (" SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s" ), sqlite3_errstr (ret));
150
- return false ;
151
- }
152
- int32_t user_ver = sqlite3_column_int (user_ver_stmt, 0 );
153
- sqlite3_finalize (user_ver_stmt);
158
+ read_result = ReadPragmaInteger (m_db, " user_version" , " sqlite wallet schema version" , error);
159
+ if (!read_result.has_value ()) return false ;
160
+ int32_t user_ver = read_result.value ();
154
161
if (user_ver != WALLET_SCHEMA_VERSION) {
155
162
error = strprintf (_ (" SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported" ), user_ver, WALLET_SCHEMA_VERSION);
156
163
return false ;
157
164
}
158
165
159
166
sqlite3_stmt* stmt{nullptr };
160
- ret = sqlite3_prepare_v2 (m_db, " PRAGMA integrity_check" , -1 , &stmt, nullptr );
167
+ int ret = sqlite3_prepare_v2 (m_db, " PRAGMA integrity_check" , -1 , &stmt, nullptr );
161
168
if (ret != SQLITE_OK) {
162
169
sqlite3_finalize (stmt);
163
170
error = strprintf (_ (" SQLiteDatabase: Failed to prepare statement to verify database: %s" ), sqlite3_errstr (ret));
@@ -213,12 +220,9 @@ void SQLiteDatabase::Open()
213
220
214
221
// Acquire an exclusive lock on the database
215
222
// First change the locking mode to exclusive
216
- int ret = sqlite3_exec (m_db, " PRAGMA locking_mode = exclusive" , nullptr , nullptr , nullptr );
217
- if (ret != SQLITE_OK) {
218
- throw std::runtime_error (strprintf (" SQLiteDatabase: Unable to change database locking mode to exclusive: %s\n " , sqlite3_errstr (ret)));
219
- }
223
+ SetPragma (m_db, " locking_mode" , " exclusive" , " Unable to change database locking mode to exclusive" );
220
224
// Now begin a transaction to acquire the exclusive lock. This lock won't be released until we close because of the exclusive locking mode.
221
- ret = sqlite3_exec (m_db, " BEGIN EXCLUSIVE TRANSACTION" , nullptr , nullptr , nullptr );
225
+ int ret = sqlite3_exec (m_db, " BEGIN EXCLUSIVE TRANSACTION" , nullptr , nullptr , nullptr );
222
226
if (ret != SQLITE_OK) {
223
227
throw std::runtime_error (" SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?\n " );
224
228
}
@@ -228,18 +232,12 @@ void SQLiteDatabase::Open()
228
232
}
229
233
230
234
// Enable fullfsync for the platforms that use it
231
- ret = sqlite3_exec (m_db, " PRAGMA fullfsync = true" , nullptr , nullptr , nullptr );
232
- if (ret != SQLITE_OK) {
233
- throw std::runtime_error (strprintf (" SQLiteDatabase: Failed to enable fullfsync: %s\n " , sqlite3_errstr (ret)));
234
- }
235
+ SetPragma (m_db, " fullfsync" , " true" , " Failed to enable fullfsync" );
235
236
236
237
if (gArgs .GetBoolArg (" -unsafesqlitesync" , false )) {
237
238
// Use normal synchronous mode for the journal
238
239
LogPrintf (" WARNING SQLite is configured to not wait for data to be flushed to disk. Data loss and corruption may occur.\n " );
239
- ret = sqlite3_exec (m_db, " PRAGMA synchronous = OFF" , nullptr , nullptr , nullptr );
240
- if (ret != SQLITE_OK) {
241
- throw std::runtime_error (strprintf (" SQLiteDatabase: Failed to set synchronous mode to OFF: %s\n " , sqlite3_errstr (ret)));
242
- }
240
+ SetPragma (m_db, " synchronous" , " OFF" , " Failed to set synchronous mode to OFF" );
243
241
}
244
242
245
243
// Make the table for our key-value pairs
@@ -271,18 +269,12 @@ void SQLiteDatabase::Open()
271
269
272
270
// Set the application id
273
271
uint32_t app_id = ReadBE32 (Params ().MessageStart ());
274
- std::string set_app_id = strprintf (" PRAGMA application_id = %d" , static_cast <int32_t >(app_id));
275
- ret = sqlite3_exec (m_db, set_app_id.c_str (), nullptr , nullptr , nullptr );
276
- if (ret != SQLITE_OK) {
277
- throw std::runtime_error (strprintf (" SQLiteDatabase: Failed to set the application id: %s\n " , sqlite3_errstr (ret)));
278
- }
272
+ SetPragma (m_db, " application_id" , strprintf (" %d" , static_cast <int32_t >(app_id)),
273
+ " Failed to set the application id" );
279
274
280
275
// Set the user version
281
- std::string set_user_ver = strprintf (" PRAGMA user_version = %d" , WALLET_SCHEMA_VERSION);
282
- ret = sqlite3_exec (m_db, set_user_ver.c_str (), nullptr , nullptr , nullptr );
283
- if (ret != SQLITE_OK) {
284
- throw std::runtime_error (strprintf (" SQLiteDatabase: Failed to set the wallet schema version: %s\n " , sqlite3_errstr (ret)));
285
- }
276
+ SetPragma (m_db, " user_version" , strprintf (" %d" , WALLET_SCHEMA_VERSION),
277
+ " Failed to set the wallet schema version" );
286
278
}
287
279
}
288
280
0 commit comments