diff --git a/wallet/db.c b/wallet/db.c index 8fb2adef6..efb850704 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -132,6 +132,38 @@ static void db_clear_error(struct db *db) db->err = tal_free(db->err); } +sqlite3_stmt *db_prepare_(const char *caller, struct db *db, const char *query) +{ + int err; + sqlite3_stmt *stmt; + if (db->in_transaction && db->err) + return NULL; + + db_clear_error(db); + err = sqlite3_prepare_v2(db->sql, query, -1, &stmt, NULL); + + if (err != SQLITE_OK) { + db->err = tal_fmt(db, "%s: %s: %s", caller, query, + sqlite3_errmsg(db->sql)); + } + return stmt; +} + +bool db_exec_prepared_(const char *caller, struct db *db, sqlite3_stmt *stmt) +{ + if (db->in_transaction && db->err) + return false; + db_clear_error(db); + + if (sqlite3_step(stmt) != SQLITE_DONE) { + db->err = + tal_fmt(db, "%s: %s", caller, sqlite3_errmsg(db->sql)); + return false; + } else { + return true; + } +} + bool PRINTF_FMT(3, 4) db_exec(const char *caller, struct db *db, const char *fmt, ...) { diff --git a/wallet/db.h b/wallet/db.h index c7e5bd3f7..4217f87bf 100644 --- a/wallet/db.h +++ b/wallet/db.h @@ -80,4 +80,34 @@ s64 db_get_intvar(struct db *db, char *varname, s64 defval); bool sqlite3_column_hexval(sqlite3_stmt *s, int col, void *dest, size_t destlen); +/** + * db_prepare -- Prepare a DB query/command + * + * Tiny wrapper around `sqlite3_prepare_v2` that checks and sets + * errors like `db_query` and `db_exec` do. It returns a statement + * `stmt` if the given query/command was successfully compiled into a + * statement, `NULL` otherwise. On failure `db->err` will be set with + * the human readable error. + * + * @db: Database to query/exec + * @query: The SQL statement to compile + */ +#define db_prepare(db,query) db_prepare_(__func__,db,query) +sqlite3_stmt *db_prepare_(const char *caller, struct db *db, const char *query); + +/** + * db_exec_prepared -- Execute a prepared statement + * + * After preparing a statement using `db_prepare`, and after binding + * all non-null variables using the `sqlite3_bind_*` functions, it can + * be executed with this function. It is a small, transaction-aware, + * wrapper around `sqlite3_step`, that also sets `db->err` if the + * execution fails. + * + * @db: The database to execute on + * @stmt: The prepared statement to execute + */ +#define db_exec_prepared(db,stmt) db_exec_prepared_(__func__,db,stmt) +bool db_exec_prepared_(const char *caller, struct db *db, sqlite3_stmt *stmt); + #endif /* WALLET_DB_H */