Rename a couple of functions; add set_busy_timeout

This commit is contained in:
Ivan Ukhov 2015-06-08 07:53:28 -04:00
parent 2698514218
commit bfa3a976c8
3 changed files with 47 additions and 42 deletions

View File

@ -11,7 +11,7 @@ pub struct Database {
phantom: PhantomData<raw::sqlite3>, phantom: PhantomData<raw::sqlite3>,
} }
/// A callback triggered when an operation fails due to concurrent activity. If /// A callback triggered when the database is busy and rejects an operation. If
/// the callback returns `true`, the operation will be repeated. /// the callback returns `true`, the operation will be repeated.
pub type BusyCallback<'l> = FnMut(usize) -> bool + 'l; pub type BusyCallback<'l> = FnMut(usize) -> bool + 'l;
@ -20,7 +20,7 @@ pub type BusyCallback<'l> = FnMut(usize) -> bool + 'l;
pub type ExecuteCallback<'l> = FnMut(Vec<(String, String)>) -> bool + 'l; pub type ExecuteCallback<'l> = FnMut(Vec<(String, String)>) -> bool + 'l;
impl Database { impl Database {
/// Open a database. /// Open a database connect.
pub fn open(path: &Path) -> Result<Database> { pub fn open(path: &Path) -> Result<Database> {
let mut raw = 0 as *mut _; let mut raw = 0 as *mut _;
unsafe { unsafe {
@ -29,48 +29,51 @@ impl Database {
Ok(Database { raw: raw, phantom: PhantomData }) Ok(Database { raw: raw, phantom: PhantomData })
} }
/// Execute an SQL statement. /// Execute an SQL query.
pub fn execute<'l>(&self, sql: &str, callback: Option<&mut ExecuteCallback<'l>>) pub fn execute<'l>(&self, sql: &str, callback: Option<&mut ExecuteCallback<'l>>)
-> Result<()> { -> Result<()> {
unsafe {
match callback { match callback {
Some(callback) => { Some(callback) => unsafe {
let mut callback = Box::new(callback); let mut callback = Box::new(callback);
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql),
Some(execute_callback), Some(execute_callback),
&mut callback as *mut _ as *mut _, &mut callback as *mut _ as *mut _,
0 as *mut _)); 0 as *mut _));
}, },
None => { None => unsafe {
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None, success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None,
0 as *mut _, 0 as *mut _)); 0 as *mut _, 0 as *mut _));
}, },
} }
}
Ok(()) Ok(())
} }
/// Create a prepared statement. /// Compile an SQL statement.
#[inline] #[inline]
pub fn prepare_statement<'l>(&'l self, sql: &str) -> Result<Statement<'l>> { pub fn prepare<'l>(&'l self, sql: &str) -> Result<Statement<'l>> {
::statement::new(self, sql) ::statement::new(self, sql)
} }
/// Set a callback for handling failures due to concurrent activity. /// Set a callback to handle rejected operations when the database is busy.
pub fn set_busy_handler(&mut self, callback: Option<&mut BusyCallback>) -> Result<()> { pub fn set_busy_handler(&mut self, callback: Option<&mut BusyCallback>) -> Result<()> {
unsafe {
match callback { match callback {
Some(callback) => { Some(callback) => unsafe {
let mut callback = Box::new(callback); let mut callback = Box::new(callback);
success!(self, raw::sqlite3_busy_handler(self.raw, Some(busy_callback), success!(self, raw::sqlite3_busy_handler(self.raw, Some(busy_callback),
&mut callback as *mut _ as *mut _)); &mut callback as *mut _ as *mut _));
}, },
None => { None => unsafe {
success!(self, raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _)); success!(self, raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _));
}, },
} }
Ok(())
} }
/// Set a timeout before rejecting an operation when the database is busy.
#[inline]
pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
unsafe { success!(self, raw::sqlite3_busy_timeout(self.raw, milliseconds as c_int)) };
Ok(()) Ok(())
} }
} }

View File

@ -10,58 +10,60 @@ pub struct Statement<'l> {
phantom: PhantomData<(&'l raw::sqlite3, raw::sqlite3_stmt)>, phantom: PhantomData<(&'l raw::sqlite3, raw::sqlite3_stmt)>,
} }
/// A binding of a prepared statement. /// A binding of a parameter of a prepared statement.
pub enum Binding<'l> { pub enum Binding<'l> {
Float(usize, f64), Float(usize, f64),
Integer(usize, i64), Integer(usize, i64),
Text(usize, &'l str), Text(usize, &'l str),
} }
/// A value stored in a prepared statement. /// A value stored in a result row of a query.
pub trait Value { pub trait Value {
/// Read the value at a specific column. /// Read the value stored in a specific column.
fn read(statement: &Statement, i: usize) -> Result<Self>; fn read(statement: &Statement, i: usize) -> Result<Self>;
} }
impl<'l> Statement<'l> { impl<'l> Statement<'l> {
/// Assign values to the placeholders. /// Bind values to the parameters.
/// ///
/// The leftmost parameter has an index of 1. /// The leftmost parameter has the index 1.
pub fn bind(&mut self, bindings: &[Binding]) -> Result<()> { pub fn bind(&mut self, bindings: &[Binding]) -> Result<()> {
for binding in bindings.iter() { for binding in bindings.iter() {
match *binding { match *binding {
Binding::Float(i, value) => unsafe { Binding::Float(i, value) => unsafe {
debug_assert!(i > 0, "the indexation starts from 1"); 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!(raw::sqlite3_bind_double(self.raw, i as c_int, value as c_double));
}, },
Binding::Integer(i, value) => unsafe { Binding::Integer(i, value) => unsafe {
debug_assert!(i > 0, "the indexation starts from 1"); debug_assert!(i > 0, "the indexing starts from 1");
success!(raw::sqlite3_bind_int64(self.raw, i as c_int, success!(raw::sqlite3_bind_int64(self.raw, i as c_int,
value as raw::sqlite3_int64)); value as raw::sqlite3_int64));
}, },
Binding::Text(i, value) => unsafe { Binding::Text(i, value) => unsafe {
debug_assert!(i > 0, "the indexation starts from 1"); 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), success!(raw::sqlite3_bind_text(self.raw, i as c_int, str_to_c_str!(value), -1,
-1, None)); None));
}, },
} }
} }
Ok(()) Ok(())
} }
/// Return the value of a column. /// Return the value stored in a specific column of the current result row.
///
/// The leftmost column has the index 0.
#[inline] #[inline]
pub fn column<T: Value>(&self, i: usize) -> Result<T> { pub fn column<T: Value>(&self, i: usize) -> Result<T> {
<T as Value>::read(self, i) <T as Value>::read(self, i)
} }
/// Take a step. /// Evaluate the statement.
#[inline] #[inline]
pub fn step(&mut self) -> ResultCode { pub fn step(&mut self) -> ResultCode {
unsafe { ::result::code_from_raw(raw::sqlite3_step(self.raw)) } unsafe { ::result::code_from_raw(raw::sqlite3_step(self.raw)) }
} }
/// Reset. /// Reset the statement.
#[inline] #[inline]
pub fn reset(&mut self) -> Result<()> { pub fn reset(&mut self) -> Result<()> {
unsafe { success!(raw::sqlite3_reset(self.raw)) }; unsafe { success!(raw::sqlite3_reset(self.raw)) };

View File

@ -25,7 +25,7 @@ fn workflow() {
{ {
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#; let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
let mut statement = ok!(database.prepare_statement(sql)); let mut statement = ok!(database.prepare(sql));
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)])); ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
assert!(statement.step() == ResultCode::Done); assert!(statement.step() == ResultCode::Done);
} }
@ -46,7 +46,7 @@ fn workflow() {
{ {
let sql = r#"SELECT * FROM `users`;"#; let sql = r#"SELECT * FROM `users`;"#;
let mut statement = ok!(database.prepare_statement(sql)); let mut statement = ok!(database.prepare(sql));
assert!(statement.step() == ResultCode::Row); assert!(statement.step() == ResultCode::Row);
assert!(ok!(statement.column::<i64>(0)) == 1); assert!(ok!(statement.column::<i64>(0)) == 1);
assert!(ok!(statement.column::<String>(1)) == String::from("Alice")); assert!(ok!(statement.column::<String>(1)) == String::from("Alice"));