fix(ext/node): SQLite reset guards to prevent database locks (#28298)

Fixes https://github.com/denoland/deno/issues/28295
This commit is contained in:
Divy Srivastava 2025-02-25 19:27:55 +05:30 committed by GitHub
parent b9cffda7c9
commit e66ef32a8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 4 deletions

View file

@ -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. // Represents a single prepared statement. Cannot be initialized directly via constructor.
// Instances are created using `DatabaseSync#prepare`. // Instances are created using `DatabaseSync#prepare`.
// //
@ -416,6 +424,8 @@ impl StatementSync {
self.bind_params(scope, params)?; self.bind_params(scope, params)?;
let _reset = ResetGuard(self);
let entry = self.read_row(scope)?; let entry = self.read_row(scope)?;
let result = entry let result = entry
.map(|r| r.into()) .map(|r| r.into())
@ -438,9 +448,10 @@ impl StatementSync {
let db = db.as_ref().ok_or(SqliteError::InUse)?; let db = db.as_ref().ok_or(SqliteError::InUse)?;
self.bind_params(scope, params)?; self.bind_params(scope, params)?;
self.step()?;
self.reset()?; let _reset = ResetGuard(self);
self.step()?;
Ok(RunStatementResult { Ok(RunStatementResult {
last_insert_rowid: db.last_insert_rowid(), last_insert_rowid: db.last_insert_rowid(),
@ -460,12 +471,12 @@ impl StatementSync {
let mut arr = vec![]; let mut arr = vec![];
self.bind_params(scope, params)?; self.bind_params(scope, params)?;
let _reset = ResetGuard(self);
while let Some(result) = self.read_row(scope)? { while let Some(result) = self.read_row(scope)? {
arr.push(result.into()); arr.push(result.into());
} }
self.reset()?;
let arr = v8::Array::new_with_elements(scope, &arr); let arr = v8::Array::new_with_elements(scope, &arr);
Ok(arr) Ok(arr)
} }

View file

@ -272,3 +272,17 @@ Deno.test("[node/sqlite] error message", () => {
"NOT NULL constraint failed: foo.b", "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");
});