Skip to content

Commit

Permalink
fix(ext/node): SQLite reset guards to prevent database locks (#28298)
Browse files Browse the repository at this point in the history
Fixes #28295
  • Loading branch information
littledivy authored Feb 25, 2025
1 parent b9cffda commit e66ef32
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
19 changes: 15 additions & 4 deletions ext/node/ops/sqlite/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,14 @@ impl StatementSync {
}
}

struct ResetGuard<'a>(&'a StatementSync);

impl<'a> Drop for ResetGuard<'a> {
fn drop(&mut self) {
let _ = self.0.reset();
}
}

// Represents a single prepared statement. Cannot be initialized directly via constructor.
// Instances are created using `DatabaseSync#prepare`.
//
Expand All @@ -416,6 +424,8 @@ impl StatementSync {

self.bind_params(scope, params)?;

let _reset = ResetGuard(self);

let entry = self.read_row(scope)?;
let result = entry
.map(|r| r.into())
Expand All @@ -438,9 +448,10 @@ impl StatementSync {
let db = db.as_ref().ok_or(SqliteError::InUse)?;

self.bind_params(scope, params)?;
self.step()?;

self.reset()?;
let _reset = ResetGuard(self);

self.step()?;

Ok(RunStatementResult {
last_insert_rowid: db.last_insert_rowid(),
Expand All @@ -460,12 +471,12 @@ impl StatementSync {
let mut arr = vec![];

self.bind_params(scope, params)?;

let _reset = ResetGuard(self);
while let Some(result) = self.read_row(scope)? {
arr.push(result.into());
}

self.reset()?;

let arr = v8::Array::new_with_elements(scope, &arr);
Ok(arr)
}
Expand Down
14 changes: 14 additions & 0 deletions tests/unit_node/sqlite_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,17 @@ Deno.test("[node/sqlite] error message", () => {
"NOT NULL constraint failed: foo.b",
);
});

// https://github.com/denoland/deno/issues/28295
Deno.test("[node/sqlite] StatementSync reset guards don't lock db", () => {
const db = new DatabaseSync(":memory:");

db.exec("CREATE TABLE foo(a integer, b text)");
db.exec("CREATE TABLE bar(a integer, b text)");

const stmt = db.prepare("SELECT name FROM sqlite_master WHERE type='table' ");

assertEquals(stmt.get(), { name: "foo", __proto__: null });

db.exec("DROP TABLE IF EXISTS foo");
});

0 comments on commit e66ef32

Please sign in to comment.