From 727e6b2a4ee5abb7f2dcbc9f7778291908dc28ad Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 26 May 2020 20:54:00 -0400 Subject: Implement SQLiteDatabase::Verify --- src/wallet/sqlite.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/wallet/sqlite.h | 2 ++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index f9c4dfb2a5..bfdd859162 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -109,6 +109,44 @@ void SQLiteDatabase::Cleanup() noexcept } } +bool SQLiteDatabase::Verify(bilingual_str& error) +{ + assert(m_db); + + sqlite3_stmt* stmt{nullptr}; + ret = sqlite3_prepare_v2(m_db, "PRAGMA integrity_check", -1, &stmt, nullptr); + if (ret != SQLITE_OK) { + sqlite3_finalize(stmt); + error = strprintf(_("SQLiteDatabase: Failed to prepare statement to verify database: %s"), sqlite3_errstr(ret)); + return false; + } + while (true) { + ret = sqlite3_step(stmt); + if (ret == SQLITE_DONE) { + break; + } + if (ret != SQLITE_ROW) { + error = strprintf(_("SQLiteDatabase: Failed to execute statement to verify database: %s"), sqlite3_errstr(ret)); + break; + } + const char* msg = (const char*)sqlite3_column_text(stmt, 0); + if (!msg) { + error = strprintf(_("SQLiteDatabase: Failed to read database verification error: %s"), sqlite3_errstr(ret)); + break; + } + std::string str_msg(msg); + if (str_msg == "ok") { + continue; + } + if (error.empty()) { + error = _("Failed to verify database") + Untranslated("\n"); + } + error += Untranslated(strprintf("%s\n", str_msg)); + } + sqlite3_finalize(stmt); + return error.empty(); +} + void SQLiteDatabase::Open() { int flags = SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; @@ -468,7 +506,19 @@ bool ExistsSQLiteDatabase(const fs::path& path) std::unique_ptr MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) { - return MakeUnique(path, path / DATABASE_FILENAME); + const fs::path file = path / DATABASE_FILENAME; + try { + auto db = MakeUnique(path, file); + if (options.verify && !db->Verify(error)) { + status = DatabaseStatus::FAILED_VERIFY; + return nullptr; + } + return db; + } catch (const std::runtime_error& e) { + status = DatabaseStatus::FAILED_LOAD; + error.original = e.what(); + return nullptr; + } } std::string SQLiteDatabaseVersion() diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index dca6560abb..c6a3f7f503 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -71,6 +71,8 @@ public: ~SQLiteDatabase(); + bool Verify(bilingual_str& error); + /** Open the database if it is not already opened */ void Open() override; -- cgit v1.2.3