2015-05-29 11:24:01 -04:00
|
|
|
use libc::{c_double, c_int};
|
|
|
|
use raw;
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
2015-05-29 16:58:48 -04:00
|
|
|
use {Database, Result, ResultCode};
|
2015-05-29 11:24:01 -04:00
|
|
|
|
|
|
|
/// A prepared statement.
|
|
|
|
pub struct Statement<'l> {
|
|
|
|
raw: *mut raw::sqlite3_stmt,
|
2015-06-01 11:39:22 -04:00
|
|
|
phantom: PhantomData<(&'l raw::sqlite3, raw::sqlite3_stmt)>,
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A binding of a prepared statement.
|
|
|
|
pub enum Binding<'l> {
|
|
|
|
Float(usize, f64),
|
|
|
|
Integer(usize, i64),
|
|
|
|
Text(usize, &'l str),
|
|
|
|
}
|
|
|
|
|
2015-05-29 13:34:48 -04:00
|
|
|
/// A value stored in a prepared statement.
|
2015-05-29 13:08:02 -04:00
|
|
|
pub trait Value {
|
2015-05-29 13:34:48 -04:00
|
|
|
/// Read the value at a specific column.
|
2015-06-01 16:30:02 -04:00
|
|
|
fn read(statement: &Statement, i: usize) -> Result<Self>;
|
2015-05-29 13:08:02 -04:00
|
|
|
}
|
|
|
|
|
2015-05-29 11:24:01 -04:00
|
|
|
impl<'l> Statement<'l> {
|
|
|
|
/// Assign values to the placeholders.
|
2015-05-29 13:34:48 -04:00
|
|
|
///
|
|
|
|
/// The leftmost parameter has an index of 1.
|
2015-05-29 11:24:01 -04:00
|
|
|
pub fn bind(&mut self, bindings: &[Binding]) -> Result<()> {
|
|
|
|
for binding in bindings.iter() {
|
|
|
|
match *binding {
|
|
|
|
Binding::Float(i, value) => unsafe {
|
2015-05-29 13:34:48 -04:00
|
|
|
debug_assert!(i > 0, "the indexation starts from 1");
|
2015-05-29 11:24:01 -04:00
|
|
|
success!(raw::sqlite3_bind_double(self.raw, i as c_int, value as c_double));
|
|
|
|
},
|
|
|
|
Binding::Integer(i, value) => unsafe {
|
2015-05-29 13:34:48 -04:00
|
|
|
debug_assert!(i > 0, "the indexation starts from 1");
|
2015-05-29 11:24:01 -04:00
|
|
|
success!(raw::sqlite3_bind_int64(self.raw, i as c_int,
|
|
|
|
value as raw::sqlite3_int64));
|
|
|
|
},
|
|
|
|
Binding::Text(i, value) => unsafe {
|
2015-05-29 13:34:48 -04:00
|
|
|
debug_assert!(i > 0, "the indexation starts from 1");
|
2015-05-29 11:24:01 -04:00
|
|
|
success!(raw::sqlite3_bind_text(self.raw, i as c_int, str_to_c_str!(value),
|
|
|
|
-1, None));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-05-29 13:08:02 -04:00
|
|
|
/// Return the value of a column.
|
|
|
|
#[inline]
|
2015-06-01 16:30:02 -04:00
|
|
|
pub fn column<T: Value>(&self, i: usize) -> Result<T> {
|
2015-05-29 13:08:02 -04:00
|
|
|
<T as Value>::read(self, i)
|
|
|
|
}
|
|
|
|
|
2015-05-29 11:24:01 -04:00
|
|
|
/// Take a step.
|
|
|
|
#[inline]
|
|
|
|
pub fn step(&mut self) -> ResultCode {
|
2015-05-29 13:50:05 -04:00
|
|
|
unsafe { ::result::code_from_raw(raw::sqlite3_step(self.raw)) }
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Reset.
|
|
|
|
#[inline]
|
|
|
|
pub fn reset(&mut self) -> Result<()> {
|
|
|
|
unsafe { success!(raw::sqlite3_reset(self.raw)) };
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'l> Drop for Statement<'l> {
|
|
|
|
#[inline]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe { ::raw::sqlite3_finalize(self.raw) };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-29 13:08:02 -04:00
|
|
|
impl Value for f64 {
|
2015-06-01 16:30:02 -04:00
|
|
|
fn read(statement: &Statement, i: usize) -> Result<f64> {
|
2015-05-29 13:08:02 -04:00
|
|
|
Ok(unsafe { ::raw::sqlite3_column_double(statement.raw, i as c_int) as f64 })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Value for i64 {
|
2015-06-01 16:30:02 -04:00
|
|
|
fn read(statement: &Statement, i: usize) -> Result<i64> {
|
2015-05-29 13:08:02 -04:00
|
|
|
Ok(unsafe { ::raw::sqlite3_column_int64(statement.raw, i as c_int) as i64 })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Value for String {
|
2015-06-01 16:30:02 -04:00
|
|
|
fn read(statement: &Statement, i: usize) -> Result<String> {
|
2015-05-29 13:08:02 -04:00
|
|
|
unsafe {
|
|
|
|
let pointer = ::raw::sqlite3_column_text(statement.raw, i as c_int);
|
|
|
|
if pointer.is_null() {
|
|
|
|
raise!("cannot read a TEXT column");
|
|
|
|
}
|
|
|
|
Ok(c_str_to_string!(pointer))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-29 11:24:01 -04:00
|
|
|
#[inline]
|
2015-06-01 16:27:09 -04:00
|
|
|
pub fn new<'l>(database: &'l Database, sql: &str) -> Result<Statement<'l>> {
|
2015-05-29 16:58:48 -04:00
|
|
|
let mut raw = 0 as *mut _;
|
|
|
|
unsafe {
|
|
|
|
success!(database, raw::sqlite3_prepare(::database::as_raw(database), str_to_c_str!(sql),
|
|
|
|
-1, &mut raw, 0 as *mut _));
|
|
|
|
}
|
2015-05-30 10:31:41 -04:00
|
|
|
Ok(Statement { raw: raw, phantom: PhantomData })
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|