diff --git a/ext/node/ops/sqlite/mod.rs b/ext/node/ops/sqlite/mod.rs index 29c246dae5a468..73eaa847c14c5b 100644 --- a/ext/node/ops/sqlite/mod.rs +++ b/ext/node/ops/sqlite/mod.rs @@ -38,6 +38,9 @@ pub enum SqliteError { #[class(generic)] #[error("Invalid constructor")] InvalidConstructor, + #[class(generic)] + #[error("Expanded SQL text would exceed configured limits")] + InvalidExpandedSql, #[class(range)] #[error("The value of column {0} is too large to be represented as a JavaScript number: {1}")] NumberTooLarge(i32, i64), diff --git a/ext/node/ops/sqlite/statement.rs b/ext/node/ops/sqlite/statement.rs index 1fa8ade59903de..60f2610a0eb9c8 100644 --- a/ext/node/ops/sqlite/statement.rs +++ b/ext/node/ops/sqlite/statement.rs @@ -373,4 +373,38 @@ impl StatementSync { fn set_read_big_ints(&self, enabled: bool) { self.use_big_ints.set(enabled); } + + #[getter] + #[rename("sourceSQL")] + #[string] + fn source_sql(&self) -> String { + // SAFETY: `self.inner` is a valid pointer to a sqlite3_stmt + // as it lives as long as the StatementSync instance. + unsafe { + let raw = ffi::sqlite3_sql(self.inner); + std::ffi::CStr::from_ptr(raw as _) + .to_string_lossy() + .into_owned() + } + } + + #[getter] + #[rename("expandedSQL")] + #[string] + fn expanded_sql(&self) -> Result { + // SAFETY: `self.inner` is a valid pointer to a sqlite3_stmt + // as it lives as long as the StatementSync instance. + unsafe { + let raw = ffi::sqlite3_expanded_sql(self.inner); + if raw.is_null() { + return Err(SqliteError::InvalidExpandedSql); + } + let sql = std::ffi::CStr::from_ptr(raw as _) + .to_string_lossy() + .into_owned(); + ffi::sqlite3_free(raw as _); + + Ok(sql) + } + } } diff --git a/tests/unit_node/sqlite_test.ts b/tests/unit_node/sqlite_test.ts index 43b6914f3c45f2..d75b59546b1462 100644 --- a/tests/unit_node/sqlite_test.ts +++ b/tests/unit_node/sqlite_test.ts @@ -71,6 +71,9 @@ Deno.test("[node/sqlite] StatementSync read bigints are supported", () => { stmt.setReadBigInts(true); assertEquals(stmt.get(), { key: 1n, __proto__: null }); + + assertEquals(stmt.sourceSQL, "SELECT * FROM data"); + assertEquals(stmt.expandedSQL, "SELECT * FROM data"); }); Deno.test("[node/sqlite] StatementSync integer too large", () => {