diff options
| author | Anders Betts <anders.betts@gmail.com> | 2026-09-20 21:55:04 +0200 |
|---|---|---|
| committer | Anders Betts <anders.betts@gmail.com> | 2026-09-20 22:02:57 +0200 |
| commit | ceff3d26732a7fde2f66df0270269d3bebcfabf7 (patch) | |
| tree | 4ad6677617cae9de4aa4b5b42352a7a8cf29a3e9 | |
| parent | 10a535ace098144980d0ffd1593f6384c39cc221 (diff) | |
| download | bokf-ceff3d26732a7fde2f66df0270269d3bebcfabf7.tar.gz bokf-ceff3d26732a7fde2f66df0270269d3bebcfabf7.zip | |
commands: shared DB-error helpers
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
| -rw-r--r-- | src/cmd_accounts.c | 37 | ||||
| -rw-r--r-- | src/cmd_attachments.c | 14 | ||||
| -rw-r--r-- | src/cmd_audit.c | 2 | ||||
| -rw-r--r-- | src/cmd_auth.c | 4 | ||||
| -rw-r--r-- | src/cmd_bank.c | 58 | ||||
| -rw-r--r-- | src/cmd_bokslut.c | 4 | ||||
| -rw-r--r-- | src/cmd_customers.c | 32 | ||||
| -rw-r--r-- | src/cmd_fiscal.c | 40 | ||||
| -rw-r--r-- | src/cmd_invoices.c | 34 | ||||
| -rw-r--r-- | src/cmd_org.c | 78 | ||||
| -rw-r--r-- | src/cmd_rules.c | 14 | ||||
| -rw-r--r-- | src/cmd_settings.c | 8 | ||||
| -rw-r--r-- | src/cmd_sie.c | 2 | ||||
| -rw-r--r-- | src/cmd_templates.c | 45 | ||||
| -rw-r--r-- | src/cmd_users.c | 17 | ||||
| -rw-r--r-- | src/cmd_util.c | 18 | ||||
| -rw-r--r-- | src/cmd_util.h | 3 | ||||
| -rw-r--r-- | src/cmd_vouchers.c | 10 |
18 files changed, 185 insertions, 235 deletions
diff --git a/src/cmd_accounts.c b/src/cmd_accounts.c index 900558f..b5770b0 100644 --- a/src/cmd_accounts.c +++ b/src/cmd_accounts.c @@ -49,7 +49,7 @@ static yyjson_mut_val *h_account_list(struct req *r) : "SELECT " ACCOUNT_COLUMNS " FROM accounts" " WHERE org_id=?1 ORDER BY number"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); while (sqlite3_step(st) == SQLITE_ROW) yyjson_mut_arr_add_val(items, account_json(r->rdoc, st)); @@ -72,7 +72,7 @@ static yyjson_mut_val *h_account_get(struct req *r) : "SELECT " ACCOUNT_COLUMNS " FROM accounts" " WHERE org_id=?1 AND number=?2"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); if (id) sqlite3_bind_int64(st, 2, id); @@ -116,26 +116,20 @@ static yyjson_mut_val *h_account_create(struct req *r) "INSERT INTO accounts(org_id,number,name,type,sru_code,vat_code," "created_at) VALUES(?1,?2,?3,?4,?5,?6,?7)", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, number, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 3, name, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 4, type, -1, SQLITE_TRANSIENT); - if (sru) - sqlite3_bind_text(st, 5, sru, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 5); - if (vat) - sqlite3_bind_text(st, 6, vat, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 6); + bind_text_or_null(st, 5, sru); + bind_text_or_null(st, 6, vat); sqlite3_bind_text(st, 7, ts, -1, SQLITE_TRANSIENT); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) { if ((rc & 0xff) == SQLITE_CONSTRAINT) return fail(r, "CONFLICT", "account number already exists"); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } int64_t id = db_last_id(r->db); char *reqjson = audit_args_json(r->args); @@ -173,27 +167,18 @@ static yyjson_mut_val *h_account_update(struct req *r) " active=CASE WHEN ?5<0 THEN active ELSE ?5 END, updated_at=?6" " WHERE org_id=?1 AND id=?7", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); - if (name) - sqlite3_bind_text(st, 2, name, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 2); - if (sru) - sqlite3_bind_text(st, 3, sru, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 3); - if (vat) - sqlite3_bind_text(st, 4, vat, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 4); + bind_text_or_null(st, 2, name); + bind_text_or_null(st, 3, sru); + bind_text_or_null(st, 4, vat); sqlite3_bind_int(st, 5, active); sqlite3_bind_text(st, 6, ts, -1, SQLITE_TRANSIENT); sqlite3_bind_int64(st, 7, id); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "account not found"); char *reqjson = audit_args_json(r->args); diff --git a/src/cmd_attachments.c b/src/cmd_attachments.c index b1590fd..7721086 100644 --- a/src/cmd_attachments.c +++ b/src/cmd_attachments.c @@ -111,7 +111,7 @@ static yyjson_mut_val *h_attachment_put(struct req *r) " AND filename=?3", -1, &st, NULL) != SQLITE_OK) { free(content); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_blob(st, 2, hash, 32, SQLITE_TRANSIENT); @@ -149,7 +149,7 @@ static yyjson_mut_val *h_attachment_put(struct req *r) "content,created_at,created_by) VALUES(?1,?2,?3,?4,?5,?6,?7,?8)", -1, &st, NULL) != SQLITE_OK) { free(content); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_blob(st, 2, hash, 32, SQLITE_TRANSIENT); @@ -163,7 +163,7 @@ static yyjson_mut_val *h_attachment_put(struct req *r) sqlite3_finalize(st); free(content); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); int64_t id = db_last_id(r->db); if (voucher_id) { @@ -232,14 +232,14 @@ static yyjson_mut_val *h_attachment_unlink(struct req *r) "DELETE FROM voucher_attachments WHERE org_id=?1" " AND voucher_id=?2 AND attachment_id=?3", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, voucher_id); sqlite3_bind_int64(st, 3, id); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "link not found"); char *reqjson = audit_args_json(r->args); @@ -260,7 +260,7 @@ static yyjson_mut_val *h_attachment_get(struct req *r) "SELECT filename,mime,size_bytes,content,sha256,created_at" " FROM attachments WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -321,7 +321,7 @@ static yyjson_mut_val *h_attachment_list(struct req *r) " WHERE va3.org_id=a.org_id AND va3.attachment_id=a.id))" " AND a.id>?4 ORDER BY a.id LIMIT ?5", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, voucher_id); sqlite3_bind_int(st, 3, unlinked); diff --git a/src/cmd_audit.c b/src/cmd_audit.c index 183e7e6..250f096 100644 --- a/src/cmd_audit.c +++ b/src/cmd_audit.c @@ -41,7 +41,7 @@ static yyjson_mut_val *h_audit_list(struct req *r) "request_json,result_code FROM audit_log" " WHERE org_id=?1 AND seq>?2 ORDER BY seq LIMIT ?4"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, cursor); if (action) diff --git a/src/cmd_auth.c b/src/cmd_auth.c index be140f4..9eb628f 100644 --- a/src/cmd_auth.c +++ b/src/cmd_auth.c @@ -241,7 +241,7 @@ static yyjson_mut_val *h_session_open(struct req *r) -1, &st, NULL); if (rc != SQLITE_OK) { free(reqjson); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_blob(st, 1, th, 32, SQLITE_TRANSIENT); int found = sqlite3_step(st) == SQLITE_ROW; @@ -339,7 +339,7 @@ static yyjson_mut_val *h_session_whoami(struct req *r) "SELECT username,display_name,is_admin FROM users" " WHERE id=?1", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->sess->user_id); if (sqlite3_step(st) == SQLITE_ROW) { username = xstrdup(sq(sqlite3_column_text(st, 0))); diff --git a/src/cmd_bank.c b/src/cmd_bank.c index b1ab2e3..82d5574 100644 --- a/src/cmd_bank.c +++ b/src/cmd_bank.c @@ -301,7 +301,7 @@ static yyjson_mut_val *h_bank_import(struct req *r) free(setting); free(rows); free(csv); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } if (!found) { yyjson_mut_val *res = @@ -337,7 +337,7 @@ static yyjson_mut_val *h_bank_import(struct req *r) free(setting); free(rows); free(csv); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(q, 1, r->org_id); sqlite3_bind_blob(q, 2, sorted[i], 32, SQLITE_TRANSIENT); @@ -394,7 +394,7 @@ static yyjson_mut_val *h_bank_import(struct req *r) free(setting); free(rows); free(csv); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } if (db_exec(r->db, "COMMIT", NULL) != 0) { db_exec(r->db, "ROLLBACK", NULL); @@ -402,7 +402,7 @@ static yyjson_mut_val *h_bank_import(struct req *r) free(setting); free(rows); free(csv); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } } int64_t duplicates = (int64_t)nrows - imported; @@ -476,20 +476,11 @@ static yyjson_mut_val *h_bank_list(struct req *r) " WHERE m.org_id=t.org_id AND m.transaction_id=t.id)))" " ORDER BY t.booked_at,t.id LIMIT ?6", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); - if (account) - sqlite3_bind_text(st, 2, account, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 2); - if (from) - sqlite3_bind_text(st, 3, from, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 3); - if (to) - sqlite3_bind_text(st, 4, to, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 4); + bind_text_or_null(st, 2, account); + bind_text_or_null(st, 3, from); + bind_text_or_null(st, 4, to); sqlite3_bind_int64(st, 5, status_code); sqlite3_bind_int64(st, 6, limit); @@ -533,7 +524,7 @@ static yyjson_mut_val *h_bank_list(struct req *r) " GROUP BY v.id,v.series,v.number,v.date ORDER BY v.id", -1, &ms, NULL) != SQLITE_OK) { sqlite3_finalize(st); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(ms, 1, r->org_id); sqlite3_bind_text(ms, 2, tx_account, -1, SQLITE_TRANSIENT); @@ -576,7 +567,7 @@ static yyjson_mut_val *h_bank_list(struct req *r) "v.id LIMIT 3", -1, &ss, NULL) != SQLITE_OK) { sqlite3_finalize(st); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(ss, 1, r->org_id); sqlite3_bind_text(ss, 2, tx_account, -1, SQLITE_TRANSIENT); @@ -616,10 +607,7 @@ static yyjson_mut_val *h_bank_list(struct req *r) " WHERE t.org_id=?1 AND (?2 IS NULL OR t.account=?2)", -1, &sum, NULL) == SQLITE_OK) { sqlite3_bind_int64(sum, 1, r->org_id); - if (account) - sqlite3_bind_text(sum, 2, account, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(sum, 2); + bind_text_or_null(sum, 2, account); if (sqlite3_step(sum) == SQLITE_ROW) { int64_t total = sqlite3_column_int64(sum, 0); matched = sqlite3_column_int64(sum, 1); @@ -678,7 +666,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) "SELECT account,amount_ore FROM bank_transactions" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, tx_id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -693,7 +681,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) if (sqlite3_prepare_v2( r->db, "SELECT 1 FROM vouchers WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, voucher_id); found = sqlite3_step(st) == SQLITE_ROW; @@ -708,7 +696,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) " JOIN accounts a ON a.org_id=r.org_id AND a.id=r.account_id" " WHERE r.org_id=?1 AND r.voucher_id=?2 AND a.number=?3", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, voucher_id); sqlite3_bind_text(st, 3, account, -1, SQLITE_TRANSIENT); @@ -724,7 +712,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) "SELECT 1 FROM bank_matches WHERE org_id=?1 AND transaction_id=?2" " AND voucher_id=?3", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, tx_id); sqlite3_bind_int64(st, 3, voucher_id); @@ -736,7 +724,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) int64_t legs = 0; if (bank_legs_sum(r->db, r->org_id, tx_id, account, &legs) != 0) - return fail(r, "INTERNAL", "database error"); + return db_error(r); if (r->dry_run) { sqlite3_stmt *vs = NULL; int64_t voucher_leg = 0; @@ -747,7 +735,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) " JOIN accounts a ON a.org_id=r.org_id AND a.id=r.account_id" " WHERE r.org_id=?1 AND r.voucher_id=?2 AND a.number=?3", -1, &vs, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(vs, 1, r->org_id); sqlite3_bind_int64(vs, 2, voucher_id); sqlite3_bind_text(vs, 3, account, -1, SQLITE_TRANSIENT); @@ -770,7 +758,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) "INSERT INTO bank_matches(org_id,transaction_id,voucher_id," "matched_at,matched_by,kind) VALUES(?1,?2,?3,?4,?5,'manual')", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, tx_id); sqlite3_bind_int64(st, 3, voucher_id); @@ -779,7 +767,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", "database error"); + return db_error(r); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, @@ -787,7 +775,7 @@ static yyjson_mut_val *h_bank_match(struct req *r) free(reqjson); if (bank_legs_sum(r->db, r->org_id, tx_id, account, &legs) != 0) - return fail(r, "INTERNAL", "database error"); + return db_error(r); yyjson_mut_val *o = yyjson_mut_obj(r->rdoc); yyjson_mut_obj_add_int(r->rdoc, o, "transaction_id", tx_id); yyjson_mut_obj_add_int(r->rdoc, o, "voucher_id", voucher_id); @@ -808,7 +796,7 @@ static yyjson_mut_val *h_bank_unmatch(struct req *r) "SELECT 1 FROM bank_matches WHERE org_id=?1 AND transaction_id=?2" " AND voucher_id=?3", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, tx_id); sqlite3_bind_int64(st, 3, voucher_id); @@ -822,14 +810,14 @@ static yyjson_mut_val *h_bank_unmatch(struct req *r) "DELETE FROM bank_matches WHERE org_id=?1" " AND transaction_id=?2 AND voucher_id=?3", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, tx_id); sqlite3_bind_int64(st, 3, voucher_id); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", "database error"); + return db_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "match not found"); char *reqjson = audit_args_json(r->args); diff --git a/src/cmd_bokslut.c b/src/cmd_bokslut.c index 429ada4..c813923 100644 --- a/src/cmd_bokslut.c +++ b/src/cmd_bokslut.c @@ -28,7 +28,7 @@ static yyjson_mut_val *h_bokslut_post(struct req *r) "SELECT label,start_date,end_date FROM fiscal_years" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, fy_id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -97,7 +97,7 @@ static yyjson_mut_val *h_bokslut_post(struct req *r) " WHERE r.org_id=?1 AND v.fiscal_year_id=?2 AND v.series<>'IB'" " AND a.type IN ('revenue','expense') AND a.number NOT LIKE '89%'", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, fy_id); if (sqlite3_step(st) == SQLITE_ROW) diff --git a/src/cmd_customers.c b/src/cmd_customers.c index a46cd32..d259a8e 100644 --- a/src/cmd_customers.c +++ b/src/cmd_customers.c @@ -129,7 +129,7 @@ static yyjson_mut_val *customer_lookup(struct req *r, int64_t id, int *found) " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) { *found = -1; - fail(r, "INTERNAL", "database error"); + db_error(r); return NULL; } sqlite3_bind_int64(st, 1, r->org_id); @@ -152,7 +152,7 @@ static int customer_name_taken(struct req *r, const char *name, int64_t except_i "SELECT id FROM customers WHERE org_id=?1 AND name=?2" " AND id<>?3", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -173,7 +173,7 @@ static yyjson_mut_val *h_customer_list(struct req *r) "SELECT " CUSTOMER_COLUMNS " FROM customers WHERE org_id=?1" " AND (?2=0 OR active=1) ORDER BY name COLLATE NOCASE, id", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int(st, 2, active_only); yyjson_mut_val *items = yyjson_mut_arr(r->rdoc); @@ -248,7 +248,7 @@ static yyjson_mut_val *h_customer_create(struct req *r) "vat_nr,email,your_ref,payment_days,notes,created_at)" " VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12)", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, in.name, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 3, address, -1, SQLITE_TRANSIENT); @@ -266,7 +266,7 @@ static yyjson_mut_val *h_customer_create(struct req *r) if (rc != SQLITE_DONE) { if ((rc & 0xff) == SQLITE_CONSTRAINT) return fail(r, "CONFLICT", "a customer with this name already exists"); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } int64_t id = db_last_id(r->db); char *reqjson = audit_args_json(r->args); @@ -325,7 +325,7 @@ static yyjson_mut_val *h_customer_update(struct req *r) "created_at,COALESCE(updated_at,'')" " FROM customers WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); const char *texts[] = { in.name, in.address, in.postal_code, in.city, @@ -333,11 +333,7 @@ static yyjson_mut_val *h_customer_update(struct req *r) in.notes }; static const int bind_index[] = { 3, 4, 5, 6, 7, 8, 9, 10, 12 }; for (size_t i = 0; i < sizeof texts / sizeof texts[0]; i++) { - if (texts[i]) - sqlite3_bind_text(st, bind_index[i], texts[i], -1, - SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, bind_index[i]); + bind_text_or_null(st, bind_index[i], texts[i]); } sqlite3_bind_int64(st, 11, in.have_payment ? in.payment_days : -1); sqlite3_bind_int64(st, 13, in.have_active ? in.active : -1); @@ -366,7 +362,7 @@ static yyjson_mut_val *h_customer_update(struct req *r) " active=CASE WHEN ?13<0 THEN active ELSE ?13 END," " updated_at=?14 WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); const char *texts[] = { in.name, in.address, in.postal_code, in.city, @@ -374,11 +370,7 @@ static yyjson_mut_val *h_customer_update(struct req *r) in.notes }; static const int text_index[] = { 3, 4, 5, 6, 7, 8, 9, 10, 12 }; for (size_t i = 0; i < sizeof texts / sizeof texts[0]; i++) { - if (texts[i]) - sqlite3_bind_text(st, text_index[i], texts[i], -1, - SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, text_index[i]); + bind_text_or_null(st, text_index[i], texts[i]); } sqlite3_bind_int64(st, 11, in.have_payment ? in.payment_days : -1); sqlite3_bind_int64(st, 13, in.have_active ? in.active : -1); @@ -388,7 +380,7 @@ static yyjson_mut_val *h_customer_update(struct req *r) if (rc != SQLITE_DONE) { if ((rc & 0xff) == SQLITE_CONSTRAINT) return fail(r, "CONFLICT", "a customer with this name already exists"); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "customer not found"); @@ -436,7 +428,7 @@ static yyjson_mut_val *h_customer_archive(struct req *r) "UPDATE customers SET active=?3, updated_at=?4" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); sqlite3_bind_int(st, 3, active); @@ -444,7 +436,7 @@ static yyjson_mut_val *h_customer_archive(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "customer not found"); char *reqjson = audit_args_json(r->args); diff --git a/src/cmd_fiscal.c b/src/cmd_fiscal.c index 94d2429..3f8e2c2 100644 --- a/src/cmd_fiscal.c +++ b/src/cmd_fiscal.c @@ -58,7 +58,7 @@ static yyjson_mut_val *h_fiscal_year_list(struct req *r) "SELECT " FY_COLUMNS " FROM fiscal_years WHERE org_id=?1" " ORDER BY start_date", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); while (sqlite3_step(st) == SQLITE_ROW) yyjson_mut_arr_add_val(items, fy_json(r, st)); @@ -79,7 +79,7 @@ static yyjson_mut_val *h_fiscal_year_get(struct req *r) : "SELECT " FY_COLUMNS " FROM fiscal_years" " WHERE org_id=?1 ORDER BY start_date DESC LIMIT 1"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); if (id) sqlite3_bind_int64(st, 2, id); @@ -156,7 +156,7 @@ static yyjson_mut_val *h_fiscal_year_open(struct req *r) "events,employees,notes,created_at)" " VALUES(?1,?2,?3,?4,?5,?6,?7,?8)", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, label, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 3, start, -1, SQLITE_TRANSIENT); @@ -199,7 +199,7 @@ static yyjson_mut_val *h_fiscal_year_close(struct req *r) "UPDATE fiscal_years SET status='closed', closed_at=?3," " closed_by=?4 WHERE org_id=?1 AND id=?2 AND status='open'", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); sqlite3_bind_text(st, 3, ts, -1, SQLITE_TRANSIENT); @@ -207,7 +207,7 @@ static yyjson_mut_val *h_fiscal_year_close(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "open fiscal year not found"); char *reqjson = audit_args_json(r->args); @@ -236,13 +236,13 @@ static yyjson_mut_val *h_fiscal_year_reopen(struct req *r) "UPDATE fiscal_years SET status='open', closed_at=NULL," " closed_by=NULL WHERE org_id=?1 AND id=?2 AND status='closed'", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "closed fiscal year not found"); char *reqjson = audit_args_json(r->args); @@ -282,7 +282,7 @@ static yyjson_mut_val *h_fiscal_year_update(struct req *r) "SELECT count(*) FROM fiscal_years" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); int64_t exists = 0; @@ -315,24 +315,18 @@ static yyjson_mut_val *h_fiscal_year_update(struct req *r) " notes=COALESCE(?8,notes)" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); sqlite3_bind_int64(st, 3, have_div ? dividend : -1); for (int i = 0; i < 4; i++) { - if (svals[i]) - sqlite3_bind_text(st, i + 4, svals[i], -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, i + 4); + bind_text_or_null(st, i + 4, svals[i]); } - if (notes) - sqlite3_bind_text(st, 8, notes, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 8); + bind_text_or_null(st, 8, notes); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, "fiscal_year.update", reqjson, "OK", NULL); @@ -341,7 +335,7 @@ static yyjson_mut_val *h_fiscal_year_update(struct req *r) "SELECT " FY_COLUMNS " FROM fiscal_years" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); yyjson_mut_val *o = NULL; @@ -367,14 +361,14 @@ static yyjson_mut_val *h_period_lock(struct req *r) "UPDATE fiscal_years SET locked_until=?3 WHERE org_id=?1 AND id=?2" " AND ?3 BETWEEN start_date AND end_date", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, fy); sqlite3_bind_text(st, 3, until, -1, SQLITE_TRANSIENT); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "fiscal year not found or until is outside it"); @@ -399,13 +393,13 @@ static yyjson_mut_val *h_period_unlock(struct req *r) r->db, "UPDATE fiscal_years SET locked_until=NULL WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, fy); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "fiscal year not found"); char *reqjson = audit_args_json(r->args); diff --git a/src/cmd_invoices.c b/src/cmd_invoices.c index b8d44e3..4bce5ee 100644 --- a/src/cmd_invoices.c +++ b/src/cmd_invoices.c @@ -41,7 +41,7 @@ static int invoice_take_number(struct req *r, int64_t *out) if (sqlite3_prepare_v2( r->db, "SELECT next_number FROM invoice_sequence WHERE org_id=?1", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -54,7 +54,7 @@ static int invoice_take_number(struct req *r, int64_t *out) "UPDATE invoice_sequence SET next_number=next_number+1" " WHERE org_id=?1", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -69,7 +69,7 @@ static int invoice_take_number(struct req *r, int64_t *out) r->db, "INSERT INTO invoice_sequence(org_id,next_number) VALUES(?1,2)", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -109,13 +109,13 @@ static yyjson_mut_val *h_invoice_sequence_set(struct req *r) "INSERT INTO invoice_sequence(org_id,next_number) VALUES(?1,?2)" " ON CONFLICT(org_id) DO UPDATE SET next_number=excluded.next_number", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, next); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, "invoice.sequence_set", reqjson, "OK", NULL); @@ -387,7 +387,7 @@ static int invoice_view_fill(struct req *r, const struct invoice_draft *d, "COALESCE(phone,''),COALESCE(email,''),COALESCE(org_nr,'')," "COALESCE(vat_nr,'') FROM orgs WHERE id=?1", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -422,7 +422,7 @@ static int invoice_view_fill(struct req *r, const struct invoice_draft *d, "SELECT name,address,postal_code,city,vat_nr,payment_days,active" " FROM customers WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -591,7 +591,7 @@ static int invoice_store_attachment(struct req *r, const struct invoice_view *v, "content,created_at,created_by)" " VALUES(?1,?2,?3,'application/pdf',?4,?5,?6,?7)", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -627,7 +627,7 @@ static int invoice_store_invoice(struct req *r, const struct invoice_draft *d, " VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16," "?17)", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -673,7 +673,7 @@ static int invoice_store_invoice(struct req *r, const struct invoice_draft *d, "vat_code,account)" " VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12)", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); return -1; } sqlite3_bind_int64(st, 1, r->org_id); @@ -929,7 +929,7 @@ static yyjson_mut_val *h_invoice_get(struct req *r) " ON c.org_id=i.org_id AND c.id=i.customer_id" " WHERE i.org_id=?1 AND i.id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -1032,7 +1032,7 @@ static yyjson_mut_val *h_invoice_list(struct req *r) " AND (?3='' OR i.status=?3)" " ORDER BY i.number DESC, i.id DESC LIMIT ?4", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, customer_id); sqlite3_bind_text(st, 3, status, -1, SQLITE_TRANSIENT); @@ -1094,7 +1094,7 @@ static yyjson_mut_val *h_invoice_pdf(struct req *r) r->db, "SELECT document_id FROM invoices WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -1113,7 +1113,7 @@ static yyjson_mut_val *h_invoice_pdf(struct req *r) r->db, "SELECT content FROM attachments WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, document_id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -1163,7 +1163,7 @@ static yyjson_mut_val *h_invoice_send(struct req *r) " JOIN orgs o ON o.id=i.org_id" " WHERE i.org_id=?1 AND i.id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -1192,7 +1192,7 @@ static yyjson_mut_val *h_invoice_send(struct req *r) if (sqlite3_prepare_v2( r->db, "SELECT content FROM attachments WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, document_id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -1317,7 +1317,7 @@ static yyjson_mut_val *h_invoice_send(struct req *r) "UPDATE invoices SET last_sent_at=?1,last_sent_to=?2" " WHERE org_id=?3 AND id=?4", -1, &st, NULL) != SQLITE_OK) { - fail(r, "INTERNAL", "database error"); + db_error(r); goto done; } sqlite3_bind_text(st, 1, ts, -1, SQLITE_TRANSIENT); diff --git a/src/cmd_org.c b/src/cmd_org.c index 4776491..8adaf3b 100644 --- a/src/cmd_org.c +++ b/src/cmd_org.c @@ -88,13 +88,10 @@ static yyjson_mut_val *h_org_create(struct req *r) -1, &st, NULL); if (rc != SQLITE_OK) { db_exec(r->db, "ROLLBACK", NULL); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } sqlite3_bind_text(st, 1, name, -1, SQLITE_TRANSIENT); - if (org_nr) - sqlite3_bind_text(st, 2, org_nr, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 2); + bind_text_or_null(st, 2, org_nr); sqlite3_bind_int64(st, 3, fy_month); sqlite3_bind_text(st, 4, moms, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 5, framework, -1, SQLITE_TRANSIENT); @@ -104,7 +101,7 @@ static yyjson_mut_val *h_org_create(struct req *r) sqlite3_finalize(st); if (rc != SQLITE_DONE) { db_exec(r->db, "ROLLBACK", NULL); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } int64_t org_id = db_last_id(r->db); @@ -115,7 +112,7 @@ static yyjson_mut_val *h_org_create(struct req *r) -1, &st, NULL); if (rc != SQLITE_OK) { db_exec(r->db, "ROLLBACK", NULL); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } sqlite3_bind_int64(st, 1, org_id); sqlite3_bind_int64(st, 2, r->sess->user_id); @@ -124,7 +121,7 @@ static yyjson_mut_val *h_org_create(struct req *r) sqlite3_finalize(st); if (rc != SQLITE_DONE) { db_exec(r->db, "ROLLBACK", NULL); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } int64_t fy_id = 0; char *seed_err = NULL; @@ -148,7 +145,7 @@ static yyjson_mut_val *h_org_create(struct req *r) st = NULL; if (sqlite3_prepare_v2(r->db, "SELECT " ORG_COLUMNS " FROM orgs WHERE id=?1", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, org_id); yyjson_mut_val *o = NULL; if (sqlite3_step(st) == SQLITE_ROW) @@ -169,7 +166,7 @@ static yyjson_mut_val *h_org_list(struct req *r) "SELECT o.id,o.name,o.org_nr,m.role FROM memberships m" " JOIN orgs o ON o.id=m.org_id WHERE m.user_id=?1 ORDER BY o.id", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->sess->user_id); while (sqlite3_step(st) == SQLITE_ROW) { yyjson_mut_val *o = yyjson_mut_arr_add_obj(r->rdoc, items); @@ -192,7 +189,7 @@ static yyjson_mut_val *h_org_get(struct req *r) sqlite3_stmt *st = NULL; if (sqlite3_prepare_v2(r->db, "SELECT " ORG_COLUMNS " FROM orgs WHERE id=?1", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); yyjson_mut_val *o = NULL; if (sqlite3_step(st) == SQLITE_ROW) @@ -280,28 +277,19 @@ static yyjson_mut_val *h_org_update(struct req *r) " shares=CASE WHEN ?15<0 THEN shares ELSE ?15 END" " WHERE id=?1", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); for (int i = 0; i < 10; i++) { - if (texts[i]) - sqlite3_bind_text(st, i + 2, texts[i], -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, i + 2); + bind_text_or_null(st, i + 2, texts[i]); } sqlite3_bind_int64(st, 12, fy_month); - if (moms) - sqlite3_bind_text(st, 13, moms, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 13); - if (framework) - sqlite3_bind_text(st, 14, framework, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 14); + bind_text_or_null(st, 13, moms); + bind_text_or_null(st, 14, framework); sqlite3_bind_int64(st, 15, shares); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, @@ -312,7 +300,7 @@ static yyjson_mut_val *h_org_update(struct req *r) if (sqlite3_prepare_v2(r->db, "SELECT " ORG_COLUMNS " FROM orgs WHERE id=?1", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); yyjson_mut_val *o = NULL; if (sqlite3_step(st) == SQLITE_ROW) @@ -332,7 +320,7 @@ static yyjson_mut_val *h_org_member_list(struct req *r) "SELECT u.id,u.username,u.display_name,m.role FROM memberships m" " JOIN users u ON u.id=m.user_id WHERE m.org_id=?1 ORDER BY u.id", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); while (sqlite3_step(st) == SQLITE_ROW) { yyjson_mut_val *o = yyjson_mut_arr_add_obj(r->rdoc, items); @@ -403,7 +391,7 @@ static yyjson_mut_val *h_org_member_add(struct req *r) "INSERT INTO memberships(org_id,user_id,role,created_at)" " VALUES(?1,?2,?3,?4)", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, uid); sqlite3_bind_text(st, 3, role, -1, SQLITE_TRANSIENT); @@ -442,14 +430,14 @@ static yyjson_mut_val *h_org_member_set_role(struct req *r) r->db, "UPDATE memberships SET role=?1 WHERE org_id=?2 AND user_id=?3", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_text(st, 1, role, -1, SQLITE_TRANSIENT); sqlite3_bind_int64(st, 2, r->org_id); sqlite3_bind_int64(st, 3, uid); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, 0, "member.set_role", reqjson, "OK", NULL); @@ -477,13 +465,13 @@ static yyjson_mut_val *h_org_member_remove(struct req *r) if (sqlite3_prepare_v2( r->db, "DELETE FROM memberships WHERE org_id=?1 AND user_id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, uid); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, 0, "member.remove", reqjson, "OK", NULL); @@ -514,7 +502,7 @@ static yyjson_mut_val *h_board_list(struct req *r) "SELECT id,name,title FROM board_members" " WHERE org_id=?1 ORDER BY id", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); while (sqlite3_step(st) == SQLITE_ROW) yyjson_mut_arr_add_val(items, board_json(r, st)); @@ -531,7 +519,7 @@ static yyjson_mut_val *board_get(struct req *r, int64_t id) "SELECT id,name,title FROM board_members" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); yyjson_mut_val *o = NULL; @@ -565,7 +553,7 @@ static yyjson_mut_val *h_board_add(struct req *r) "INSERT INTO board_members(org_id,name,title," "created_at) VALUES(?1,?2,?3,?4)", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, name, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 3, title, -1, SQLITE_TRANSIENT); @@ -573,7 +561,7 @@ static yyjson_mut_val *h_board_add(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); int64_t id = db_last_id(r->db); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, @@ -611,21 +599,15 @@ static yyjson_mut_val *h_board_update(struct req *r) " title=COALESCE(?4,title)" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); - if (name) - sqlite3_bind_text(st, 3, name, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 3); - if (title) - sqlite3_bind_text(st, 4, title, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 4); + bind_text_or_null(st, 3, name); + bind_text_or_null(st, 4, title); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "board member not found"); char *reqjson = audit_args_json(r->args); @@ -651,13 +633,13 @@ static yyjson_mut_val *h_board_remove(struct req *r) "DELETE FROM board_members" " WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "board member not found"); char *reqjson = audit_args_json(r->args); diff --git a/src/cmd_rules.c b/src/cmd_rules.c index 04772f3..d9a1594 100644 --- a/src/cmd_rules.c +++ b/src/cmd_rules.c @@ -153,7 +153,7 @@ static yyjson_mut_val *h_report_rule_list(struct req *r) " FROM report_rules WHERE org_id=?1" " ORDER BY report,sort_order,box,id"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); if (report) sqlite3_bind_text(st, 2, report, -1, SQLITE_TRANSIENT); @@ -218,7 +218,7 @@ static yyjson_mut_val *h_report_rule_create(struct req *r) "INSERT INTO report_rules(org_id,report,box,match_type,pattern," "sign,sort_order) VALUES(?1,?2,?3,?4,?5,?6,?7)", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, report, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 3, box, -1, SQLITE_TRANSIENT); @@ -229,7 +229,7 @@ static yyjson_mut_val *h_report_rule_create(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); int64_t id = db_last_id(r->db); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, @@ -288,7 +288,7 @@ static yyjson_mut_val *h_report_rule_update(struct req *r) "UPDATE report_rules SET box=?3,match_type=?4,pattern=?5,sign=?6," "sort_order=?7 WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, row.id); sqlite3_bind_text(st, 3, row.box, -1, SQLITE_TRANSIENT); @@ -299,7 +299,7 @@ static yyjson_mut_val *h_report_rule_update(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "report rule not found"); char *reqjson = audit_args_json(r->args); @@ -331,13 +331,13 @@ static yyjson_mut_val *h_report_rule_delete(struct req *r) if (sqlite3_prepare_v2( r->db, "DELETE FROM report_rules WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "report rule not found"); char *reqjson = audit_args_json(r->args); diff --git a/src/cmd_settings.c b/src/cmd_settings.c index 8ae60ed..066dc55 100644 --- a/src/cmd_settings.c +++ b/src/cmd_settings.c @@ -116,7 +116,7 @@ static yyjson_mut_val *h_settings_set(struct req *r) " AND key=?2"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) { free(stored); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, key, -1, SQLITE_TRANSIENT); @@ -126,7 +126,7 @@ static yyjson_mut_val *h_settings_set(struct req *r) sqlite3_finalize(st); free(stored); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); char *reqjson = settings_secret_audit_json(key); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, "settings.set", reqjson, "OK", NULL); @@ -193,14 +193,14 @@ static yyjson_mut_val *h_settings_set(struct req *r) "INSERT INTO settings(org_id,key,value) VALUES(?1,?2,?3)" " ON CONFLICT(org_id,key) DO UPDATE SET value=excluded.value", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, key, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 3, value, -1, SQLITE_TRANSIENT); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); char *reqjson = audit_args_json(r->args); audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id, "settings.set", reqjson, "OK", NULL); diff --git a/src/cmd_sie.c b/src/cmd_sie.c index d5b2e8e..312c0a5 100644 --- a/src/cmd_sie.c +++ b/src/cmd_sie.c @@ -53,7 +53,7 @@ static yyjson_mut_val *h_sie_export(struct req *r) r->db, "SELECT label FROM fiscal_years WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, fy); if (sqlite3_step(st) != SQLITE_ROW) { diff --git a/src/cmd_templates.c b/src/cmd_templates.c index a134d96..7e40886 100644 --- a/src/cmd_templates.c +++ b/src/cmd_templates.c @@ -65,7 +65,7 @@ static int parse_template_rows(struct req *r, yyjson_val *rowsv, " AND number=?2", -1, &st, NULL) != SQLITE_OK) { free(rows); - return fail(r, "INTERNAL", "database error") ? -1 : -1; + return db_error(r) ? -1 : -1; } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, account, -1, SQLITE_TRANSIENT); @@ -124,7 +124,7 @@ static yyjson_mut_val *h_template_list(struct req *r) " WHERE tr.org_id=t.org_id AND tr.template_id=t.id)" " FROM voucher_templates t WHERE t.org_id=?1 ORDER BY t.name"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); while (sqlite3_step(st) == SQLITE_ROW) { yyjson_mut_val *o = yyjson_mut_arr_add_obj(r->rdoc, items); @@ -160,7 +160,7 @@ static yyjson_mut_val *h_template_get(struct req *r) : "SELECT id,name,series,description,active" " FROM voucher_templates WHERE org_id=?1 AND name=?2"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); if (id > 0) sqlite3_bind_int64(st, 2, id); @@ -255,7 +255,7 @@ static yyjson_mut_val *h_template_create(struct req *r) -1, &st, NULL) != SQLITE_OK) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, name, -1, SQLITE_TRANSIENT); @@ -269,7 +269,7 @@ static yyjson_mut_val *h_template_create(struct req *r) free(rows); if ((rc & 0xff) == SQLITE_CONSTRAINT) return fail(r, "CONFLICT", "a template with that name exists"); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } int64_t tpl = db_last_id(r->db); for (size_t i = 0; i < nrows; i++) { @@ -280,7 +280,7 @@ static yyjson_mut_val *h_template_create(struct req *r) -1, &st, NULL) != SQLITE_OK) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, tpl); @@ -296,7 +296,7 @@ static yyjson_mut_val *h_template_create(struct req *r) if (rc != SQLITE_DONE) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } } free(rows); @@ -369,21 +369,12 @@ static yyjson_mut_val *h_template_update(struct req *r) -1, &st, NULL) != SQLITE_OK) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); - if (new_name) - sqlite3_bind_text(st, 2, new_name, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 2); - if (series) - sqlite3_bind_text(st, 3, series, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 3); - if (description) - sqlite3_bind_text(st, 4, description, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 4); + bind_text_or_null(st, 2, new_name); + bind_text_or_null(st, 3, series); + bind_text_or_null(st, 4, description); sqlite3_bind_int(st, 5, active); sqlite3_bind_text(st, 6, ts, -1, SQLITE_TRANSIENT); sqlite3_bind_int64(st, 7, head.id); @@ -392,7 +383,7 @@ static yyjson_mut_val *h_template_update(struct req *r) if (rc != SQLITE_DONE) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } if (rowsv) { if (sqlite3_prepare_v2( @@ -402,7 +393,7 @@ static yyjson_mut_val *h_template_update(struct req *r) -1, &st, NULL) != SQLITE_OK) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, head.id); @@ -411,7 +402,7 @@ static yyjson_mut_val *h_template_update(struct req *r) if (rc != SQLITE_DONE) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } for (size_t i = 0; i < nrows; i++) { if (sqlite3_prepare_v2( @@ -422,7 +413,7 @@ static yyjson_mut_val *h_template_update(struct req *r) -1, &st, NULL) != SQLITE_OK) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, head.id); @@ -438,7 +429,7 @@ static yyjson_mut_val *h_template_update(struct req *r) if (rc != SQLITE_DONE) { db_exec(r->db, "ROLLBACK", NULL); free(rows); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } } } @@ -466,7 +457,7 @@ static yyjson_mut_val *h_template_archive(struct req *r) : "UPDATE voucher_templates SET active=0 WHERE org_id=?1" " AND name=?2"; if (sqlite3_prepare_v2(r->db, sql, -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); if (id > 0) sqlite3_bind_int64(st, 2, id); @@ -475,7 +466,7 @@ static yyjson_mut_val *h_template_archive(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "template not found"); char *reqjson = audit_args_json(r->args); diff --git a/src/cmd_users.c b/src/cmd_users.c index f327c13..7fae2cc 100644 --- a/src/cmd_users.c +++ b/src/cmd_users.c @@ -57,7 +57,7 @@ static yyjson_mut_val *h_user_list(struct req *r) "SELECT id,username,display_name,is_admin,created_at,disabled_at" " FROM users ORDER BY id", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); while (sqlite3_step(st) == SQLITE_ROW) { yyjson_mut_val *o = yyjson_mut_arr_add_obj(r->rdoc, items); yyjson_mut_obj_add_int(r->rdoc, o, "id", sqlite3_column_int64(st, 0)); @@ -138,7 +138,7 @@ static yyjson_mut_val *h_token_create(struct req *r) "created_at,expires_at) VALUES(?1,?2,?3,?4,?5,?6,?7)", -1, &st, NULL) != SQLITE_OK) { free(token); - return fail(r, "INTERNAL", "database error"); + return db_error(r); } sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, r->sess->user_id); @@ -146,15 +146,12 @@ static yyjson_mut_val *h_token_create(struct req *r) sqlite3_bind_blob(st, 4, th, 32, SQLITE_TRANSIENT); sqlite3_bind_text(st, 5, scopes, -1, SQLITE_TRANSIENT); sqlite3_bind_text(st, 6, ts, -1, SQLITE_TRANSIENT); - if (expires_at) - sqlite3_bind_text(st, 7, expires_at, -1, SQLITE_TRANSIENT); - else - sqlite3_bind_null(st, 7); + bind_text_or_null(st, 7, expires_at); int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) { free(token); - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); } int64_t token_id = db_last_id(r->db); char *reqjson = audit_args_json(r->args); @@ -184,7 +181,7 @@ static yyjson_mut_val *h_token_list(struct req *r) "revoked_at FROM api_tokens WHERE org_id=?1 AND user_id=?2" " ORDER BY id", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, r->sess->user_id); while (sqlite3_step(st) == SQLITE_ROW) { @@ -234,7 +231,7 @@ static yyjson_mut_val *h_token_revoke(struct req *r) : "UPDATE api_tokens SET revoked_at=?1 WHERE id=?2 AND org_id=?3" " AND user_id=?4", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_text(st, 1, ts, -1, SQLITE_TRANSIENT); sqlite3_bind_int64(st, 2, id); sqlite3_bind_int64(st, 3, r->org_id); @@ -243,7 +240,7 @@ static yyjson_mut_val *h_token_revoke(struct req *r) int rc = sqlite3_step(st); sqlite3_finalize(st); if (rc != SQLITE_DONE) - return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); + return db_sqlite_error(r); if (sqlite3_changes(r->db) == 0) return fail(r, "NOT_FOUND", "token not found"); audit_append(r->db, r->org_id, r->sess->user_id, id, "token.revoke", "{}", diff --git a/src/cmd_util.c b/src/cmd_util.c index 747f836..5347d48 100644 --- a/src/cmd_util.c +++ b/src/cmd_util.c @@ -198,6 +198,24 @@ yyjson_mut_val *failf(struct req *r, const char *code, const char *fmt, ...) return NULL; } +yyjson_mut_val *db_error(struct req *r) +{ + return fail(r, "INTERNAL", "database error"); +} + +yyjson_mut_val *db_sqlite_error(struct req *r) +{ + return fail(r, "INTERNAL", sqlite3_errmsg(r->db)); +} + +void bind_text_or_null(sqlite3_stmt *st, int idx, const char *s) +{ + if (s) + sqlite3_bind_text(st, idx, s, -1, SQLITE_TRANSIENT); + else + sqlite3_bind_null(st, idx); +} + int mkdir_p(const char *path, mode_t mode) { char tmp[4096]; diff --git a/src/cmd_util.h b/src/cmd_util.h index 4113eb2..ccab9f4 100644 --- a/src/cmd_util.h +++ b/src/cmd_util.h @@ -22,6 +22,9 @@ int command_validate_args(const struct command *cmd, yyjson_val *args, yyjson_mut_val *fail(struct req *r, const char *code, const char *msg); yyjson_mut_val *failf(struct req *r, const char *code, const char *fmt, ...) __attribute__((format(printf, 3, 4))); +yyjson_mut_val *db_error(struct req *r); +yyjson_mut_val *db_sqlite_error(struct req *r); +void bind_text_or_null(sqlite3_stmt *st, int idx, const char *s); int mkdir_p(const char *path, mode_t mode); yyjson_mut_val *json_to_mut(yyjson_mut_doc *doc, const char *json); int is_digits(const char *s); diff --git a/src/cmd_vouchers.c b/src/cmd_vouchers.c index 3e30544..8977878 100644 --- a/src/cmd_vouchers.c +++ b/src/cmd_vouchers.c @@ -315,7 +315,7 @@ static yyjson_mut_val *h_voucher_get(struct req *r) r->db, "SELECT " VOUCHER_COLUMNS " FROM vouchers WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -395,7 +395,7 @@ static yyjson_mut_val *h_voucher_list(struct req *r) r->db, "SELECT id FROM accounts WHERE org_id=?1 AND number=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_text(st, 2, account, -1, SQLITE_TRANSIENT); if (sqlite3_step(st) != SQLITE_ROW) { @@ -426,7 +426,7 @@ static yyjson_mut_val *h_voucher_list(struct req *r) " AND (?7='' OR v.description LIKE '%'||?7||'%')" " AND v.id>?8 ORDER BY v.id LIMIT ?9", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, fy); sqlite3_bind_text(st, 3, series ? series : "", -1, SQLITE_TRANSIENT); @@ -490,7 +490,7 @@ static yyjson_mut_val *h_voucher_correct(struct req *r) r->db, "SELECT series,date FROM vouchers WHERE org_id=?1 AND id=?2", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); if (sqlite3_step(st) != SQLITE_ROW) { @@ -510,7 +510,7 @@ static yyjson_mut_val *h_voucher_correct(struct req *r) " JOIN accounts a ON a.org_id=r.org_id AND a.id=r.account_id" " WHERE r.org_id=?1 AND r.voucher_id=?2 ORDER BY r.line_no", -1, &st, NULL) != SQLITE_OK) - return fail(r, "INTERNAL", "database error"); + return db_error(r); sqlite3_bind_int64(st, 1, r->org_id); sqlite3_bind_int64(st, 2, id); while (sqlite3_step(st) == SQLITE_ROW) { |
