mirror of
https://github.com/denoland/deno.git
synced 2025-02-01 12:16:11 -05:00
fix(ext/node): throw RangeError when sqlite INTEGER is too large (#27907)
Signed-off-by: Divy Srivastava <dj.srivastava23@gmail.com>
This commit is contained in:
parent
9da6a20e57
commit
7d19668255
3 changed files with 23 additions and 5 deletions
|
@ -38,4 +38,7 @@ pub enum SqliteError {
|
||||||
#[class(generic)]
|
#[class(generic)]
|
||||||
#[error("Invalid constructor")]
|
#[error("Invalid constructor")]
|
||||||
InvalidConstructor,
|
InvalidConstructor,
|
||||||
|
#[class(range)]
|
||||||
|
#[error("The value of column {0} is too large to be represented as a JavaScript number: {1}")]
|
||||||
|
NumberTooLarge(i32, i64),
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ use serde::Serialize;
|
||||||
|
|
||||||
use super::SqliteError;
|
use super::SqliteError;
|
||||||
|
|
||||||
|
// ECMA-262, 15th edition, 21.1.2.6. Number.MAX_SAFE_INTEGER (2^53-1)
|
||||||
|
const MAX_SAFE_JS_INTEGER: i64 = 9007199254740991;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RunStatementResult {
|
pub struct RunStatementResult {
|
||||||
|
@ -122,17 +125,19 @@ impl StatementSync {
|
||||||
&self,
|
&self,
|
||||||
index: i32,
|
index: i32,
|
||||||
scope: &mut v8::HandleScope<'a>,
|
scope: &mut v8::HandleScope<'a>,
|
||||||
) -> v8::Local<'a, v8::Value> {
|
) -> Result<v8::Local<'a, v8::Value>, SqliteError> {
|
||||||
// SAFETY: `self.inner` is a valid pointer to a sqlite3_stmt
|
// SAFETY: `self.inner` is a valid pointer to a sqlite3_stmt
|
||||||
// as it lives as long as the StatementSync instance.
|
// as it lives as long as the StatementSync instance.
|
||||||
unsafe {
|
unsafe {
|
||||||
match ffi::sqlite3_column_type(self.inner, index) {
|
Ok(match ffi::sqlite3_column_type(self.inner, index) {
|
||||||
ffi::SQLITE_INTEGER => {
|
ffi::SQLITE_INTEGER => {
|
||||||
let value = ffi::sqlite3_column_int64(self.inner, index);
|
let value = ffi::sqlite3_column_int64(self.inner, index);
|
||||||
if self.use_big_ints.get() {
|
if self.use_big_ints.get() {
|
||||||
v8::BigInt::new_from_i64(scope, value).into()
|
v8::BigInt::new_from_i64(scope, value).into()
|
||||||
} else {
|
} else if value.abs() <= MAX_SAFE_JS_INTEGER {
|
||||||
v8::Integer::new(scope, value as _).into()
|
v8::Integer::new(scope, value as _).into()
|
||||||
|
} else {
|
||||||
|
return Err(SqliteError::NumberTooLarge(index, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ffi::SQLITE_FLOAT => {
|
ffi::SQLITE_FLOAT => {
|
||||||
|
@ -162,7 +167,7 @@ impl StatementSync {
|
||||||
}
|
}
|
||||||
ffi::SQLITE_NULL => v8::null(scope).into(),
|
ffi::SQLITE_NULL => v8::null(scope).into(),
|
||||||
_ => v8::undefined(scope).into(),
|
_ => v8::undefined(scope).into(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +188,7 @@ impl StatementSync {
|
||||||
let mut values = Vec::with_capacity(num_cols);
|
let mut values = Vec::with_capacity(num_cols);
|
||||||
|
|
||||||
for (index, name) in iter {
|
for (index, name) in iter {
|
||||||
let value = self.column_value(index, scope);
|
let value = self.column_value(index, scope)?;
|
||||||
let name =
|
let name =
|
||||||
v8::String::new_from_utf8(scope, name, v8::NewStringType::Normal)
|
v8::String::new_from_utf8(scope, name, v8::NewStringType::Normal)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -73,6 +73,16 @@ Deno.test("[node/sqlite] StatementSync read bigints are supported", () => {
|
||||||
assertEquals(stmt.get(), { key: 1n, __proto__: null });
|
assertEquals(stmt.get(), { key: 1n, __proto__: null });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test("[node/sqlite] StatementSync integer too large", () => {
|
||||||
|
const db = new DatabaseSync(":memory:");
|
||||||
|
db.exec("CREATE TABLE data(key INTEGER PRIMARY KEY);");
|
||||||
|
db.prepare("INSERT INTO data (key) VALUES (?)").run(
|
||||||
|
Number.MAX_SAFE_INTEGER + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThrows(() => db.prepare("SELECT * FROM data").get());
|
||||||
|
});
|
||||||
|
|
||||||
Deno.test("[node/sqlite] StatementSync blob are Uint8Array", () => {
|
Deno.test("[node/sqlite] StatementSync blob are Uint8Array", () => {
|
||||||
const db = new DatabaseSync(":memory:");
|
const db = new DatabaseSync(":memory:");
|
||||||
const obj = db.prepare("select cast('test' as blob)").all();
|
const obj = db.prepare("select cast('test' as blob)").all();
|
||||||
|
|
Loading…
Add table
Reference in a new issue