In my class which holds a SQLite database handle I have:
struct SQLitePreparedStatement
{
sqlite3_stmt* stmt = nullptr;
~SQLitePreparedStatement()
{
if (stmt)
sqlite3_finalize(stmt);
}
};
SQLitePreparedStatement create_table_statement{};
SQLitePreparedStatement exists_statement{};
SQLitePreparedStatement insert_statement{};
SQLitePreparedStatement insert_or_replace_statement{};
SQLitePreparedStatement get_value_statement{};
SQLitePreparedStatement remove_value_statement{};
SQLitePreparedStatement count_rows_prepared_stmt{};
SQLitePreparedStatement get_row_id_stmt{};
sqlite3* sqlite_db;
Until now I have simply called sqlite3_close on the database in the destructor, without calling finalize on the statements. I think this is wrong, and that you have to call finalize on each statement associated with the database handle BEFORE calling close on the database. This is why I wrapped the statements in a RAII struct. But if I call close on the database in the destructor this will happen BEFORE the statements have been destroyed. Is the solution here to wrap the database handle in yet another struct? And then make sure sqlite_db always comes BEFORE the statements in the declaration order and the statement destructors will run first. That's guaranteed, right? All of this seems very flimsy and prone to breakage.
sqlite3*handle has a member function for creating the RAII wrapper for the prepared statement, then order of initialization (and the automatic reverse order for destruction) comes easy and dependencies also become clear.