// Copyright (c) 2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include static const char* const DATABASE_FILENAME = "wallet.dat"; static Mutex g_sqlite_mutex; static int g_sqlite_count GUARDED_BY(g_sqlite_mutex) = 0; static void ErrorLogCallback(void* arg, int code, const char* msg) { // From sqlite3_config() documentation for the SQLITE_CONFIG_LOG option: // "The void pointer that is the second argument to SQLITE_CONFIG_LOG is passed through as // the first parameter to the application-defined logger function whenever that function is // invoked." // Assert that this is the case: assert(arg == nullptr); LogPrintf("SQLite Error. Code: %d. Message: %s\n", code, msg); } SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, bool mock) : WalletDatabase(), m_mock(mock), m_dir_path(dir_path.string()), m_file_path(file_path.string()) { { LOCK(g_sqlite_mutex); LogPrintf("Using SQLite Version %s\n", SQLiteDatabaseVersion()); LogPrintf("Using wallet %s\n", m_dir_path); if (++g_sqlite_count == 1) { // Setup logging int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr); if (ret != SQLITE_OK) { throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret))); } } int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized if (ret != SQLITE_OK) { throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret))); } } try { Open(); } catch (const std::runtime_error&) { // If open fails, cleanup this object and rethrow the exception Cleanup(); throw; } } SQLiteDatabase::~SQLiteDatabase() { Cleanup(); } void SQLiteDatabase::Cleanup() noexcept { Close(); LOCK(g_sqlite_mutex); if (--g_sqlite_count == 0) { int ret = sqlite3_shutdown(); if (ret != SQLITE_OK) { LogPrintf("SQLiteDatabase: Failed to shutdown SQLite: %s\n", sqlite3_errstr(ret)); } } } void SQLiteDatabase::Open() { } bool SQLiteDatabase::Rewrite(const char* skip) { return false; } bool SQLiteDatabase::Backup(const std::string& dest) const { return false; } void SQLiteDatabase::Close() { } std::unique_ptr SQLiteDatabase::MakeBatch(bool flush_on_close) { return nullptr; } SQLiteBatch::SQLiteBatch(SQLiteDatabase& database) : m_database(database) { } void SQLiteBatch::Close() { } bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value) { return false; } bool SQLiteBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite) { return false; } bool SQLiteBatch::EraseKey(CDataStream&& key) { return false; } bool SQLiteBatch::HasKey(CDataStream&& key) { return false; } bool SQLiteBatch::StartCursor() { return false; } bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete) { return false; } void SQLiteBatch::CloseCursor() { } bool SQLiteBatch::TxnBegin() { return false; } bool SQLiteBatch::TxnCommit() { return false; } bool SQLiteBatch::TxnAbort() { return false; } bool ExistsSQLiteDatabase(const fs::path& path) { return false; } std::unique_ptr MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) { return MakeUnique(path, path / DATABASE_FILENAME); } std::string SQLiteDatabaseVersion() { return std::string(sqlite3_libversion()); }