Skip to content

Commit

Permalink
db: catch SQL errors unless we're expecting them.
Browse files Browse the repository at this point in the history
I couldn't figure out why my new SQL query was returning 0 rows,
and it was because we were ignoring errors.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Apr 6, 2023
1 parent d2176e3 commit 9bcf28a
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 9 deletions.
6 changes: 3 additions & 3 deletions db/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int db_get_version(struct db *db)
* table that doesn't exist yet, so we need to terminate and restart
* the DB transaction.
*/
if (!db_query_prepared(stmt)) {
if (!db_query_prepared_canfail(stmt)) {
db_commit_transaction(stmt->db);
db_begin_transaction(stmt->db);
tal_free(stmt);
Expand All @@ -45,7 +45,7 @@ u32 db_data_version_get(struct db *db)
u32 version;
stmt = db_prepare_v2(db, SQL("SELECT intval FROM vars WHERE name = 'data_version'"));
/* postgres will act upset if the table doesn't exist yet. */
if (!db_query_prepared(stmt)) {
if (!db_query_prepared_canfail(stmt)) {
tal_free(stmt);
return 0;
}
Expand Down Expand Up @@ -85,7 +85,7 @@ s64 db_get_intvar(struct db *db, char *varname, s64 defval)
struct db_stmt *stmt = db_prepare_v2(
db, SQL("SELECT intval FROM vars WHERE name= ? LIMIT 1"));
db_bind_text(stmt, 0, varname);
if (db_query_prepared(stmt) && db_step(stmt))
if (db_query_prepared_canfail(stmt) && db_step(stmt))
res = db_col_int(stmt, "intval");

tal_free(stmt);
Expand Down
9 changes: 8 additions & 1 deletion db/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ struct db_stmt *db_prepare_untranslated(struct db *db, const char *query)
return stmt;
}

bool db_query_prepared(struct db_stmt *stmt)
bool db_query_prepared_canfail(struct db_stmt *stmt)
{
/* Make sure we don't accidentally execute a modifying query using a
* read-only path. */
Expand All @@ -147,6 +147,13 @@ bool db_query_prepared(struct db_stmt *stmt)
return ret;
}

void db_query_prepared(struct db_stmt *stmt)
{
if (!db_query_prepared_canfail(stmt))
db_fatal("query failed: %s: %s",
stmt->location, stmt->query->query);
}

bool db_step(struct db_stmt *stmt)
{
bool ret;
Expand Down
7 changes: 6 additions & 1 deletion db/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ bool db_exec_prepared_v2(struct db_stmt *stmt TAKES);
*
* @stmt: The prepared statement to execute
*/
bool db_query_prepared(struct db_stmt *stmt);
void db_query_prepared(struct db_stmt *stmt);

/**
* Variation which allows failure.
*/
bool db_query_prepared_canfail(struct db_stmt *stmt);

size_t db_count_changes(struct db_stmt *stmt);
void db_report_changes(struct db *db, const char *final, size_t min);
Expand Down
8 changes: 4 additions & 4 deletions wallet/test/run-db.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ static bool test_manip_columns(void)
CHECK(db->config->delete_columns(db, "tableb", &field1, 1));

stmt = db_prepare_v2(db, SQL("SELECT id, field1a FROM tablea;"));
CHECK_MSG(db_query_prepared(stmt), "db_query_prepared must succeed");
CHECK_MSG(db_query_prepared_canfail(stmt), "db_query_prepared must succeed");
CHECK_MSG(!db_err, "Simple correct SQL command");
CHECK(db_step(stmt));
CHECK(db_col_u64(stmt, "id") == 0);
Expand All @@ -233,7 +233,7 @@ static bool test_manip_columns(void)
tal_free(stmt);

stmt = db_prepare_v2(db, SQL("SELECT id, field2 FROM tableb;"));
CHECK_MSG(db_query_prepared(stmt), "db_query_prepared must succeed");
CHECK_MSG(db_query_prepared_canfail(stmt), "db_query_prepared must succeed");
CHECK_MSG(!db_err, "Simple correct SQL command");
CHECK(db_step(stmt));
CHECK(db_col_u64(stmt, "id") == 0);
Expand All @@ -247,15 +247,15 @@ static bool test_manip_columns(void)
db_begin_transaction(db);
/* This will actually fail */
stmt = db_prepare_v2(db, SQL("SELECT field1 FROM tablea;"));
CHECK_MSG(!db_query_prepared(stmt), "db_query_prepared must fail");
CHECK_MSG(!db_query_prepared_canfail(stmt), "db_query_prepared must fail");
db->dirty = false;
db->changes = tal_arr(db, const char *, 0);
db_commit_transaction(db);

db_begin_transaction(db);
/* This will actually fail */
stmt = db_prepare_v2(db, SQL("SELECT field1 FROM tableb;"));
CHECK_MSG(!db_query_prepared(stmt), "db_query_prepared must fail");
CHECK_MSG(!db_query_prepared_canfail(stmt), "db_query_prepared must fail");
db->dirty = false;
db->changes = tal_arr(db, const char *, 0);
db_commit_transaction(db);
Expand Down

0 comments on commit 9bcf28a

Please sign in to comment.