From dccfd7e801a0670bc922b2460d426eece3d7df70 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Sun, 22 May 2016 20:16:54 -0400 Subject: [PATCH] Refactor: Extract ToSql into its own module. --- src/lib.rs | 7 +++- src/named_params.rs | 7 +++- src/types/mod.rs | 95 +-------------------------------------------- src/types/to_sql.rs | 95 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 95 deletions(-) create mode 100644 src/types/to_sql.rs diff --git a/src/lib.rs b/src/lib.rs index f646558..e3894cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -882,7 +882,12 @@ impl<'conn> Statement<'conn> { for (i, p) in params.iter().enumerate() { try!(unsafe { - self.conn.decode_result(p.bind_parameter(self.stmt.ptr(), (i + 1) as c_int)) + self.conn.decode_result( + // This should be + // `p.bind_parameter(self.stmt.ptr(), (i + 1) as c_int)` + // but that doesn't compile until Rust 1.9 due to a compiler bug. + ToSql::bind_parameter(*p, self.stmt.ptr(), (i + 1) as c_int) + ) }); } diff --git a/src/named_params.rs b/src/named_params.rs index d89cc6e..d864736 100644 --- a/src/named_params.rs +++ b/src/named_params.rs @@ -204,7 +204,12 @@ impl<'conn> Statement<'conn> { fn bind_parameters_named(&mut self, params: &[(&str, &ToSql)]) -> Result<()> { for &(name, value) in params { if let Some(i) = try!(self.parameter_index(name)) { - try!(self.conn.decode_result(unsafe { value.bind_parameter(self.stmt.ptr(), i) })); + try!(self.conn.decode_result(unsafe { + // This should be + // `value.bind_parameter(self.stmt.ptr(), i)` + // but that doesn't compile until Rust 1.9 due to a compiler bug. + ToSql::bind_parameter(value, self.stmt.ptr(), i) + })); } else { return Err(Error::InvalidParameterName(name.into())); } diff --git a/src/types/mod.rs b/src/types/mod.rs index c1ec592..6110d25 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -52,106 +52,21 @@ //! } //! ``` -use libc::{c_int, c_double}; -use std::mem; -use super::ffi; -use super::str_to_cstring; - pub use ffi::sqlite3_stmt; pub use ffi::sqlite3_column_type; pub use ffi::{SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, SQLITE_NULL}; pub use self::from_sql::FromSql; +pub use self::to_sql::ToSql; mod from_sql; +mod to_sql; mod time; #[cfg(feature = "chrono")] mod chrono; #[cfg(feature = "serde_json")] mod serde_json; -/// A trait for types that can be converted into SQLite values. -pub trait ToSql { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int; -} - -macro_rules! raw_to_impl( - ($t:ty, $f:ident) => ( - impl ToSql for $t { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - ffi::$f(stmt, col, *self) - } - } - ) -); - -raw_to_impl!(c_int, sqlite3_bind_int); // i32 -raw_to_impl!(i64, sqlite3_bind_int64); -raw_to_impl!(c_double, sqlite3_bind_double); - -impl ToSql for bool { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - if *self { - ffi::sqlite3_bind_int(stmt, col, 1) - } else { - ffi::sqlite3_bind_int(stmt, col, 0) - } - } -} - -impl<'a> ToSql for &'a str { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - let length = self.len(); - if length > ::std::i32::MAX as usize { - return ffi::SQLITE_TOOBIG; - } - match str_to_cstring(self) { - Ok(c_str) => { - ffi::sqlite3_bind_text(stmt, - col, - c_str.as_ptr(), - length as c_int, - ffi::SQLITE_TRANSIENT()) - } - Err(_) => ffi::SQLITE_MISUSE, - } - } -} - -impl ToSql for String { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - (&self[..]).bind_parameter(stmt, col) - } -} - -impl<'a> ToSql for &'a [u8] { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - if self.len() > ::std::i32::MAX as usize { - return ffi::SQLITE_TOOBIG; - } - ffi::sqlite3_bind_blob(stmt, - col, - mem::transmute(self.as_ptr()), - self.len() as c_int, - ffi::SQLITE_TRANSIENT()) - } -} - -impl ToSql for Vec { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - (&self[..]).bind_parameter(stmt, col) - } -} - -impl ToSql for Option { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - match *self { - None => ffi::sqlite3_bind_null(stmt, col), - Some(ref t) => t.bind_parameter(stmt, col), - } - } -} - /// Empty struct that can be used to fill in a query parameter as `NULL`. /// /// ## Example @@ -171,12 +86,6 @@ impl ToSql for Option { #[derive(Copy,Clone)] pub struct Null; -impl ToSql for Null { - unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { - ffi::sqlite3_bind_null(stmt, col) - } -} - /// Dynamic type value (http://sqlite.org/datatype3.html) /// Value's type is dictated by SQLite (not by the caller). #[derive(Clone,Debug,PartialEq)] diff --git a/src/types/to_sql.rs b/src/types/to_sql.rs new file mode 100644 index 0000000..99293b5 --- /dev/null +++ b/src/types/to_sql.rs @@ -0,0 +1,95 @@ +use std::mem; + +use libc::{c_double, c_int}; + +use super::Null; +use ::{ffi, str_to_cstring}; +use ffi::sqlite3_stmt; + +/// A trait for types that can be converted into SQLite values. +pub trait ToSql { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int; +} + +macro_rules! raw_to_impl( + ($t:ty, $f:ident) => ( + impl ToSql for $t { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + ffi::$f(stmt, col, *self) + } + } + ) +); + +raw_to_impl!(c_int, sqlite3_bind_int); // i32 +raw_to_impl!(i64, sqlite3_bind_int64); +raw_to_impl!(c_double, sqlite3_bind_double); + +impl ToSql for bool { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + if *self { + ffi::sqlite3_bind_int(stmt, col, 1) + } else { + ffi::sqlite3_bind_int(stmt, col, 0) + } + } +} + +impl<'a> ToSql for &'a str { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + let length = self.len(); + if length > ::std::i32::MAX as usize { + return ffi::SQLITE_TOOBIG; + } + match str_to_cstring(self) { + Ok(c_str) => { + ffi::sqlite3_bind_text(stmt, + col, + c_str.as_ptr(), + length as c_int, + ffi::SQLITE_TRANSIENT()) + } + Err(_) => ffi::SQLITE_MISUSE, + } + } +} + +impl ToSql for String { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + (&self[..]).bind_parameter(stmt, col) + } +} + +impl<'a> ToSql for &'a [u8] { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + if self.len() > ::std::i32::MAX as usize { + return ffi::SQLITE_TOOBIG; + } + ffi::sqlite3_bind_blob(stmt, + col, + mem::transmute(self.as_ptr()), + self.len() as c_int, + ffi::SQLITE_TRANSIENT()) + } +} + +impl ToSql for Vec { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + (&self[..]).bind_parameter(stmt, col) + } +} + +impl ToSql for Option { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + match *self { + None => ffi::sqlite3_bind_null(stmt, col), + Some(ref t) => t.bind_parameter(stmt, col), + } + } +} + +impl ToSql for Null { + unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int { + ffi::sqlite3_bind_null(stmt, col) + } +}