diff --git a/wallet/db.c b/wallet/db.c index d3b3728a2..4e0346b50 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -604,6 +604,41 @@ struct db_stmt *db_prepare_v2_(const char *location, struct db *db, #define db_prepare_v2(db,query) \ db_prepare_v2_(__FILE__ ":" stringify(__LINE__), db, query) +bool db_step(struct db_stmt *stmt) +{ + assert(stmt->executed); + return stmt->db->config->step_fn(stmt); +} + +u64 db_column_u64(struct db_stmt *stmt, int col) +{ + return stmt->db->config->column_u64_fn(stmt, col); +} + +int db_column_int(struct db_stmt *stmt, int col) +{ + return stmt->db->config->column_int_fn(stmt, col); +} + +size_t db_column_bytes(struct db_stmt *stmt, int col) +{ + return stmt->db->config->column_bytes_fn(stmt, col); +} + +int db_column_is_null(struct db_stmt *stmt, int col) +{ + return stmt->db->config->column_is_null_fn(stmt, col); +} + +const void *db_column_blob(struct db_stmt *stmt, int col) +{ + return stmt->db->config->column_blob_fn(stmt, col); +} + +const unsigned char *db_column_text(struct db_stmt *stmt, int col) +{ + return stmt->db->config->column_blob_fn(stmt, col); +} bool db_select_step_(const char *location, struct db *db, struct sqlite3_stmt *stmt) { @@ -1368,3 +1403,14 @@ bool db_exec_prepared_v2(struct db_stmt *stmt TAKES) return ret; } + +bool db_query_prepared(struct db_stmt *stmt) +{ + /* Make sure we don't accidentally execute a modifying query using a + * read-only path. */ + bool ret; + assert(stmt->query->readonly); + ret = stmt->db->config->query_fn(stmt); + stmt->executed = true; + return ret; +} diff --git a/wallet/db.h b/wallet/db.h index bcd29b248..8b388ee59 100644 --- a/wallet/db.h +++ b/wallet/db.h @@ -249,6 +249,14 @@ void db_bind_blob(struct db_stmt *stmt, int pos, u8 *val, size_t len); void db_bind_text(struct db_stmt *stmt, int pos, const char *val); bool db_exec_prepared_v2(struct db_stmt *stmt TAKES); +bool db_step(struct db_stmt *stmt); +u64 db_column_u64(struct db_stmt *stmt, int col); +int db_column_int(struct db_stmt *stmt, int col); +size_t db_column_bytes(struct db_stmt *stmt, int col); +int db_column_is_null(struct db_stmt *stmt, int col); +const void* db_column_blob(struct db_stmt *stmt, int col); +const unsigned char *db_column_text(struct db_stmt *stmt, int col); +bool db_query_prepared(struct db_stmt *stmt); struct db_stmt *db_prepare_v2_(const char *location, struct db *db, const char *query_id); diff --git a/wallet/db_common.h b/wallet/db_common.h index e7e176518..5947a7ccc 100644 --- a/wallet/db_common.h +++ b/wallet/db_common.h @@ -111,6 +111,17 @@ struct db_config { * destructor of `struct db_stmt`, before clearing the db_stmt * itself. */ void (*stmt_free_fn)(struct db_stmt *db_stmt); + + /* Column access in a row. Only covers the primitives, others need to + * use these internally to translate (hence the non-allocating + * column_{text,blob}_fn since most other types want in place + * assignment. */ + bool (*column_is_null_fn)(struct db_stmt *stmt, int col); + u64 (*column_u64_fn)(struct db_stmt *stmt, int col); + size_t (*column_bytes_fn)(struct db_stmt *stmt, int col); + const void *(*column_blob_fn)(struct db_stmt *stmt, int col); + const unsigned char *(*column_text_fn)(struct db_stmt *stmt, int col); + s64 (*column_int_fn)(struct db_stmt *stmt, int col); }; /* Provide a way for DB backends to register themselves */ diff --git a/wallet/db_sqlite3.c b/wallet/db_sqlite3.c index fe2d68452..189b0e751 100644 --- a/wallet/db_sqlite3.c +++ b/wallet/db_sqlite3.c @@ -124,6 +124,42 @@ static bool db_sqlite3_commit_tx(struct db *db) return true; } +static bool db_sqlite3_column_is_null(struct db_stmt *stmt, int col) +{ + sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt; + return sqlite3_column_type(s, col) == SQLITE_NULL; +} + +static u64 db_sqlite3_column_u64(struct db_stmt *stmt, int col) +{ + sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt; + return sqlite3_column_int64(s, col); +} + +static s64 db_sqlite3_column_int(struct db_stmt *stmt, int col) +{ + sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt; + return sqlite3_column_int(s, col); +} + +static size_t db_sqlite3_column_bytes(struct db_stmt *stmt, int col) +{ + sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt; + return sqlite3_column_bytes(s, col); +} + +static const void *db_sqlite3_column_blob(struct db_stmt *stmt, int col) +{ + sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt; + return sqlite3_column_blob(s, col); +} + +static const unsigned char *db_sqlite3_column_text(struct db_stmt *stmt, int col) +{ + sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt; + return sqlite3_column_text(s, col); +} + static void db_sqlite3_stmt_free(struct db_stmt *stmt) { if (stmt->inner_stmt) @@ -142,6 +178,13 @@ struct db_config db_sqlite3_config = { .begin_tx_fn = &db_sqlite3_begin_tx, .commit_tx_fn = &db_sqlite3_commit_tx, .stmt_free_fn = &db_sqlite3_stmt_free, + + .column_is_null_fn = &db_sqlite3_column_is_null, + .column_u64_fn = &db_sqlite3_column_u64, + .column_int_fn = &db_sqlite3_column_int, + .column_bytes_fn = &db_sqlite3_column_bytes, + .column_blob_fn = &db_sqlite3_column_blob, + .column_text_fn = &db_sqlite3_column_text, }; AUTODATA(db_backends, &db_sqlite3_config);