diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -17,6 +17,14 @@ private: SQLiteDatabase &m_database; + sqlite3_stmt *m_read_stmt{nullptr}; + sqlite3_stmt *m_insert_stmt{nullptr}; + sqlite3_stmt *m_overwrite_stmt{nullptr}; + sqlite3_stmt *m_delete_stmt{nullptr}; + sqlite3_stmt *m_cursor_stmt{nullptr}; + + void SetupSQLStatements(); + bool ReadKey(CDataStream &&key, CDataStream &value) override; bool WriteKey(CDataStream &&key, CDataStream &&value, bool overwrite = true) override; diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -66,6 +66,55 @@ } } +void SQLiteBatch::SetupSQLStatements() { + int res; + if (!m_read_stmt) { + if ((res = sqlite3_prepare_v2( + m_database.m_db, "SELECT value FROM main WHERE key = ?", -1, + &m_read_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf( + "SQLiteDatabase: Failed to setup SQL statements: %s\n", + sqlite3_errstr(res))); + } + } + if (!m_insert_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, + "INSERT INTO main VALUES(?, ?)", -1, + &m_insert_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf( + "SQLiteDatabase: Failed to setup SQL statements: %s\n", + sqlite3_errstr(res))); + } + } + if (!m_overwrite_stmt) { + if ((res = sqlite3_prepare_v2( + m_database.m_db, "INSERT or REPLACE into main values(?, ?)", + -1, &m_overwrite_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf( + "SQLiteDatabase: Failed to setup SQL statements: %s\n", + sqlite3_errstr(res))); + } + } + if (!m_delete_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, + "DELETE FROM main WHERE key = ?", -1, + &m_delete_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf( + "SQLiteDatabase: Failed to setup SQL statements: %s\n", + sqlite3_errstr(res))); + } + } + if (!m_cursor_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, + "SELECT key, value FROM main", -1, + &m_cursor_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf( + "SQLiteDatabase: Failed to setup SQL statements : %s\n", + sqlite3_errstr(res))); + } + } +} + SQLiteDatabase::~SQLiteDatabase() { Cleanup(); } @@ -213,6 +262,8 @@ SQLiteBatch::SQLiteBatch(SQLiteDatabase &database) : m_database(database) { // Make sure we have a db handle assert(m_database.m_db); + + SetupSQLStatements(); } void SQLiteBatch::Close() { @@ -227,6 +278,43 @@ "SQLiteBatch: Batch closed and failed to abort transaction\n"); } } + + // Free all of the prepared statements + int ret = sqlite3_finalize(m_read_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize read " + "statement: %s\n", + sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_insert_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize insert " + "statement: %s\n", + sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_overwrite_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize overwrite " + "statement: %s\n", + sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_delete_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize delete " + "statement: %s\n", + sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_cursor_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize cursor " + "statement: %s\n", + sqlite3_errstr(ret)); + } + m_read_stmt = nullptr; + m_insert_stmt = nullptr; + m_overwrite_stmt = nullptr; + m_delete_stmt = nullptr; + m_cursor_stmt = nullptr; } bool SQLiteBatch::ReadKey(CDataStream &&key, CDataStream &value) {