From 327993564743389205cdfdd0a2fe4beba3bc5edf Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 11 Dec 2024 22:55:37 +0530 Subject: [PATCH] in the mirrorrrr tsh tshh --- ext/node/ops/sqlite/database.rs | 55 +++++-- ext/node/ops/sqlite/mod.rs | 8 + ext/node/ops/sqlite/statement.rs | 273 ++++++++++++++----------------- 3 files changed, 169 insertions(+), 167 deletions(-) diff --git a/ext/node/ops/sqlite/database.rs b/ext/node/ops/sqlite/database.rs index 80dc7e90a0..7643ab154b 100644 --- a/ext/node/ops/sqlite/database.rs +++ b/ext/node/ops/sqlite/database.rs @@ -40,8 +40,15 @@ pub struct DatabaseSync { impl GarbageCollected for DatabaseSync {} +// Represents a single connection to a SQLite database. #[op2] impl DatabaseSync { + // Constructs a new `DatabaseSync` instance. + // + // A SQLite database can be stored in a file or in memory. To + // use a file-backed database, the `location` should be a path. + // To use an in-memory database, the `location` should be special + // name ":memory:". #[constructor] #[cppgc] fn new( @@ -67,8 +74,17 @@ impl DatabaseSync { }) } + // Opens the database specified by `location` of this instance. + // + // This method should only be used when the database is not opened + // via the constructor. An exception is thrown if the database is + // already opened. #[fast] fn open(&self) -> Result<(), SqliteError> { + if self.conn.borrow().is_some() { + return Err(SqliteError::AlreadyOpen); + } + let db = rusqlite::Connection::open(&self.location)?; if self.options.enable_foreign_key_constraints { db.execute("PRAGMA foreign_keys = ON", [])?; @@ -79,8 +95,32 @@ impl DatabaseSync { Ok(()) } + // Closes the database connection. An exception is thrown if the + // database is not open. #[fast] - fn close(&self) {} + fn close(&self) -> Result<(), SqliteError> { + if self.conn.borrow().is_none() { + return Err(SqliteError::AlreadyClosed); + } + + *self.conn.borrow_mut() = None; + Ok(()) + } + + // This method allows one or more SQL statements to be executed + // without returning any results. + // + // This method is a wrapper around sqlite3_exec(). + #[fast] + fn exec(&self, #[string] sql: &str) -> Result<(), SqliteError> { + let db = self.conn.borrow(); + let db = db.as_ref().ok_or(SqliteError::InUse)?; + + let mut stmt = db.prepare_cached(sql)?; + stmt.raw_execute()?; + + Ok(()) + } #[cppgc] fn prepare(&self, #[string] sql: &str) -> Result { @@ -101,7 +141,7 @@ impl DatabaseSync { }; if r != libsqlite3_sys::SQLITE_OK { - panic!("Failed to prepare statement"); + return Err(SqliteError::PrepareFailed); } Ok(StatementSync { @@ -109,15 +149,4 @@ impl DatabaseSync { db: self.conn.clone(), }) } - - #[fast] - fn exec(&self, #[string] sql: &str) -> Result<(), SqliteError> { - let db = self.conn.borrow(); - let db = db.as_ref().ok_or(SqliteError::InUse)?; - - let mut stmt = db.prepare_cached(sql)?; - stmt.raw_execute()?; - - Ok(()) - } } diff --git a/ext/node/ops/sqlite/mod.rs b/ext/node/ops/sqlite/mod.rs index 7a3fae6f81..110399ffb5 100644 --- a/ext/node/ops/sqlite/mod.rs +++ b/ext/node/ops/sqlite/mod.rs @@ -12,10 +12,18 @@ pub enum SqliteError { InUse, #[error("Failed to step statement")] FailedStep, + #[error("Failed to bind parameter. {0}")] + FailedBind(&'static str), #[error("Unknown column type")] UnknownColumnType, #[error("Failed to get SQL")] GetSqlFailed, + #[error("Database is already closed")] + AlreadyClosed, + #[error("Database is already open")] + AlreadyOpen, + #[error("Failed to prepare statement")] + PrepareFailed, #[error(transparent)] Other(deno_core::error::AnyError), } diff --git a/ext/node/ops/sqlite/statement.rs b/ext/node/ops/sqlite/statement.rs index 1c09e777c6..157321815a 100644 --- a/ext/node/ops/sqlite/statement.rs +++ b/ext/node/ops/sqlite/statement.rs @@ -24,6 +24,117 @@ pub struct StatementSync { impl GarbageCollected for StatementSync {} +fn read_entry<'a>( + raw: *mut libsqlite3_sys::sqlite3_stmt, + scope: &mut v8::HandleScope<'a>, +) -> Result>, SqliteError> { + let result = v8::Object::new(scope); + unsafe { + let r = libsqlite3_sys::sqlite3_step(raw); + + if r == libsqlite3_sys::SQLITE_DONE { + return Ok(None); + } + if r != libsqlite3_sys::SQLITE_ROW { + return Err(SqliteError::FailedStep); + } + + let columns = libsqlite3_sys::sqlite3_column_count(raw); + + for i in 0..columns { + let name = libsqlite3_sys::sqlite3_column_name(raw, i); + let name = std::ffi::CStr::from_ptr(name).to_string_lossy().to_string(); + let value = match libsqlite3_sys::sqlite3_column_type(raw, i) { + libsqlite3_sys::SQLITE_INTEGER => { + let value = libsqlite3_sys::sqlite3_column_int64(raw, i); + v8::Integer::new(scope, value as _).into() + } + libsqlite3_sys::SQLITE_FLOAT => { + let value = libsqlite3_sys::sqlite3_column_double(raw, i); + v8::Number::new(scope, value).into() + } + libsqlite3_sys::SQLITE_TEXT => { + let value = libsqlite3_sys::sqlite3_column_text(raw, i); + let value = std::ffi::CStr::from_ptr(value as _) + .to_string_lossy() + .to_string(); + v8::String::new_from_utf8( + scope, + value.as_bytes(), + v8::NewStringType::Normal, + ) + .unwrap() + .into() + } + libsqlite3_sys::SQLITE_BLOB => { + let value = libsqlite3_sys::sqlite3_column_blob(raw, i); + let size = libsqlite3_sys::sqlite3_column_bytes(raw, i); + let value = + std::slice::from_raw_parts(value as *const u8, size as usize); + let value = + v8::ArrayBuffer::new_backing_store_from_vec(value.to_vec()) + .make_shared(); + v8::ArrayBuffer::with_backing_store(scope, &value).into() + } + libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(), + _ => { + return Err(SqliteError::UnknownColumnType); + } + }; + + let name = v8::String::new_from_utf8( + scope, + name.as_bytes(), + v8::NewStringType::Normal, + ) + .unwrap() + .into(); + result.set(scope, name, value); + } + } + + Ok(Some(result)) +} + +fn bind_params( + scope: &mut v8::HandleScope, + raw: *mut libsqlite3_sys::sqlite3_stmt, + params: Option<&v8::FunctionCallbackArguments>, +) -> Result<(), SqliteError> { + if let Some(params) = params { + let len = params.length(); + for i in 0..len { + let value = params.get(i); + + if value.is_number() { + let value = value.number_value(scope).unwrap(); + unsafe { + libsqlite3_sys::sqlite3_bind_double(raw, i as i32 + 1, value); + } + } else if value.is_string() { + let value = value.to_rust_string_lossy(scope); + unsafe { + libsqlite3_sys::sqlite3_bind_text( + raw, + i as i32 + 1, + value.as_ptr() as *const i8, + value.len() as i32, + libsqlite3_sys::SQLITE_TRANSIENT(), + ); + } + } else if value.is_null() { + unsafe { + libsqlite3_sys::sqlite3_bind_null(raw, i as i32 + 1); + } + } else { + return Err(SqliteError::FailedBind("Unsupported type")); + } + } + } + + Ok(()) +} + #[op2] impl StatementSync { #[constructor] @@ -39,72 +150,16 @@ impl StatementSync { ) -> Result, SqliteError> { let raw = self.inner; - let result = v8::Object::new(scope); unsafe { libsqlite3_sys::sqlite3_reset(raw); + } - let r = libsqlite3_sys::sqlite3_step(raw); + bind_params(scope, raw, params)?; - if r == libsqlite3_sys::SQLITE_DONE { - return Ok(v8::Object::new(scope)); - } - if r != libsqlite3_sys::SQLITE_ROW { - return Err(SqliteError::FailedStep); - } - - let columns = libsqlite3_sys::sqlite3_column_count(raw); - - for i in 0..columns { - let name = libsqlite3_sys::sqlite3_column_name(raw, i); - let name = std::ffi::CStr::from_ptr(name).to_string_lossy().to_string(); - let value = match libsqlite3_sys::sqlite3_column_type(raw, i) { - libsqlite3_sys::SQLITE_INTEGER => { - let value = libsqlite3_sys::sqlite3_column_int64(raw, i); - v8::Integer::new(scope, value as _).into() - } - libsqlite3_sys::SQLITE_FLOAT => { - let value = libsqlite3_sys::sqlite3_column_double(raw, i); - v8::Number::new(scope, value).into() - } - libsqlite3_sys::SQLITE_TEXT => { - let value = libsqlite3_sys::sqlite3_column_text(raw, i); - let value = std::ffi::CStr::from_ptr(value as _) - .to_string_lossy() - .to_string(); - v8::String::new_from_utf8( - scope, - value.as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap() - .into() - } - libsqlite3_sys::SQLITE_BLOB => { - let value = libsqlite3_sys::sqlite3_column_blob(raw, i); - let size = libsqlite3_sys::sqlite3_column_bytes(raw, i); - let value = - std::slice::from_raw_parts(value as *const u8, size as usize); - let value = - v8::ArrayBuffer::new_backing_store_from_vec(value.to_vec()) - .make_shared(); - v8::ArrayBuffer::with_backing_store(scope, &value).into() - } - libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(), - _ => { - return Err(SqliteError::UnknownColumnType); - } - }; - - let name = v8::String::new_from_utf8( - scope, - name.as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap() - .into(); - result.set(scope, name, value); - } + let result = read_entry(raw, scope) + .map(|r| r.unwrap_or_else(|| v8::Object::new(scope)))?; + unsafe { libsqlite3_sys::sqlite3_reset(raw); } @@ -127,6 +182,7 @@ impl StatementSync { unsafe { libsqlite3_sys::sqlite3_reset(raw); + bind_params(scope, raw, params)?; loop { let r = libsqlite3_sys::sqlite3_step(raw); if r == libsqlite3_sys::SQLITE_DONE { @@ -157,71 +213,9 @@ impl StatementSync { let mut arr = vec![]; unsafe { libsqlite3_sys::sqlite3_reset(raw); - loop { - let result = v8::Object::new(scope); - - let r = libsqlite3_sys::sqlite3_step(raw); - if r == libsqlite3_sys::SQLITE_DONE { - break; - } - if r != libsqlite3_sys::SQLITE_ROW { - return Err(SqliteError::FailedStep); - } - - let columns = libsqlite3_sys::sqlite3_column_count(raw); - - for i in 0..columns { - let name = libsqlite3_sys::sqlite3_column_name(raw, i); - let name = - std::ffi::CStr::from_ptr(name).to_string_lossy().to_string(); - let value = match libsqlite3_sys::sqlite3_column_type(raw, i) { - libsqlite3_sys::SQLITE_INTEGER => { - let value = libsqlite3_sys::sqlite3_column_int64(raw, i); - v8::Integer::new(scope, value as _).into() - } - libsqlite3_sys::SQLITE_FLOAT => { - let value = libsqlite3_sys::sqlite3_column_double(raw, i); - v8::Number::new(scope, value).into() - } - libsqlite3_sys::SQLITE_TEXT => { - let value = libsqlite3_sys::sqlite3_column_text(raw, i); - let value = std::ffi::CStr::from_ptr(value as _) - .to_string_lossy() - .to_string(); - v8::String::new_from_utf8( - scope, - value.as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap() - .into() - } - libsqlite3_sys::SQLITE_BLOB => { - let value = libsqlite3_sys::sqlite3_column_blob(raw, i); - let size = libsqlite3_sys::sqlite3_column_bytes(raw, i); - let value = - std::slice::from_raw_parts(value as *const u8, size as usize); - let value = - v8::ArrayBuffer::new_backing_store_from_vec(value.to_vec()) - .make_shared(); - v8::ArrayBuffer::with_backing_store(scope, &value).into() - } - libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(), - _ => { - return Err(SqliteError::UnknownColumnType); - } - }; - - let name = v8::String::new_from_utf8( - scope, - name.as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap() - .into(); - result.set(scope, name, value); - } + bind_params(scope, raw, params)?; + while let Some(result) = read_entry(raw, scope)? { arr.push(result.into()); } @@ -231,33 +225,4 @@ impl StatementSync { let arr = v8::Array::new_with_elements(scope, &arr); Ok(arr) } - - #[string] - fn source_sql(&self) -> Result { - let raw = unsafe { libsqlite3_sys::sqlite3_sql(self.inner) }; - - if raw.is_null() { - return Err(SqliteError::GetSqlFailed); - } - - let cstr = unsafe { std::ffi::CStr::from_ptr(raw) }; - let sql = cstr.to_string_lossy().to_string(); - - Ok(sql) - } - - #[string] - fn expanded_SQL(&self) -> Result { - let raw = unsafe { libsqlite3_sys::sqlite3_expanded_sql(self.inner) }; - if raw.is_null() { - return Err(SqliteError::GetSqlFailed); - } - - let cstr = unsafe { std::ffi::CStr::from_ptr(raw) }; - let expanded_sql = cstr.to_string_lossy().to_string(); - - unsafe { libsqlite3_sys::sqlite3_free(raw as *mut std::ffi::c_void) }; - - Ok(expanded_sql) - } }