db: Implement the sqlite3 driver
This is the DB-specific counterpart to the previous commit. Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
parent
38601afd17
commit
50a1af8908
|
@ -1,11 +1,147 @@
|
|||
#include <wallet/db_common.h>
|
||||
#include "gen_db_sqlite3.c"
|
||||
#include <ccan/ccan/tal/str/str.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if HAVE_SQLITE3
|
||||
|
||||
static const char *db_sqlite3_expand(struct db_stmt *stmt)
|
||||
{
|
||||
#if HAVE_SQLITE3_EXPANDED_SQL
|
||||
sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt;
|
||||
const char *sql;
|
||||
char *expanded_sql;
|
||||
expanded_sql = sqlite3_expanded_sql(s);
|
||||
sql = tal_strdup(stmt, expanded_sql);
|
||||
sqlite3_free(expanded_sql);
|
||||
return sql;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *db_sqlite3_fmt_error(struct db_stmt *stmt)
|
||||
{
|
||||
return tal_fmt(stmt, "%s: %s: %s", stmt->location, stmt->query->query,
|
||||
sqlite3_errmsg(stmt->db->conn));
|
||||
}
|
||||
|
||||
static bool db_sqlite3_query(struct db_stmt *stmt)
|
||||
{
|
||||
sqlite3_stmt *s;
|
||||
sqlite3 *conn = (sqlite3*)stmt->db->conn;
|
||||
int err;
|
||||
|
||||
err = sqlite3_prepare_v2(conn, stmt->query->query, -1, &s, NULL);
|
||||
|
||||
for (size_t i=0; i<stmt->query->placeholders; i++) {
|
||||
struct db_binding *b = &stmt->bindings[i];
|
||||
|
||||
/* sqlite3 uses printf-like offsets, we don't... */
|
||||
int pos = i+1;
|
||||
switch (b->type) {
|
||||
case DB_BINDING_UNINITIALIZED:
|
||||
db_fatal("DB binding not initialized: position=%zu, "
|
||||
"query=\"%s\n",
|
||||
i, stmt->query->query);
|
||||
case DB_BINDING_UINT64:
|
||||
sqlite3_bind_int64(s, pos, b->v.u64);
|
||||
break;
|
||||
case DB_BINDING_INT:
|
||||
sqlite3_bind_int(s, pos, b->v.i);
|
||||
break;
|
||||
case DB_BINDING_BLOB:
|
||||
sqlite3_bind_blob(s, pos, b->v.blob, b->len,
|
||||
SQLITE_TRANSIENT);
|
||||
break;
|
||||
case DB_BINDING_TEXT:
|
||||
sqlite3_bind_text(s, pos, b->v.text, b->len,
|
||||
SQLITE_TRANSIENT);
|
||||
break;
|
||||
case DB_BINDING_NULL:
|
||||
sqlite3_bind_null(s, pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err != SQLITE_OK) {
|
||||
tal_free(stmt->error);
|
||||
stmt->error = db_sqlite3_fmt_error(stmt);
|
||||
return false;
|
||||
}
|
||||
|
||||
stmt->inner_stmt = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool db_sqlite3_exec(struct db_stmt *stmt)
|
||||
{
|
||||
int err;
|
||||
if (!db_sqlite3_query(stmt)) {
|
||||
/* If the prepare step caused an error we hand it up. */
|
||||
return false;
|
||||
}
|
||||
|
||||
err = sqlite3_step(stmt->inner_stmt);
|
||||
if (err != SQLITE_DONE) {
|
||||
tal_free(stmt->error);
|
||||
stmt->error = db_sqlite3_fmt_error(stmt);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool db_sqlite3_step(struct db_stmt *stmt)
|
||||
{
|
||||
sqlite3_stmt *s = (sqlite3_stmt*)stmt->inner_stmt;
|
||||
return sqlite3_step(s) == SQLITE_ROW;
|
||||
}
|
||||
|
||||
static bool db_sqlite3_begin_tx(struct db *db)
|
||||
{
|
||||
int err;
|
||||
char *errmsg;
|
||||
err = sqlite3_exec(db->conn, "BEGIN TRANSACTION;", NULL, NULL, &errmsg);
|
||||
if (err != SQLITE_OK) {
|
||||
db->error = tal_fmt(db, "Failed to begin a transaction: %s", errmsg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool db_sqlite3_commit_tx(struct db *db)
|
||||
{
|
||||
int err;
|
||||
char *errmsg;
|
||||
err = sqlite3_exec(db->conn, "COMMIT;", NULL, NULL, &errmsg);
|
||||
if (err != SQLITE_OK) {
|
||||
db->error = tal_fmt(db, "Failed to begin a transaction: %s", errmsg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void db_sqlite3_stmt_free(struct db_stmt *stmt)
|
||||
{
|
||||
if (stmt->inner_stmt)
|
||||
sqlite3_finalize(stmt->inner_stmt);
|
||||
tal_free(stmt);
|
||||
}
|
||||
|
||||
struct db_config db_sqlite3_config = {
|
||||
.name = "sqlite3",
|
||||
.queries = db_sqlite3_queries,
|
||||
.num_queries = DB_SQLITE3_QUERY_COUNT,
|
||||
.expand_fn = &db_sqlite3_expand,
|
||||
.exec_fn = &db_sqlite3_exec,
|
||||
.query_fn = &db_sqlite3_query,
|
||||
.step_fn = &db_sqlite3_step,
|
||||
.begin_tx_fn = &db_sqlite3_begin_tx,
|
||||
.commit_tx_fn = &db_sqlite3_commit_tx,
|
||||
.stmt_free_fn = &db_sqlite3_stmt_free,
|
||||
};
|
||||
|
||||
AUTODATA(db_backends, &db_sqlite3_config);
|
||||
|
|
Loading…
Reference in New Issue