#include #include "gen_db_sqlite3.c" #include #include #include #include #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; iquery->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); #endif