mirror of
https://github.com/fluencelabs/sqlite-wasm-connector
synced 2025-03-15 06:20:50 +00:00
Refactor the error handling
This commit is contained in:
parent
dd47f92a1f
commit
bde720bddc
@ -30,8 +30,8 @@ impl<'l> Database<'l> {
|
||||
#[inline]
|
||||
pub fn execute(&self, sql: &str) -> Result<()> {
|
||||
unsafe {
|
||||
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None, 0 as *mut _,
|
||||
0 as *mut _));
|
||||
success!(self.raw, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None, 0 as *mut _,
|
||||
0 as *mut _));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -46,10 +46,10 @@ impl<'l> Database<'l> {
|
||||
{
|
||||
unsafe {
|
||||
let callback = Box::new(callback);
|
||||
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql),
|
||||
Some(execute_callback::<F>),
|
||||
&*callback as *const _ as *mut _ as *mut _,
|
||||
0 as *mut _));
|
||||
success!(self.raw, raw::sqlite3_exec(self.raw, str_to_c_str!(sql),
|
||||
Some(execute_callback::<F>),
|
||||
&*callback as *const _ as *mut _ as *mut _,
|
||||
0 as *mut _));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -57,7 +57,7 @@ impl<'l> Database<'l> {
|
||||
/// Create a prepared statement.
|
||||
#[inline]
|
||||
pub fn prepare(&'l self, sql: &str) -> Result<Statement<'l>> {
|
||||
::statement::new(self, sql)
|
||||
::statement::new(self.raw, sql)
|
||||
}
|
||||
|
||||
/// Set a callback for handling busy events.
|
||||
@ -74,7 +74,7 @@ impl<'l> Database<'l> {
|
||||
let result = raw::sqlite3_busy_handler(self.raw, Some(busy_callback::<F>),
|
||||
&*callback as *const _ as *mut _ as *mut _);
|
||||
self.busy_callback = Some(callback);
|
||||
success!(result);
|
||||
success!(self.raw, result);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -83,7 +83,7 @@ impl<'l> Database<'l> {
|
||||
/// rejected operations until a timeout expires.
|
||||
#[inline]
|
||||
pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
|
||||
unsafe { success!(self, raw::sqlite3_busy_timeout(self.raw, milliseconds as c_int)) };
|
||||
unsafe { success!(self.raw, raw::sqlite3_busy_timeout(self.raw, milliseconds as c_int)) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ impl<'l> Database<'l> {
|
||||
#[inline]
|
||||
pub fn remove_busy_handler(&mut self) -> Result<()> {
|
||||
::std::mem::replace(&mut self.busy_callback, None);
|
||||
unsafe { success!(raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _)) };
|
||||
unsafe { success!(self.raw, raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _)) };
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -105,11 +105,6 @@ impl<'l> Drop for Database<'l> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_raw(database: &Database) -> *mut raw::sqlite3 {
|
||||
database.raw
|
||||
}
|
||||
|
||||
extern fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
|
||||
where F: FnMut(usize) -> bool
|
||||
{
|
||||
|
39
src/error.rs
39
src/error.rs
@ -2,7 +2,7 @@ use raw;
|
||||
use std::convert::{From, Into};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use {Database, ResultCode};
|
||||
use ResultCode;
|
||||
|
||||
/// An error.
|
||||
#[derive(Debug)]
|
||||
@ -11,26 +11,6 @@ pub struct Error {
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Return the last occurred error if any.
|
||||
pub fn last(database: &Database) -> Option<Error> {
|
||||
unsafe {
|
||||
let code = raw::sqlite3_errcode(::database::as_raw(database));
|
||||
if code == raw::SQLITE_OK {
|
||||
return None;
|
||||
}
|
||||
let message = raw::sqlite3_errmsg(::database::as_raw(database));
|
||||
if message.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(Error {
|
||||
code: ::result::code_from_raw(code),
|
||||
message: Some(c_str_to_string!(message)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Error where T: Into<String> {
|
||||
#[inline]
|
||||
fn from(message: T) -> Error {
|
||||
@ -59,3 +39,20 @@ impl Display for Error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last(raw: *mut raw::sqlite3) -> Option<Error> {
|
||||
unsafe {
|
||||
let code = raw::sqlite3_errcode(raw);
|
||||
if code == raw::SQLITE_OK {
|
||||
return None;
|
||||
}
|
||||
let message = raw::sqlite3_errmsg(raw);
|
||||
if message.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(Error {
|
||||
code: ::result::code_from_raw(code),
|
||||
message: Some(c_str_to_string!(message)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
16
src/lib.rs
16
src/lib.rs
@ -10,14 +10,20 @@ macro_rules! raise(
|
||||
($message:expr) => (return Err(::Error::from($message)));
|
||||
);
|
||||
|
||||
macro_rules! failure(
|
||||
($database:expr, $code:expr) => (
|
||||
match ::error::last($database) {
|
||||
Some(error) => return Err(error),
|
||||
None => return Err(::Error::from(::result::code_from_raw($code))),
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
macro_rules! success(
|
||||
($database:expr, $result:expr) => (
|
||||
match $result {
|
||||
::raw::SQLITE_OK => {},
|
||||
code => match ::Error::last($database) {
|
||||
Some(error) => return Err(error),
|
||||
None => return Err(::Error::from(::result::code_from_raw(code))),
|
||||
},
|
||||
code => failure!($database, code),
|
||||
}
|
||||
);
|
||||
($result:expr) => (
|
||||
@ -64,7 +70,7 @@ mod statement;
|
||||
pub use error::Error;
|
||||
pub use database::Database;
|
||||
pub use result::{Result, ResultCode};
|
||||
pub use statement::{Statement, Binding, Value};
|
||||
pub use statement::{Statement, Binding, Value, State};
|
||||
|
||||
/// Open a database.
|
||||
#[inline]
|
||||
|
@ -2,12 +2,12 @@ use libc::{c_double, c_int};
|
||||
use raw;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use {Database, Result, ResultCode};
|
||||
use Result;
|
||||
|
||||
/// A prepared statement.
|
||||
pub struct Statement<'l> {
|
||||
raw: *mut raw::sqlite3_stmt,
|
||||
phantom: PhantomData<(&'l raw::sqlite3, raw::sqlite3_stmt)>,
|
||||
raw: (*mut raw::sqlite3_stmt, *mut raw::sqlite3),
|
||||
phantom: PhantomData<(raw::sqlite3_stmt, &'l raw::sqlite3)>,
|
||||
}
|
||||
|
||||
/// A binding of a parameter of a prepared statement.
|
||||
@ -23,6 +23,13 @@ pub trait Value {
|
||||
fn read(statement: &Statement, i: usize) -> Result<Self>;
|
||||
}
|
||||
|
||||
/// A state of a prepared statement.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum State {
|
||||
Done,
|
||||
Row,
|
||||
}
|
||||
|
||||
impl<'l> Statement<'l> {
|
||||
/// Bind values to the parameters.
|
||||
///
|
||||
@ -32,17 +39,18 @@ impl<'l> Statement<'l> {
|
||||
match *binding {
|
||||
Binding::Float(i, value) => unsafe {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
success!(raw::sqlite3_bind_double(self.raw, i as c_int, value as c_double));
|
||||
success!(self.raw.1, raw::sqlite3_bind_double(self.raw.0, i as c_int,
|
||||
value as c_double));
|
||||
},
|
||||
Binding::Integer(i, value) => unsafe {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
success!(raw::sqlite3_bind_int64(self.raw, i as c_int,
|
||||
value as raw::sqlite3_int64));
|
||||
success!(self.raw.1, raw::sqlite3_bind_int64(self.raw.0, i as c_int,
|
||||
value as raw::sqlite3_int64));
|
||||
},
|
||||
Binding::Text(i, value) => unsafe {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
success!(raw::sqlite3_bind_text(self.raw, i as c_int, str_to_c_str!(value), -1,
|
||||
None));
|
||||
success!(self.raw.1, raw::sqlite3_bind_text(self.raw.0, i as c_int,
|
||||
str_to_c_str!(value), -1, None));
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -58,15 +66,18 @@ impl<'l> Statement<'l> {
|
||||
}
|
||||
|
||||
/// Evaluate the statement.
|
||||
#[inline]
|
||||
pub fn step(&mut self) -> ResultCode {
|
||||
unsafe { ::result::code_from_raw(raw::sqlite3_step(self.raw)) }
|
||||
pub fn step(&mut self) -> Result<State> {
|
||||
match unsafe { raw::sqlite3_step(self.raw.0) } {
|
||||
raw::SQLITE_DONE => Ok(State::Done),
|
||||
raw::SQLITE_ROW => Ok(State::Row),
|
||||
code => failure!(self.raw.1, code),
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the statement.
|
||||
#[inline]
|
||||
pub fn reset(&mut self) -> Result<()> {
|
||||
unsafe { success!(raw::sqlite3_reset(self.raw)) };
|
||||
unsafe { success!(self.raw.1, raw::sqlite3_reset(self.raw.0)) };
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -74,26 +85,26 @@ impl<'l> Statement<'l> {
|
||||
impl<'l> Drop for Statement<'l> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe { ::raw::sqlite3_finalize(self.raw) };
|
||||
unsafe { raw::sqlite3_finalize(self.raw.0) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for f64 {
|
||||
fn read(statement: &Statement, i: usize) -> Result<f64> {
|
||||
Ok(unsafe { ::raw::sqlite3_column_double(statement.raw, i as c_int) as f64 })
|
||||
Ok(unsafe { raw::sqlite3_column_double(statement.raw.0, i as c_int) as f64 })
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for i64 {
|
||||
fn read(statement: &Statement, i: usize) -> Result<i64> {
|
||||
Ok(unsafe { ::raw::sqlite3_column_int64(statement.raw, i as c_int) as i64 })
|
||||
Ok(unsafe { raw::sqlite3_column_int64(statement.raw.0, i as c_int) as i64 })
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for String {
|
||||
fn read(statement: &Statement, i: usize) -> Result<String> {
|
||||
unsafe {
|
||||
let pointer = ::raw::sqlite3_column_text(statement.raw, i as c_int);
|
||||
let pointer = raw::sqlite3_column_text(statement.raw.0, i as c_int);
|
||||
if pointer.is_null() {
|
||||
raise!("cannot read a TEXT column");
|
||||
}
|
||||
@ -103,11 +114,10 @@ impl Value for String {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new<'l>(database: &'l Database, sql: &str) -> Result<Statement<'l>> {
|
||||
let mut raw = 0 as *mut _;
|
||||
pub fn new<'l>(raw1: *mut raw::sqlite3, sql: &str) -> Result<Statement<'l>> {
|
||||
let mut raw0 = 0 as *mut _;
|
||||
unsafe {
|
||||
success!(database, raw::sqlite3_prepare(::database::as_raw(database), str_to_c_str!(sql),
|
||||
-1, &mut raw, 0 as *mut _));
|
||||
success!(raw1, raw::sqlite3_prepare(raw1, str_to_c_str!(sql), -1, &mut raw0, 0 as *mut _));
|
||||
}
|
||||
Ok(Statement { raw: raw, phantom: PhantomData })
|
||||
Ok(Statement { raw: (raw0, raw1), phantom: PhantomData })
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ macro_rules! ok(
|
||||
#[test]
|
||||
fn workflow() {
|
||||
use sqlite::Binding::*;
|
||||
use sqlite::ResultCode;
|
||||
use sqlite::State;
|
||||
|
||||
macro_rules! pair(
|
||||
($one:expr, $two:expr) => ((String::from($one), String::from($two)));
|
||||
@ -27,7 +27,7 @@ fn workflow() {
|
||||
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
|
||||
let mut statement = ok!(database.prepare(sql));
|
||||
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
|
||||
assert!(statement.step() == ResultCode::Done);
|
||||
assert!(ok!(statement.step()) == State::Done);
|
||||
}
|
||||
|
||||
{
|
||||
@ -47,11 +47,11 @@ fn workflow() {
|
||||
{
|
||||
let sql = r#"SELECT * FROM `users`;"#;
|
||||
let mut statement = ok!(database.prepare(sql));
|
||||
assert!(statement.step() == ResultCode::Row);
|
||||
assert!(ok!(statement.step()) == State::Row);
|
||||
assert!(ok!(statement.column::<i64>(0)) == 1);
|
||||
assert!(ok!(statement.column::<String>(1)) == String::from("Alice"));
|
||||
assert!(ok!(statement.column::<f64>(2)) == 20.99);
|
||||
assert!(statement.step() == ResultCode::Done);
|
||||
assert!(ok!(statement.step()) == State::Done);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user