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>,
}
/// 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.
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;
impl Database {
/// Open a database.
/// Open a database connect.
pub fn open(path: &Path) -> Result<Database> {
let mut raw = 0 as *mut _;
unsafe {
@ -29,50 +29,53 @@ impl Database {
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>>)
-> Result<()> {
unsafe {
match callback {
Some(callback) => {
let mut callback = Box::new(callback);
match callback {
Some(callback) => unsafe {
let mut callback = Box::new(callback);
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql),
Some(execute_callback),
&mut callback as *mut _ as *mut _,
0 as *mut _));
},
None => {
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None,
0 as *mut _, 0 as *mut _));
},
}
},
None => unsafe {
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None,
0 as *mut _, 0 as *mut _));
},
}
Ok(())
}
/// Create a prepared statement.
/// Compile an SQL statement.
#[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)
}
/// 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<()> {
unsafe {
match callback {
Some(callback) => {
let mut callback = Box::new(callback);
success!(self, raw::sqlite3_busy_handler(self.raw, Some(busy_callback),
&mut callback as *mut _ as *mut _));
},
None => {
success!(self, raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _));
},
}
match callback {
Some(callback) => unsafe {
let mut callback = Box::new(callback);
success!(self, raw::sqlite3_busy_handler(self.raw, Some(busy_callback),
&mut callback as *mut _ as *mut _));
},
None => unsafe {
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(())
}
}
impl Drop for Database {

View File

@ -10,58 +10,60 @@ pub struct Statement<'l> {
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> {
Float(usize, f64),
Integer(usize, i64),
Text(usize, &'l str),
}
/// A value stored in a prepared statement.
/// A value stored in a result row of a query.
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>;
}
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<()> {
for binding in bindings.iter() {
match *binding {
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));
},
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,
value as raw::sqlite3_int64));
},
Binding::Text(i, value) => unsafe {
debug_assert!(i > 0, "the indexation starts from 1");
success!(raw::sqlite3_bind_text(self.raw, i as c_int, str_to_c_str!(value),
-1, None));
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));
},
}
}
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]
pub fn column<T: Value>(&self, i: usize) -> Result<T> {
<T as Value>::read(self, i)
}
/// Take a step.
/// Evaluate the statement.
#[inline]
pub fn step(&mut self) -> ResultCode {
unsafe { ::result::code_from_raw(raw::sqlite3_step(self.raw)) }
}
/// Reset.
/// Reset the statement.
#[inline]
pub fn reset(&mut self) -> Result<()> {
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 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)]));
assert!(statement.step() == ResultCode::Done);
}
@ -46,7 +46,7 @@ fn workflow() {
{
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!(ok!(statement.column::<i64>(0)) == 1);
assert!(ok!(statement.column::<String>(1)) == String::from("Alice"));