aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd_accounts.c37
-rw-r--r--src/cmd_attachments.c14
-rw-r--r--src/cmd_audit.c2
-rw-r--r--src/cmd_auth.c4
-rw-r--r--src/cmd_bank.c58
-rw-r--r--src/cmd_bokslut.c4
-rw-r--r--src/cmd_customers.c32
-rw-r--r--src/cmd_fiscal.c40
-rw-r--r--src/cmd_invoices.c34
-rw-r--r--src/cmd_org.c78
-rw-r--r--src/cmd_rules.c14
-rw-r--r--src/cmd_settings.c8
-rw-r--r--src/cmd_sie.c2
-rw-r--r--src/cmd_templates.c45
-rw-r--r--src/cmd_users.c17
-rw-r--r--src/cmd_util.c18
-rw-r--r--src/cmd_util.h3
-rw-r--r--src/cmd_vouchers.c10
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) {