commit bcf81facaa8ee6f5bf40e44c52540943aa7dbf51
parent 90c15be14a45fa6ac5e7afb90f573141936a0a4c
Author: Florian Dold <dold@taler.net>
Date: Sun, 9 Aug 2026 18:44:00 +0200
sqlite: reset getFirst statements before returning
Diffstat:
2 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/tart_module.c b/tart_module.c
@@ -2102,14 +2102,15 @@ static JSValue js_sqlite3_stmt_get_first(JSContext *ctx, JSValue this_val,
goto fail;
}
ret_val = row_obj;
- goto done;
+ goto reset;
}
case SQLITE_DONE: {
ret_val = JS_UNDEFINED;
- goto done;
+ goto reset;
}
default:
ret_val = throw_sqlite3_error(ctx, db);
+ sqlite3_reset(stmt);
goto done;
}
}
@@ -2124,7 +2125,7 @@ done:
return ret_val;
fail:
ret_val = JS_EXCEPTION;
- goto done;
+ goto reset;
}
diff --git a/tests/test_sqlite3_error.js b/tests/test_sqlite3_error.js
@@ -0,0 +1,32 @@
+import * as os from "os";
+import * as tart from "tart";
+
+const dbPath = `/tmp/qtart-sqlite3-get-first-${Date.now()}.sqlite3`;
+let db;
+let stmt;
+
+try {
+ db = tart.sqlite3Open(dbPath);
+ tart.sqlite3Exec(db, "CREATE TABLE entries (value TEXT)");
+ tart.sqlite3Exec(db, "INSERT INTO entries VALUES ('one')");
+
+ stmt = tart.sqlite3Prepare(db, "SELECT value FROM entries");
+ const row = tart.sqlite3StmtGetFirst(stmt);
+ if (row?.value !== "one") {
+ throw Error(`unexpected first row: ${JSON.stringify(row)}`);
+ }
+
+ // Changing into WAL fails while another statement on the connection is
+ // still active. sqlite3StmtGetFirst must reset its SELECT before returning.
+ tart.sqlite3Exec(db, "PRAGMA journal_mode = WAL");
+} finally {
+ if (stmt !== undefined) {
+ tart.sqlite3Finalize(stmt);
+ }
+ if (db !== undefined) {
+ tart.sqlite3Close(db);
+ }
+ os.remove(dbPath);
+ os.remove(`${dbPath}-wal`);
+ os.remove(`${dbPath}-shm`);
+}