2015-06-12 14:23:18 -04:00
|
|
|
use ffi;
|
2015-05-29 11:24:01 -04:00
|
|
|
use libc::{c_double, c_int};
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
2015-06-08 17:43:31 -04:00
|
|
|
use Result;
|
2015-05-29 11:24:01 -04:00
|
|
|
|
|
|
|
/// A prepared statement.
|
|
|
|
pub struct Statement<'l> {
|
2015-06-12 14:23:18 -04:00
|
|
|
raw: (*mut ffi::sqlite3_stmt, *mut ffi::sqlite3),
|
|
|
|
phantom: PhantomData<(ffi::sqlite3_stmt, &'l ffi::sqlite3)>,
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|
|
|
|
|
2015-06-19 11:34:03 -04:00
|
|
|
/// A state of a prepared statement.
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
pub enum State {
|
2015-06-19 13:03:54 -04:00
|
|
|
/// There is a row available for reading.
|
2015-06-19 11:34:03 -04:00
|
|
|
Row,
|
2015-06-19 13:03:54 -04:00
|
|
|
/// There is nothing else to read.
|
|
|
|
Done,
|
2015-06-19 11:34:03 -04:00
|
|
|
}
|
|
|
|
|
2015-06-19 11:31:29 -04:00
|
|
|
/// A parameter of a prepared statement.
|
|
|
|
pub trait Parameter {
|
|
|
|
/// Bind the parameter at a specific location.
|
|
|
|
///
|
|
|
|
/// The leftmost location has the index 1.
|
2015-06-19 13:10:09 -04:00
|
|
|
fn bind(&self, &mut Statement, usize) -> Result<()>;
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|
|
|
|
|
2015-06-19 11:31:29 -04:00
|
|
|
/// A value stored in a prepared statement.
|
2015-05-29 13:08:02 -04:00
|
|
|
pub trait Value {
|
2015-06-08 07:53:28 -04:00
|
|
|
/// Read the value stored in a specific column.
|
2015-06-19 11:31:29 -04:00
|
|
|
///
|
|
|
|
/// The leftmost column has the index 0.
|
|
|
|
fn read(&Statement, usize) -> Result<Self>;
|
2015-05-29 13:08:02 -04:00
|
|
|
}
|
|
|
|
|
2015-05-29 11:24:01 -04:00
|
|
|
impl<'l> Statement<'l> {
|
2015-06-19 11:31:29 -04:00
|
|
|
/// Bind the parameter at a specific location.
|
2015-05-29 13:34:48 -04:00
|
|
|
///
|
2015-06-19 11:31:29 -04:00
|
|
|
/// The leftmost location has the index 1.
|
|
|
|
#[inline]
|
2015-06-19 13:15:42 -04:00
|
|
|
pub fn bind<T: Parameter>(&mut self, i: usize, parameter: T) -> Result<()> {
|
2015-06-19 11:31:29 -04:00
|
|
|
parameter.bind(self, i)
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|
|
|
|
|
2015-06-19 11:31:29 -04:00
|
|
|
/// Read the value stored in a specific column.
|
2015-06-08 07:53:28 -04:00
|
|
|
///
|
|
|
|
/// The leftmost column has the index 0.
|
2015-05-29 13:08:02 -04:00
|
|
|
#[inline]
|
2015-06-19 13:15:42 -04:00
|
|
|
pub fn read<T: Value>(&self, i: usize) -> Result<T> {
|
2015-06-19 11:31:29 -04:00
|
|
|
Value::read(self, i)
|
2015-05-29 13:08:02 -04:00
|
|
|
}
|
|
|
|
|
2015-06-08 07:53:28 -04:00
|
|
|
/// Evaluate the statement.
|
2015-06-08 17:43:31 -04:00
|
|
|
pub fn step(&mut self) -> Result<State> {
|
2015-06-12 14:23:18 -04:00
|
|
|
match unsafe { ffi::sqlite3_step(self.raw.0) } {
|
|
|
|
ffi::SQLITE_DONE => Ok(State::Done),
|
|
|
|
ffi::SQLITE_ROW => Ok(State::Row),
|
2015-06-08 17:43:31 -04:00
|
|
|
code => failure!(self.raw.1, code),
|
|
|
|
}
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|
|
|
|
|
2015-06-08 07:53:28 -04:00
|
|
|
/// Reset the statement.
|
2015-05-29 11:24:01 -04:00
|
|
|
#[inline]
|
|
|
|
pub fn reset(&mut self) -> Result<()> {
|
2015-06-12 14:23:18 -04:00
|
|
|
unsafe { success!(self.raw.1, ffi::sqlite3_reset(self.raw.0)) };
|
2015-05-29 11:24:01 -04:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'l> Drop for Statement<'l> {
|
|
|
|
#[inline]
|
|
|
|
fn drop(&mut self) {
|
2015-06-12 14:23:18 -04:00
|
|
|
unsafe { ffi::sqlite3_finalize(self.raw.0) };
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-19 11:31:29 -04:00
|
|
|
impl Parameter for f64 {
|
|
|
|
#[inline]
|
2015-06-19 13:10:09 -04:00
|
|
|
fn bind(&self, statement: &mut Statement, i: usize) -> Result<()> {
|
2015-06-19 11:31:29 -04:00
|
|
|
debug_assert!(i > 0, "the indexing starts from 1");
|
|
|
|
unsafe {
|
|
|
|
success!(statement.raw.1, ffi::sqlite3_bind_double(statement.raw.0, i as c_int,
|
|
|
|
*self as c_double));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parameter for i64 {
|
|
|
|
#[inline]
|
2015-06-19 13:10:09 -04:00
|
|
|
fn bind(&self, statement: &mut Statement, i: usize) -> Result<()> {
|
2015-06-19 11:31:29 -04:00
|
|
|
debug_assert!(i > 0, "the indexing starts from 1");
|
|
|
|
unsafe {
|
|
|
|
success!(statement.raw.1, ffi::sqlite3_bind_int64(statement.raw.0, i as c_int,
|
|
|
|
*self as ffi::sqlite3_int64));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'l> Parameter for &'l str {
|
|
|
|
#[inline]
|
2015-06-19 13:10:09 -04:00
|
|
|
fn bind(&self, statement: &mut Statement, i: usize) -> Result<()> {
|
2015-06-19 11:31:29 -04:00
|
|
|
debug_assert!(i > 0, "the indexing starts from 1");
|
|
|
|
unsafe {
|
|
|
|
success!(statement.raw.1, ffi::sqlite3_bind_text(statement.raw.0, i as c_int,
|
2015-06-19 11:33:11 -04:00
|
|
|
str_to_c_str!(*self), -1, None));
|
2015-06-19 11:31:29 -04:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-29 13:08:02 -04:00
|
|
|
impl Value for f64 {
|
2015-06-19 11:31:29 -04:00
|
|
|
#[inline]
|
2015-06-01 16:30:02 -04:00
|
|
|
fn read(statement: &Statement, i: usize) -> Result<f64> {
|
2015-06-12 14:23:18 -04:00
|
|
|
Ok(unsafe { ffi::sqlite3_column_double(statement.raw.0, i as c_int) as f64 })
|
2015-05-29 13:08:02 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Value for i64 {
|
2015-06-19 11:31:29 -04:00
|
|
|
#[inline]
|
2015-06-01 16:30:02 -04:00
|
|
|
fn read(statement: &Statement, i: usize) -> Result<i64> {
|
2015-06-12 14:23:18 -04:00
|
|
|
Ok(unsafe { ffi::sqlite3_column_int64(statement.raw.0, i as c_int) as i64 })
|
2015-05-29 13:08:02 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Value for String {
|
2015-06-19 11:31:29 -04:00
|
|
|
#[inline]
|
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 {
|
2015-06-12 14:23:18 -04:00
|
|
|
let pointer = ffi::sqlite3_column_text(statement.raw.0, i as c_int);
|
2015-05-29 13:08:02 -04:00
|
|
|
if pointer.is_null() {
|
2015-06-19 20:24:34 -04:00
|
|
|
raise!("cannot read a text column");
|
2015-05-29 13:08:02 -04:00
|
|
|
}
|
|
|
|
Ok(c_str_to_string!(pointer))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-29 11:24:01 -04:00
|
|
|
#[inline]
|
2015-06-12 14:23:18 -04:00
|
|
|
pub fn new<'l>(raw1: *mut ffi::sqlite3, sql: &str) -> Result<Statement<'l>> {
|
2015-06-08 17:43:31 -04:00
|
|
|
let mut raw0 = 0 as *mut _;
|
2015-05-29 16:58:48 -04:00
|
|
|
unsafe {
|
2015-06-12 14:34:50 -04:00
|
|
|
success!(raw1, ffi::sqlite3_prepare_v2(raw1, str_to_c_str!(sql), -1, &mut raw0,
|
|
|
|
0 as *mut _));
|
2015-05-29 16:58:48 -04:00
|
|
|
}
|
2015-06-08 17:43:31 -04:00
|
|
|
Ok(Statement { raw: (raw0, raw1), phantom: PhantomData })
|
2015-05-29 11:24:01 -04:00
|
|
|
}
|