mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 04:52:26 -05:00
in the mirrorrrr tsh tshh
This commit is contained in:
parent
87574d241e
commit
3279935647
3 changed files with 169 additions and 167 deletions
|
@ -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<StatementSync, SqliteError> {
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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<Option<v8::Local<'a, v8::Object>>, 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<v8::Local<'a, v8::Object>, 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<String, SqliteError> {
|
||||
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<String, SqliteError> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue