summaryrefslogtreecommitdiff
path: root/src/ledger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ledger.c')
-rw-r--r--src/ledger.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/src/ledger.c b/src/ledger.c
index 2de794e..a22e15e 100644
--- a/src/ledger.c
+++ b/src/ledger.c
@@ -345,6 +345,12 @@ static int db_step(sqlite3 *db, sqlite3_stmt *st, char *errbuf, size_t n)
return rc;
}
+static void tx_rollback(sqlite3 *db, int owner)
+{
+ if (owner)
+ sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+}
+
int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
struct ledger_error *e, char **out_result_json)
{
@@ -417,9 +423,12 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
(long long)(sum_debit - sum_credit));
}
- if (sqlite3_exec(db, "BEGIN IMMEDIATE", NULL, NULL, NULL) != SQLITE_OK) {
- free(series_owned);
- return fail(e, "DB_BUSY", "could not start transaction");
+ if (!o->already_in_tx) {
+ if (sqlite3_exec(db, "BEGIN IMMEDIATE", NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ free(series_owned);
+ return fail(e, "DB_BUSY", "could not start transaction");
+ }
}
int rc = -1;
@@ -443,7 +452,7 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
sqlite3_bind_text(st, 2, o->date, -1, SQLITE_TRANSIENT);
if (sqlite3_step(st) != SQLITE_ROW) {
sqlite3_finalize(st);
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "DATE_OUT_OF_RANGE",
"no fiscal year contains %s; open one first", o->date);
@@ -462,13 +471,13 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
sqlite3_finalize(st);
if (strcmp(fy_status, "closed") == 0) {
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "FISCAL_YEAR_CLOSED", "fiscal year %s is closed",
fy_label);
}
if (locked_until[0] && strcmp(o->date, locked_until) <= 0) {
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "PERIOD_LOCKED", "period is locked through %s",
locked_until);
@@ -490,7 +499,7 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
if (sqlite3_step(st) != SQLITE_ROW) {
sqlite3_finalize(st);
free(acct_ids);
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "ACCOUNT_NOT_FOUND", "account %s does not exist",
o->rows[i].account);
@@ -500,7 +509,7 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
sqlite3_finalize(st);
if (!active) {
free(acct_ids);
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "ACCOUNT_INACTIVE", "account %s is inactive",
o->rows[i].account);
@@ -524,7 +533,7 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
sqlite3_finalize(st);
if (!exists) {
free(acct_ids);
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "NOT_FOUND", "voucher %lld does not exist",
(long long)o->corrects_voucher_id);
@@ -624,7 +633,7 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
*out_result_json = yyjson_mut_write(doc, 0, NULL);
yyjson_mut_doc_free(doc);
free(acct_ids);
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return 0;
}
@@ -722,13 +731,13 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
}
sqlite3_finalize(st);
if (!exists) {
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "NOT_FOUND", "attachment %lld does not exist",
(long long)aid);
}
if (linked) {
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
free(series_owned);
return fail(e, "CONFLICT", "attachment %lld is already linked",
(long long)aid);
@@ -783,10 +792,13 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
}
}
- if (sqlite3_exec(db, "COMMIT", NULL, NULL, NULL) != SQLITE_OK) {
- free(result_json);
- free(series_owned);
- return fail(e, "DB_BUSY", "commit failed: %s", sqlite3_errmsg(db));
+ if (!o->already_in_tx) {
+ if (sqlite3_exec(db, "COMMIT", NULL, NULL, NULL) != SQLITE_OK) {
+ free(result_json);
+ free(series_owned);
+ return fail(e, "DB_BUSY", "commit failed: %s",
+ sqlite3_errmsg(db));
+ }
}
free(series_owned);
*out_result_json = result_json;
@@ -794,7 +806,7 @@ int ledger_post(sqlite3 *db, const struct ledger_post_opts *o,
busy:
free(series_owned);
- sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ tx_rollback(db, !o->already_in_tx);
e->code = "DB_BUSY";
if (!e->msg[0])
snprintf(e->msg, sizeof e->msg, "database error: %s",