Run rustfmt on all crate files

This commit is contained in:
John Gallagher 2015-12-10 16:48:09 -05:00
parent 26a7930d73
commit a1f1480b18
5 changed files with 488 additions and 317 deletions

View File

@ -52,17 +52,20 @@
//! ``` //! ```
extern crate libc; extern crate libc;
extern crate libsqlite3_sys as ffi; extern crate libsqlite3_sys as ffi;
#[macro_use] extern crate bitflags; #[macro_use]
#[cfg(test)] #[macro_use] extern crate lazy_static; extern crate bitflags;
#[cfg(test)]
#[macro_use]
extern crate lazy_static;
use std::default::Default; use std::default::Default;
use std::convert; use std::convert;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::fmt; use std::fmt;
use std::path::{Path,PathBuf}; use std::path::{Path, PathBuf};
use std::error; use std::error;
use std::rc::{Rc}; use std::rc::Rc;
use std::cell::{RefCell, Cell}; use std::cell::{RefCell, Cell};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::str; use std::str;
@ -70,19 +73,18 @@ use libc::{c_int, c_void, c_char};
use types::{ToSql, FromSql}; use types::{ToSql, FromSql};
pub use transaction::{SqliteTransaction}; pub use transaction::SqliteTransaction;
pub use transaction::{SqliteTransactionBehavior, pub use transaction::{SqliteTransactionBehavior, SqliteTransactionDeferred,
SqliteTransactionDeferred, SqliteTransactionImmediate, SqliteTransactionExclusive};
SqliteTransactionImmediate,
SqliteTransactionExclusive};
#[cfg(feature = "load_extension")] pub use load_extension_guard::{SqliteLoadExtensionGuard}; #[cfg(feature = "load_extension")]
pub use load_extension_guard::SqliteLoadExtensionGuard;
pub mod types; pub mod types;
mod transaction; mod transaction;
#[cfg(feature = "load_extension")] mod load_extension_guard; #[cfg(feature = "load_extension")]mod load_extension_guard;
#[cfg(feature = "trace")] pub mod trace; #[cfg(feature = "trace")]pub mod trace;
#[cfg(feature = "backup")] pub mod backup; #[cfg(feature = "backup")]pub mod backup;
/// A typedef of the result returned by many methods. /// A typedef of the result returned by many methods.
pub type SqliteResult<T> = Result<T, SqliteError>; pub type SqliteResult<T> = Result<T, SqliteError>;
@ -124,21 +126,27 @@ impl SqliteError {
} else { } else {
unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) } unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) }
}; };
SqliteError{ code: code, message: message } SqliteError {
code: code,
message: message,
}
} }
} }
fn str_to_cstring(s: &str) -> SqliteResult<CString> { fn str_to_cstring(s: &str) -> SqliteResult<CString> {
CString::new(s).map_err(|_| SqliteError{ CString::new(s).map_err(|_| {
code: ffi::SQLITE_MISUSE, SqliteError {
message: format!("Could not convert string {} to C-combatible string", s), code: ffi::SQLITE_MISUSE,
message: format!("Could not convert string {} to C-combatible string", s),
}
}) })
} }
fn path_to_cstring(p: &Path) -> SqliteResult<CString> { fn path_to_cstring(p: &Path) -> SqliteResult<CString> {
let s = try!(p.to_str().ok_or(SqliteError{ let s = try!(p.to_str().ok_or(SqliteError {
code: ffi::SQLITE_MISUSE, code: ffi::SQLITE_MISUSE,
message: format!("Could not convert path {} to UTF-8 string", p.to_string_lossy()), message: format!("Could not convert path {} to UTF-8 string",
p.to_string_lossy()),
})); }));
str_to_cstring(s) str_to_cstring(s)
} }
@ -162,8 +170,8 @@ impl<'a> DatabaseName<'a> {
fn to_cstring(self) -> SqliteResult<CString> { fn to_cstring(self) -> SqliteResult<CString> {
use self::DatabaseName::{Main, Temp, Attached}; use self::DatabaseName::{Main, Temp, Attached};
match self { match self {
Main => str_to_cstring("main"), Main => str_to_cstring("main"),
Temp => str_to_cstring("temp"), Temp => str_to_cstring("temp"),
Attached(s) => str_to_cstring(s), Attached(s) => str_to_cstring(s),
} }
} }
@ -211,13 +219,17 @@ impl SqliteConnection {
/// ///
/// Will return `Err` if `path` cannot be converted to a C-compatible string or if the /// Will return `Err` if `path` cannot be converted to a C-compatible string or if the
/// underlying SQLite open call fails. /// underlying SQLite open call fails.
pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: SqliteOpenFlags) pub fn open_with_flags<P: AsRef<Path>>(path: P,
-> SqliteResult<SqliteConnection> { flags: SqliteOpenFlags)
let c_path = try!(path_to_cstring(path.as_ref())); -> SqliteResult<SqliteConnection> {
InnerSqliteConnection::open_with_flags(&c_path, flags).map(|db| { let c_path = try!(path_to_cstring(path.as_ref()));
SqliteConnection{ db: RefCell::new(db), path: Some(path.as_ref().to_path_buf()) } InnerSqliteConnection::open_with_flags(&c_path, flags).map(|db| {
}) SqliteConnection {
} db: RefCell::new(db),
path: Some(path.as_ref().to_path_buf()),
}
})
}
/// Open a new connection to an in-memory SQLite database. /// Open a new connection to an in-memory SQLite database.
/// ///
@ -230,7 +242,10 @@ impl SqliteConnection {
pub fn open_in_memory_with_flags(flags: SqliteOpenFlags) -> SqliteResult<SqliteConnection> { pub fn open_in_memory_with_flags(flags: SqliteOpenFlags) -> SqliteResult<SqliteConnection> {
let c_memory = try!(str_to_cstring(":memory:")); let c_memory = try!(str_to_cstring(":memory:"));
InnerSqliteConnection::open_with_flags(&c_memory, flags).map(|db| { InnerSqliteConnection::open_with_flags(&c_memory, flags).map(|db| {
SqliteConnection{ db: RefCell::new(db), path: None } SqliteConnection {
db: RefCell::new(db),
path: None,
}
}) })
} }
@ -269,10 +284,11 @@ impl SqliteConnection {
/// # Failure /// # Failure
/// ///
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
pub fn transaction_with_behavior<'a>(&'a self, behavior: SqliteTransactionBehavior) pub fn transaction_with_behavior<'a>(&'a self,
-> SqliteResult<SqliteTransaction<'a>> { behavior: SqliteTransactionBehavior)
SqliteTransaction::new(self, behavior) -> SqliteResult<SqliteTransaction<'a>> {
} SqliteTransaction::new(self, behavior)
}
/// Convenience method to run multiple SQL statements (that cannot take any parameters). /// Convenience method to run multiple SQL statements (that cannot take any parameters).
/// ///
@ -351,18 +367,21 @@ impl SqliteConnection {
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails. /// underlying SQLite call fails.
pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> SqliteResult<T> pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> SqliteResult<T>
where F: FnOnce(SqliteRow) -> T { where F: FnOnce(SqliteRow) -> T
let mut stmt = try!(self.prepare(sql)); {
let mut rows = try!(stmt.query(params)); let mut stmt = try!(self.prepare(sql));
let mut rows = try!(stmt.query(params));
match rows.next() { match rows.next() {
Some(row) => row.map(f), Some(row) => row.map(f),
None => Err(SqliteError{ None => {
code: ffi::SQLITE_NOTICE, Err(SqliteError {
message: "Query did not return a row".to_string(), code: ffi::SQLITE_NOTICE,
}) message: "Query did not return a row".to_string(),
})
}
}
} }
}
/// Convenience method to execute a query that is expected to return a single row, /// Convenience method to execute a query that is expected to return a single row,
/// and execute a mapping via `f` on that returned row with the possibility of failure. /// and execute a mapping via `f` on that returned row with the possibility of failure.
@ -386,19 +405,22 @@ impl SqliteConnection {
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails. /// underlying SQLite call fails.
pub fn query_row_and_then<T, E, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T, E> pub fn query_row_and_then<T, E, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T, E>
where F: FnOnce(SqliteRow) -> Result<T, E>, where F: FnOnce(SqliteRow) -> Result<T, E>,
E: convert::From<SqliteError> { E: convert::From<SqliteError>
let mut stmt = try!(self.prepare(sql)); {
let mut rows = try!(stmt.query(params)); let mut stmt = try!(self.prepare(sql));
let mut rows = try!(stmt.query(params));
match rows.next() { match rows.next() {
Some(row) => row.map_err(E::from).and_then(f), Some(row) => row.map_err(E::from).and_then(f),
None => Err(E::from(SqliteError{ None => {
code: ffi::SQLITE_NOTICE, Err(E::from(SqliteError {
message: "Query did not return a row".to_string(), code: ffi::SQLITE_NOTICE,
})) message: "Query did not return a row".to_string(),
} }))
} }
}
}
/// Convenience method to execute a query that is expected to return a single row. /// Convenience method to execute a query that is expected to return a single row.
/// ///
@ -420,9 +442,10 @@ impl SqliteConnection {
/// This method should be considered deprecated. Use `query_row` instead, which now /// This method should be considered deprecated. Use `query_row` instead, which now
/// does exactly the same thing. /// does exactly the same thing.
pub fn query_row_safe<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> SqliteResult<T> pub fn query_row_safe<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> SqliteResult<T>
where F: FnOnce(SqliteRow) -> T { where F: FnOnce(SqliteRow) -> T
self.query_row(sql, params, f) {
} self.query_row(sql, params, f)
}
/// Prepare a SQL statement for execution. /// Prepare a SQL statement for execution.
/// ///
@ -517,9 +540,12 @@ impl SqliteConnection {
/// ///
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
#[cfg(feature = "load_extension")] #[cfg(feature = "load_extension")]
pub fn load_extension<P: AsRef<Path>>(&self, dylib_path: P, entry_point: Option<&str>) -> SqliteResult<()> { pub fn load_extension<P: AsRef<Path>>(&self,
self.db.borrow_mut().load_extension(dylib_path.as_ref(), entry_point) dylib_path: P,
} entry_point: Option<&str>)
-> SqliteResult<()> {
self.db.borrow_mut().load_extension(dylib_path.as_ref(), entry_point)
}
fn decode_result(&self, code: c_int) -> SqliteResult<()> { fn decode_result(&self, code: c_int) -> SqliteResult<()> {
self.db.borrow_mut().decode_result(code) self.db.borrow_mut().decode_result(code)
@ -561,40 +587,40 @@ bitflags! {
impl Default for SqliteOpenFlags { impl Default for SqliteOpenFlags {
fn default() -> SqliteOpenFlags { fn default() -> SqliteOpenFlags {
SQLITE_OPEN_READ_WRITE SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NO_MUTEX | SQLITE_OPEN_URI
| SQLITE_OPEN_CREATE
| SQLITE_OPEN_NO_MUTEX
| SQLITE_OPEN_URI
} }
} }
impl InnerSqliteConnection { impl InnerSqliteConnection {
fn open_with_flags(c_path: &CString, flags: SqliteOpenFlags) fn open_with_flags(c_path: &CString,
-> SqliteResult<InnerSqliteConnection> { flags: SqliteOpenFlags)
unsafe { -> SqliteResult<InnerSqliteConnection> {
let mut db: *mut ffi::sqlite3 = mem::uninitialized(); unsafe {
let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), ptr::null()); let mut db: *mut ffi::sqlite3 = mem::uninitialized();
if r != ffi::SQLITE_OK { let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), ptr::null());
let e = if db.is_null() { if r != ffi::SQLITE_OK {
SqliteError{ code: r, let e = if db.is_null() {
message: ffi::code_to_str(r).to_string() } SqliteError {
} else { code: r,
message: ffi::code_to_str(r).to_string(),
}
} else {
let e = SqliteError::from_handle(db, r);
ffi::sqlite3_close(db);
e
};
return Err(e);
}
let r = ffi::sqlite3_busy_timeout(db, 5000);
if r != ffi::SQLITE_OK {
let e = SqliteError::from_handle(db, r); let e = SqliteError::from_handle(db, r);
ffi::sqlite3_close(db); ffi::sqlite3_close(db);
e return Err(e);
}; }
Ok(InnerSqliteConnection { db: db })
return Err(e);
} }
let r = ffi::sqlite3_busy_timeout(db, 5000);
if r != ffi::SQLITE_OK {
let e = SqliteError::from_handle(db, r);
ffi::sqlite3_close(db);
return Err(e);
}
Ok(InnerSqliteConnection{ db: db })
} }
}
fn db(&self) -> *mut ffi::Struct_sqlite3 { fn db(&self) -> *mut ffi::Struct_sqlite3 {
self.db self.db
@ -608,15 +634,21 @@ impl InnerSqliteConnection {
} }
} }
unsafe fn decode_result_with_errmsg(&self, code: c_int, errmsg: *mut c_char) -> SqliteResult<()> { unsafe fn decode_result_with_errmsg(&self,
if code == ffi::SQLITE_OK { code: c_int,
Ok(()) errmsg: *mut c_char)
} else { -> SqliteResult<()> {
let message = errmsg_to_string(&*errmsg); if code == ffi::SQLITE_OK {
ffi::sqlite3_free(errmsg as *mut c_void); Ok(())
Err(SqliteError{ code: code, message: message }) } else {
let message = errmsg_to_string(&*errmsg);
ffi::sqlite3_free(errmsg as *mut c_void);
Err(SqliteError {
code: code,
message: message,
})
}
} }
}
fn close(&mut self) -> SqliteResult<()> { fn close(&mut self) -> SqliteResult<()> {
unsafe { unsafe {
@ -630,7 +662,11 @@ impl InnerSqliteConnection {
let c_sql = try!(str_to_cstring(sql)); let c_sql = try!(str_to_cstring(sql));
unsafe { unsafe {
let mut errmsg: *mut c_char = mem::uninitialized(); let mut errmsg: *mut c_char = mem::uninitialized();
let r = ffi::sqlite3_exec(self.db(), c_sql.as_ptr(), None, ptr::null_mut(), &mut errmsg); let r = ffi::sqlite3_exec(self.db(),
c_sql.as_ptr(),
None,
ptr::null_mut(),
&mut errmsg);
self.decode_result_with_errmsg(r, errmsg) self.decode_result_with_errmsg(r, errmsg)
} }
} }
@ -648,7 +684,10 @@ impl InnerSqliteConnection {
let mut errmsg: *mut c_char = mem::uninitialized(); let mut errmsg: *mut c_char = mem::uninitialized();
let r = if let Some(entry_point) = entry_point { let r = if let Some(entry_point) = entry_point {
let c_entry = try!(str_to_cstring(entry_point)); let c_entry = try!(str_to_cstring(entry_point));
ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), c_entry.as_ptr(), &mut errmsg) ffi::sqlite3_load_extension(self.db,
dylib_str.as_ptr(),
c_entry.as_ptr(),
&mut errmsg)
} else { } else {
ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), ptr::null(), &mut errmsg) ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), ptr::null(), &mut errmsg)
}; };
@ -657,34 +696,34 @@ impl InnerSqliteConnection {
} }
fn last_insert_rowid(&self) -> i64 { fn last_insert_rowid(&self) -> i64 {
unsafe { unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
ffi::sqlite3_last_insert_rowid(self.db())
}
} }
fn prepare<'a>(&mut self, fn prepare<'a>(&mut self,
conn: &'a SqliteConnection, conn: &'a SqliteConnection,
sql: &str) -> SqliteResult<SqliteStatement<'a>> { sql: &str)
if sql.len() >= ::std::i32::MAX as usize { -> SqliteResult<SqliteStatement<'a>> {
return Err(SqliteError { if sql.len() >= ::std::i32::MAX as usize {
code: ffi::SQLITE_TOOBIG, return Err(SqliteError {
message: "statement too long".to_string() code: ffi::SQLITE_TOOBIG,
}); message: "statement too long".to_string(),
});
}
let mut c_stmt: *mut ffi::sqlite3_stmt = unsafe { mem::uninitialized() };
let c_sql = try!(str_to_cstring(sql));
let r = unsafe {
let len_with_nul = (sql.len() + 1) as c_int;
ffi::sqlite3_prepare_v2(self.db(),
c_sql.as_ptr(),
len_with_nul,
&mut c_stmt,
ptr::null_mut())
};
self.decode_result(r).map(|_| SqliteStatement::new(conn, c_stmt))
} }
let mut c_stmt: *mut ffi::sqlite3_stmt = unsafe { mem::uninitialized() };
let c_sql = try!(str_to_cstring(sql));
let r = unsafe {
let len_with_nul = (sql.len() + 1) as c_int;
ffi::sqlite3_prepare_v2(self.db(), c_sql.as_ptr(), len_with_nul, &mut c_stmt,
ptr::null_mut())
};
self.decode_result(r).map(|_| {
SqliteStatement::new(conn, c_stmt)
})
}
fn changes(&mut self) -> c_int { fn changes(&mut self) -> c_int {
unsafe{ ffi::sqlite3_changes(self.db()) } unsafe { ffi::sqlite3_changes(self.db()) }
} }
} }
@ -705,8 +744,12 @@ pub struct SqliteStatement<'conn> {
impl<'conn> SqliteStatement<'conn> { impl<'conn> SqliteStatement<'conn> {
fn new(conn: &SqliteConnection, stmt: *mut ffi::sqlite3_stmt) -> SqliteStatement { fn new(conn: &SqliteConnection, stmt: *mut ffi::sqlite3_stmt) -> SqliteStatement {
SqliteStatement{ conn: conn, stmt: stmt, needs_reset: false, SqliteStatement {
column_count: unsafe { ffi::sqlite3_column_count(stmt) }} conn: conn,
stmt: stmt,
needs_reset: false,
column_count: unsafe { ffi::sqlite3_column_count(stmt) },
}
} }
/// Get all the column names in the result set of the prepared statement. /// Get all the column names in the result set of the prepared statement.
@ -714,9 +757,7 @@ impl<'conn> SqliteStatement<'conn> {
let n = self.column_count; let n = self.column_count;
let mut cols = Vec::with_capacity(n as usize); let mut cols = Vec::with_capacity(n as usize);
for i in 0..n { for i in 0..n {
let slice = unsafe { let slice = unsafe { CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, i)) };
CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, i))
};
let s = str::from_utf8(slice.to_bytes()).unwrap(); let s = str::from_utf8(slice.to_bytes()).unwrap();
cols.push(s); cols.push(s);
} }
@ -755,14 +796,21 @@ impl<'conn> SqliteStatement<'conn> {
match r { match r {
ffi::SQLITE_DONE => { ffi::SQLITE_DONE => {
if self.column_count != 0 { if self.column_count != 0 {
Err(SqliteError{ code: ffi::SQLITE_MISUSE, Err(SqliteError {
message: "Unexpected column count - did you mean to call query?".to_string() }) code: ffi::SQLITE_MISUSE,
message: "Unexpected column count - did you mean to call query?"
.to_string(),
})
} else { } else {
Ok(self.conn.changes()) Ok(self.conn.changes())
} }
}, }
ffi::SQLITE_ROW => Err(SqliteError{ code: r, ffi::SQLITE_ROW => {
message: "Unexpected row result - did you mean to call query?".to_string() }), Err(SqliteError {
code: r,
message: "Unexpected row result - did you mean to call query?".to_string(),
})
}
_ => Err(self.conn.decode_result(r).unwrap_err()), _ => Err(self.conn.decode_result(r).unwrap_err()),
} }
} }
@ -811,16 +859,19 @@ impl<'conn> SqliteStatement<'conn> {
/// # Failure /// # Failure
/// ///
/// Will return `Err` if binding parameters fails. /// Will return `Err` if binding parameters fails.
pub fn query_map<'a, T, F>(&'a mut self, params: &[&ToSql], f: F) pub fn query_map<'a, T, F>(&'a mut self,
-> SqliteResult<MappedRows<'a, F>> params: &[&ToSql],
where F: FnMut(&SqliteRow) -> T { f: F)
let row_iter = try!(self.query(params)); -> SqliteResult<MappedRows<'a, F>>
where F: FnMut(&SqliteRow) -> T
{
let row_iter = try!(self.query(params));
Ok(MappedRows{ Ok(MappedRows {
rows: row_iter, rows: row_iter,
map: f, map: f,
}) })
} }
/// Executes the prepared statement and maps a function over the resulting /// Executes the prepared statement and maps a function over the resulting
/// rows, where the function returns a `Result` with `Error` type implementing /// rows, where the function returns a `Result` with `Error` type implementing
@ -832,17 +883,20 @@ impl<'conn> SqliteStatement<'conn> {
/// # Failure /// # Failure
/// ///
/// Will return `Err` if binding parameters fails. /// Will return `Err` if binding parameters fails.
pub fn query_and_then<'a, T, E, F>(&'a mut self, params: &[&ToSql], f: F) pub fn query_and_then<'a, T, E, F>(&'a mut self,
-> SqliteResult<AndThenRows<'a, F>> params: &[&ToSql],
where E: convert::From<SqliteError>, f: F)
F: FnMut(&SqliteRow) -> Result<T, E> { -> SqliteResult<AndThenRows<'a, F>>
let row_iter = try!(self.query(params)); where E: convert::From<SqliteError>,
F: FnMut(&SqliteRow) -> Result<T, E>
{
let row_iter = try!(self.query(params));
Ok(AndThenRows{ Ok(AndThenRows {
rows: row_iter, rows: row_iter,
map: f, map: f,
}) })
} }
/// Consumes the statement. /// Consumes the statement.
/// ///
@ -858,9 +912,9 @@ impl<'conn> SqliteStatement<'conn> {
unsafe fn bind_parameters(&mut self, params: &[&ToSql]) -> SqliteResult<()> { unsafe fn bind_parameters(&mut self, params: &[&ToSql]) -> SqliteResult<()> {
assert!(params.len() as c_int == ffi::sqlite3_bind_parameter_count(self.stmt), assert!(params.len() as c_int == ffi::sqlite3_bind_parameter_count(self.stmt),
"incorrect number of parameters to query(): expected {}, got {}", "incorrect number of parameters to query(): expected {}, got {}",
ffi::sqlite3_bind_parameter_count(self.stmt), ffi::sqlite3_bind_parameter_count(self.stmt),
params.len()); params.len());
for (i, p) in params.iter().enumerate() { for (i, p) in params.iter().enumerate() {
try!(self.conn.decode_result(p.bind_parameter(self.stmt, (i + 1) as c_int))); try!(self.conn.decode_result(p.bind_parameter(self.stmt, (i + 1) as c_int)));
@ -871,7 +925,9 @@ impl<'conn> SqliteStatement<'conn> {
fn reset_if_needed(&mut self) { fn reset_if_needed(&mut self) {
if self.needs_reset { if self.needs_reset {
unsafe { ffi::sqlite3_reset(self.stmt); }; unsafe {
ffi::sqlite3_reset(self.stmt);
};
self.needs_reset = false; self.needs_reset = false;
} }
} }
@ -910,8 +966,8 @@ pub struct MappedRows<'stmt, F> {
map: F, map: F,
} }
impl<'stmt, T, F> Iterator for MappedRows<'stmt, F> impl<'stmt, T, F> Iterator for MappedRows<'stmt, F> where F: FnMut(&SqliteRow) -> T
where F: FnMut(&SqliteRow) -> T { {
type Item = SqliteResult<T>; type Item = SqliteResult<T>;
fn next(&mut self) -> Option<SqliteResult<T>> { fn next(&mut self) -> Option<SqliteResult<T>> {
@ -927,14 +983,16 @@ pub struct AndThenRows<'stmt, F> {
} }
impl<'stmt, T, E, F> Iterator for AndThenRows<'stmt, F> impl<'stmt, T, E, F> Iterator for AndThenRows<'stmt, F>
where E: convert::From<SqliteError>, where E: convert::From<SqliteError>,
F: FnMut(&SqliteRow) -> Result<T, E> { F: FnMut(&SqliteRow) -> Result<T, E>
{
type Item = Result<T, E>; type Item = Result<T, E>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.rows.next().map(|row_result| row_result self.rows.next().map(|row_result| {
.map_err(E::from) row_result.map_err(E::from)
.and_then(|row| (self.map)(&row))) .and_then(|row| (self.map)(&row))
})
} }
} }
@ -981,7 +1039,11 @@ pub struct SqliteRows<'stmt> {
impl<'stmt> SqliteRows<'stmt> { impl<'stmt> SqliteRows<'stmt> {
fn new(stmt: &'stmt SqliteStatement<'stmt>) -> SqliteRows<'stmt> { fn new(stmt: &'stmt SqliteStatement<'stmt>) -> SqliteRows<'stmt> {
SqliteRows{ stmt: stmt, current_row: Rc::new(Cell::new(0)), failed: false } SqliteRows {
stmt: stmt,
current_row: Rc::new(Cell::new(0)),
failed: false,
}
} }
} }
@ -996,12 +1058,12 @@ impl<'stmt> Iterator for SqliteRows<'stmt> {
ffi::SQLITE_ROW => { ffi::SQLITE_ROW => {
let current_row = self.current_row.get() + 1; let current_row = self.current_row.get() + 1;
self.current_row.set(current_row); self.current_row.set(current_row);
Some(Ok(SqliteRow{ Some(Ok(SqliteRow {
stmt: self.stmt, stmt: self.stmt,
current_row: self.current_row.clone(), current_row: self.current_row.clone(),
row_idx: current_row, row_idx: current_row,
})) }))
}, }
ffi::SQLITE_DONE => None, ffi::SQLITE_DONE => None,
code => { code => {
self.failed = true; self.failed = true;
@ -1062,19 +1124,23 @@ impl<'stmt> SqliteRow<'stmt> {
/// for this row or if this row is stale. /// for this row or if this row is stale.
pub fn get_checked<T: FromSql>(&self, idx: c_int) -> SqliteResult<T> { pub fn get_checked<T: FromSql>(&self, idx: c_int) -> SqliteResult<T> {
if self.row_idx != self.current_row.get() { if self.row_idx != self.current_row.get() {
return Err(SqliteError{ code: ffi::SQLITE_MISUSE, return Err(SqliteError {
message: "Cannot get values from a row after advancing to next row".to_string() }); code: ffi::SQLITE_MISUSE,
message: "Cannot get values from a row after advancing to next row".to_string(),
});
} }
unsafe { unsafe {
if idx < 0 || idx >= self.stmt.column_count { if idx < 0 || idx >= self.stmt.column_count {
return Err(SqliteError{ code: ffi::SQLITE_MISUSE, return Err(SqliteError {
message: "Invalid column index".to_string() }); code: ffi::SQLITE_MISUSE,
message: "Invalid column index".to_string(),
});
} }
if T::column_has_valid_sqlite_type(self.stmt.stmt, idx) { if T::column_has_valid_sqlite_type(self.stmt.stmt, idx) {
FromSql::column_result(self.stmt.stmt, idx) FromSql::column_result(self.stmt.stmt, idx)
} else { } else {
Err(SqliteError{ Err(SqliteError {
code: ffi::SQLITE_MISMATCH, code: ffi::SQLITE_MISMATCH,
message: "Invalid column type".to_string(), message: "Invalid column type".to_string(),
}) })
@ -1105,6 +1171,7 @@ mod test {
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_persistence() { fn test_persistence() {
let temp_dir = TempDir::new("test_open_file").unwrap(); let temp_dir = TempDir::new("test_open_file").unwrap();
let path = temp_dir.path().join("test.db3"); let path = temp_dir.path().join("test.db3");
@ -1115,14 +1182,12 @@ mod test {
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(42); INSERT INTO foo VALUES(42);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
} }
let path_string = path.to_str().unwrap(); let path_string = path.to_str().unwrap();
let db = SqliteConnection::open(&path_string).unwrap(); let db = SqliteConnection::open(&path_string).unwrap();
let the_answer = db.query_row("SELECT x FROM foo", let the_answer = db.query_row("SELECT x FROM foo", &[], |r| r.get::<i64>(0));
&[],
|r| r.get::<i64>(0));
assert_eq!(42i64, the_answer.unwrap()); assert_eq!(42i64, the_answer.unwrap());
} }
@ -1137,16 +1202,16 @@ mod test {
#[test] #[test]
fn test_open_with_flags() { fn test_open_with_flags() {
for bad_flags in [ for bad_flags in [SqliteOpenFlags::empty(),
SqliteOpenFlags::empty(), SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_READ_WRITE,
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_READ_WRITE, SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_CREATE]
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_CREATE, .iter() {
].iter() { assert!(SqliteConnection::open_in_memory_with_flags(*bad_flags).is_err());
assert!(SqliteConnection::open_in_memory_with_flags(*bad_flags).is_err()); }
}
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_execute_batch() { fn test_execute_batch() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1168,10 +1233,13 @@ mod test {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();
assert_eq!(db.execute("INSERT INTO foo(x) VALUES (?)", &[&1i32]).unwrap(), 1); assert_eq!(db.execute("INSERT INTO foo(x) VALUES (?)", &[&1i32]).unwrap(),
assert_eq!(db.execute("INSERT INTO foo(x) VALUES (?)", &[&2i32]).unwrap(), 1); 1);
assert_eq!(db.execute("INSERT INTO foo(x) VALUES (?)", &[&2i32]).unwrap(),
1);
assert_eq!(3i32, db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap()); assert_eq!(3i32,
db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap());
} }
#[test] #[test]
@ -1240,6 +1308,7 @@ mod test {
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_map() { fn test_query_map() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1252,8 +1321,7 @@ mod test {
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let results: SqliteResult<Vec<String>> = query let results: SqliteResult<Vec<String>> = query.query_map(&[], |row| row.get(1))
.query_map(&[], |row| row.get(1))
.unwrap() .unwrap()
.collect(); .collect();
@ -1261,6 +1329,7 @@ mod test {
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_row() { fn test_query_row() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1272,9 +1341,9 @@ mod test {
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
assert_eq!(10i64, db.query_row("SELECT SUM(x) FROM foo", &[], |r| { assert_eq!(10i64,
r.get::<i64>(0) db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get::<i64>(0))
}).unwrap()); .unwrap());
let result = db.query_row("SELECT x FROM foo WHERE x > 5", &[], |r| r.get::<i64>(0)); let result = db.query_row("SELECT x FROM foo WHERE x > 5", &[], |r| r.get::<i64>(0));
let error = result.unwrap_err(); let error = result.unwrap_err();
@ -1323,7 +1392,7 @@ mod test {
assert_eq!(db.last_insert_rowid(), 1); assert_eq!(db.last_insert_rowid(), 1);
let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES").unwrap(); let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES").unwrap();
for _ in 0i32 .. 9 { for _ in 0i32..9 {
stmt.execute(&[]).unwrap(); stmt.execute(&[]).unwrap();
} }
assert_eq!(db.last_insert_rowid(), 10); assert_eq!(db.last_insert_rowid(), 10);
@ -1351,17 +1420,19 @@ mod test {
impl fmt::Display for CustomError { impl fmt::Display for CustomError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
CustomError::SomeError => write!(f, "{}", self.description()), CustomError::SomeError => write!(f, "{}", self.description()),
CustomError::Sqlite(ref se) => write!(f, "{}: {}", self.description(), se), CustomError::Sqlite(ref se) => write!(f, "{}: {}", self.description(), se),
} }
} }
} }
impl StdError for CustomError { impl StdError for CustomError {
fn description(&self) -> &str { "my custom error" } fn description(&self) -> &str {
"my custom error"
}
fn cause(&self) -> Option<&StdError> { fn cause(&self) -> Option<&StdError> {
match *self { match *self {
CustomError::SomeError => None, CustomError::SomeError => None,
CustomError::Sqlite(ref se) => Some(se), CustomError::Sqlite(ref se) => Some(se),
} }
} }
@ -1376,6 +1447,7 @@ mod test {
type CustomResult<T> = Result<T, CustomError>; type CustomResult<T> = Result<T, CustomError>;
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_and_then() { fn test_query_and_then() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1388,8 +1460,8 @@ mod test {
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let results: SqliteResult<Vec<String>> = query let results: SqliteResult<Vec<String>> = query.query_and_then(&[],
.query_and_then(&[], |row| row.get_checked(1)) |row| row.get_checked(1))
.unwrap() .unwrap()
.collect(); .collect();
@ -1397,6 +1469,7 @@ mod test {
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_and_then_fails() { fn test_query_and_then_fails() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1409,28 +1482,31 @@ mod test {
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let bad_type: SqliteResult<Vec<f64>> = query let bad_type: SqliteResult<Vec<f64>> = query.query_and_then(&[],
.query_and_then(&[], |row| row.get_checked(1)) |row| row.get_checked(1))
.unwrap() .unwrap()
.collect(); .collect();
assert_eq!(bad_type, Err(SqliteError{ assert_eq!(bad_type,
code: ffi::SQLITE_MISMATCH, Err(SqliteError {
message: "Invalid column type".to_owned(), code: ffi::SQLITE_MISMATCH,
})); message: "Invalid column type".to_owned(),
}));
let bad_idx: SqliteResult<Vec<String>> = query let bad_idx: SqliteResult<Vec<String>> = query.query_and_then(&[],
.query_and_then(&[], |row| row.get_checked(3)) |row| row.get_checked(3))
.unwrap() .unwrap()
.collect(); .collect();
assert_eq!(bad_idx, Err(SqliteError{ assert_eq!(bad_idx,
code: ffi::SQLITE_MISUSE, Err(SqliteError {
message: "Invalid column index".to_owned(), code: ffi::SQLITE_MISUSE,
})); message: "Invalid column index".to_owned(),
}));
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_and_then_custom_error() { fn test_query_and_then_custom_error() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1443,15 +1519,18 @@ mod test {
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let results: CustomResult<Vec<String>> = query let results: CustomResult<Vec<String>> = query.query_and_then(&[], |row| {
.query_and_then(&[], |row| row.get_checked(1).map_err(CustomError::Sqlite)) row.get_checked(1)
.unwrap() .map_err(CustomError::Sqlite)
})
.unwrap()
.collect(); .collect();
assert_eq!(results.unwrap().concat(), "hello, world!"); assert_eq!(results.unwrap().concat(), "hello, world!");
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_and_then_custom_error_fails() { fn test_query_and_then_custom_error_fails() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1464,35 +1543,43 @@ mod test {
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let bad_type: CustomResult<Vec<f64>> = query let bad_type: CustomResult<Vec<f64>> = query.query_and_then(&[], |row| {
.query_and_then(&[], |row| row.get_checked(1).map_err(CustomError::Sqlite)) row.get_checked(1)
.unwrap() .map_err(CustomError::Sqlite)
})
.unwrap()
.collect(); .collect();
assert_eq!(bad_type, Err(CustomError::Sqlite(SqliteError{ assert_eq!(bad_type,
code: ffi::SQLITE_MISMATCH, Err(CustomError::Sqlite(SqliteError {
message: "Invalid column type".to_owned(), code: ffi::SQLITE_MISMATCH,
}))); message: "Invalid column type".to_owned(),
})));
let bad_idx: CustomResult<Vec<String>> = query let bad_idx: CustomResult<Vec<String>> = query.query_and_then(&[], |row| {
.query_and_then(&[], |row| row.get_checked(3).map_err(CustomError::Sqlite)) row.get_checked(3)
.unwrap() .map_err(CustomError::Sqlite)
})
.unwrap()
.collect(); .collect();
assert_eq!(bad_idx, Err(CustomError::Sqlite(SqliteError{ assert_eq!(bad_idx,
code: ffi::SQLITE_MISUSE, Err(CustomError::Sqlite(SqliteError {
message: "Invalid column index".to_owned(), code: ffi::SQLITE_MISUSE,
}))); message: "Invalid column index".to_owned(),
})));
let non_sqlite_err: CustomResult<Vec<String>> = query let non_sqlite_err: CustomResult<Vec<String>> = query.query_and_then(&[], |_| {
.query_and_then(&[], |_| Err(CustomError::SomeError)) Err(CustomError::SomeError)
.unwrap() })
.unwrap()
.collect(); .collect();
assert_eq!(non_sqlite_err, Err(CustomError::SomeError)); assert_eq!(non_sqlite_err, Err(CustomError::SomeError));
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_row_and_then_custom_error() { fn test_query_row_and_then_custom_error() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1502,13 +1589,15 @@ mod test {
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let query = "SELECT x, y FROM foo ORDER BY x DESC"; let query = "SELECT x, y FROM foo ORDER BY x DESC";
let results: CustomResult<String> = db let results: CustomResult<String> = db.query_row_and_then(query, &[], |row| {
.query_row_and_then(query, &[], |row| row.get_checked(1).map_err(CustomError::Sqlite)); row.get_checked(1).map_err(CustomError::Sqlite)
});
assert_eq!(results.unwrap(), "hello"); assert_eq!(results.unwrap(), "hello");
} }
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_query_row_and_then_custom_error_fails() { fn test_query_row_and_then_custom_error_fails() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
@ -1518,24 +1607,29 @@ mod test {
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let query = "SELECT x, y FROM foo ORDER BY x DESC"; let query = "SELECT x, y FROM foo ORDER BY x DESC";
let bad_type: CustomResult<f64> = db let bad_type: CustomResult<f64> = db.query_row_and_then(query, &[], |row| {
.query_row_and_then(query, &[], |row| row.get_checked(1).map_err(CustomError::Sqlite)); row.get_checked(1).map_err(CustomError::Sqlite)
});
assert_eq!(bad_type, Err(CustomError::Sqlite(SqliteError{ assert_eq!(bad_type,
code: ffi::SQLITE_MISMATCH, Err(CustomError::Sqlite(SqliteError {
message: "Invalid column type".to_owned(), code: ffi::SQLITE_MISMATCH,
}))); message: "Invalid column type".to_owned(),
})));
let bad_idx: CustomResult<String> = db let bad_idx: CustomResult<String> = db.query_row_and_then(query, &[], |row| {
.query_row_and_then(query, &[], |row| row.get_checked(3).map_err(CustomError::Sqlite)); row.get_checked(3).map_err(CustomError::Sqlite)
});
assert_eq!(bad_idx, Err(CustomError::Sqlite(SqliteError{ assert_eq!(bad_idx,
code: ffi::SQLITE_MISUSE, Err(CustomError::Sqlite(SqliteError {
message: "Invalid column index".to_owned(), code: ffi::SQLITE_MISUSE,
}))); message: "Invalid column index".to_owned(),
})));
let non_sqlite_err: CustomResult<String> = db let non_sqlite_err: CustomResult<String> = db.query_row_and_then(query, &[], |_| {
.query_row_and_then(query, &[], |_| Err(CustomError::SomeError)); Err(CustomError::SomeError)
});
assert_eq!(non_sqlite_err, Err(CustomError::SomeError)); assert_eq!(non_sqlite_err, Err(CustomError::SomeError));
} }

View File

@ -21,7 +21,7 @@ impl<'conn> SqliteLoadExtensionGuard<'conn> {
/// Attempt to enable loading extensions. Loading extensions will be disabled when this /// Attempt to enable loading extensions. Loading extensions will be disabled when this
/// guard goes out of scope. Cannot be meaningfully nested. /// guard goes out of scope. Cannot be meaningfully nested.
pub fn new(conn: &SqliteConnection) -> SqliteResult<SqliteLoadExtensionGuard> { pub fn new(conn: &SqliteConnection) -> SqliteResult<SqliteLoadExtensionGuard> {
conn.load_extension_enable().map(|_| SqliteLoadExtensionGuard{ conn: conn }) conn.load_extension_enable().map(|_| SqliteLoadExtensionGuard { conn: conn })
} }
} }

View File

@ -35,7 +35,7 @@ pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> SqliteResult<()>
Some(f) => { Some(f) => {
let p_arg: *mut c_void = mem::transmute(f); let p_arg: *mut c_void = mem::transmute(f);
ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, Some(log_callback), p_arg) ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, Some(log_callback), p_arg)
}, }
None => { None => {
let nullptr: *mut c_void = ptr::null_mut(); let nullptr: *mut c_void = ptr::null_mut();
ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr) ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr)
@ -43,7 +43,10 @@ pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> SqliteResult<()>
}; };
if rc != ffi::SQLITE_OK { if rc != ffi::SQLITE_OK {
return Err(SqliteError{ code: rc, message: "sqlite3_config(SQLITE_CONFIG_LOG, ...)".to_string() }); return Err(SqliteError {
code: rc,
message: "sqlite3_config(SQLITE_CONFIG_LOG, ...)".to_string(),
});
} }
Ok(()) Ok(())
@ -64,7 +67,7 @@ impl SqliteConnection {
/// There can only be a single tracer defined for each database connection. /// There can only be a single tracer defined for each database connection.
/// Setting a new tracer clears the old one. /// Setting a new tracer clears the old one.
pub fn trace(&mut self, trace_fn: Option<fn(&str)>) { pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
extern "C" fn trace_callback (p_arg: *mut c_void, z_sql: *const c_char) { extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) {
let trace_fn: fn(&str) = unsafe { mem::transmute(p_arg) }; let trace_fn: fn(&str) = unsafe { mem::transmute(p_arg) };
let c_slice = unsafe { CStr::from_ptr(z_sql).to_bytes() }; let c_slice = unsafe { CStr::from_ptr(z_sql).to_bytes() };
if let Ok(s) = str::from_utf8(c_slice) { if let Ok(s) = str::from_utf8(c_slice) {
@ -74,8 +77,12 @@ impl SqliteConnection {
let c = self.db.borrow_mut(); let c = self.db.borrow_mut();
match trace_fn { match trace_fn {
Some(f) => unsafe { ffi::sqlite3_trace(c.db(), Some(trace_callback), mem::transmute(f)); }, Some(f) => unsafe {
None => unsafe { ffi::sqlite3_trace(c.db(), None, ptr::null_mut()); }, ffi::sqlite3_trace(c.db(), Some(trace_callback), mem::transmute(f));
},
None => unsafe {
ffi::sqlite3_trace(c.db(), None, ptr::null_mut());
},
} }
} }
@ -84,7 +91,9 @@ impl SqliteConnection {
/// There can only be a single profiler defined for each database connection. /// There can only be a single profiler defined for each database connection.
/// Setting a new profiler clears the old one. /// Setting a new profiler clears the old one.
pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) { pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
extern "C" fn profile_callback(p_arg: *mut c_void, z_sql: *const c_char, nanoseconds: u64) { extern "C" fn profile_callback(p_arg: *mut c_void,
z_sql: *const c_char,
nanoseconds: u64) {
let profile_fn: fn(&str, Duration) = unsafe { mem::transmute(p_arg) }; let profile_fn: fn(&str, Duration) = unsafe { mem::transmute(p_arg) };
let c_slice = unsafe { CStr::from_ptr(z_sql).to_bytes() }; let c_slice = unsafe { CStr::from_ptr(z_sql).to_bytes() };
if let Ok(s) = str::from_utf8(c_slice) { if let Ok(s) = str::from_utf8(c_slice) {
@ -98,8 +107,10 @@ impl SqliteConnection {
let c = self.db.borrow_mut(); let c = self.db.borrow_mut();
match profile_fn { match profile_fn {
Some(f) => unsafe { ffi::sqlite3_profile(c.db(), Some(profile_callback), mem::transmute(f)) }, Some(f) => unsafe {
None => unsafe { ffi::sqlite3_profile(c.db(), None, ptr::null_mut()) }, ffi::sqlite3_profile(c.db(), Some(profile_callback), mem::transmute(f))
},
None => unsafe { ffi::sqlite3_profile(c.db(), None, ptr::null_mut()) },
}; };
} }
} }

View File

@ -1,9 +1,7 @@
use {SqliteResult, SqliteConnection}; use {SqliteResult, SqliteConnection};
pub use SqliteTransactionBehavior::{ pub use SqliteTransactionBehavior::{SqliteTransactionDeferred, SqliteTransactionImmediate,
SqliteTransactionDeferred, SqliteTransactionExclusive};
SqliteTransactionImmediate,
SqliteTransactionExclusive};
/// Options for transaction behavior. See [BEGIN /// Options for transaction behavior. See [BEGIN
/// TRANSACTION](http://www.sqlite.org/lang_transaction.html) for details. /// TRANSACTION](http://www.sqlite.org/lang_transaction.html) for details.
@ -46,14 +44,20 @@ pub struct SqliteTransaction<'conn> {
impl<'conn> SqliteTransaction<'conn> { impl<'conn> SqliteTransaction<'conn> {
/// Begin a new transaction. Cannot be nested; see `savepoint` for nested transactions. /// Begin a new transaction. Cannot be nested; see `savepoint` for nested transactions.
pub fn new(conn: &SqliteConnection, pub fn new(conn: &SqliteConnection,
behavior: SqliteTransactionBehavior) -> SqliteResult<SqliteTransaction> { behavior: SqliteTransactionBehavior)
-> SqliteResult<SqliteTransaction> {
let query = match behavior { let query = match behavior {
SqliteTransactionDeferred => "BEGIN DEFERRED", SqliteTransactionDeferred => "BEGIN DEFERRED",
SqliteTransactionImmediate => "BEGIN IMMEDIATE", SqliteTransactionImmediate => "BEGIN IMMEDIATE",
SqliteTransactionExclusive => "BEGIN EXCLUSIVE", SqliteTransactionExclusive => "BEGIN EXCLUSIVE",
}; };
conn.execute_batch(query).map(|_| { conn.execute_batch(query).map(|_| {
SqliteTransaction{ conn: conn, depth: 0, commit: false, finished: false } SqliteTransaction {
conn: conn,
depth: 0,
commit: false,
finished: false,
}
}) })
} }
@ -85,8 +89,11 @@ impl<'conn> SqliteTransaction<'conn> {
/// ``` /// ```
pub fn savepoint<'a>(&'a self) -> SqliteResult<SqliteTransaction<'a>> { pub fn savepoint<'a>(&'a self) -> SqliteResult<SqliteTransaction<'a>> {
self.conn.execute_batch("SAVEPOINT sp").map(|_| { self.conn.execute_batch("SAVEPOINT sp").map(|_| {
SqliteTransaction{ SqliteTransaction {
conn: self.conn, depth: self.depth + 1, commit: false, finished: false conn: self.conn,
depth: self.depth + 1,
commit: false,
finished: false,
} }
}) })
} }
@ -118,7 +125,11 @@ impl<'conn> SqliteTransaction<'conn> {
fn commit_(&mut self) -> SqliteResult<()> { fn commit_(&mut self) -> SqliteResult<()> {
self.finished = true; self.finished = true;
self.conn.execute_batch(if self.depth == 0 { "COMMIT" } else { "RELEASE sp" }) self.conn.execute_batch(if self.depth == 0 {
"COMMIT"
} else {
"RELEASE sp"
})
} }
/// A convenience method which consumes and rolls back a transaction. /// A convenience method which consumes and rolls back a transaction.
@ -128,7 +139,11 @@ impl<'conn> SqliteTransaction<'conn> {
fn rollback_(&mut self) -> SqliteResult<()> { fn rollback_(&mut self) -> SqliteResult<()> {
self.finished = true; self.finished = true;
self.conn.execute_batch(if self.depth == 0 { "ROLLBACK" } else { "ROLLBACK TO sp" }) self.conn.execute_batch(if self.depth == 0 {
"ROLLBACK"
} else {
"ROLLBACK TO sp"
})
} }
/// Consumes the transaction, committing or rolling back according to the current setting /// Consumes the transaction, committing or rolling back according to the current setting
@ -181,7 +196,8 @@ mod test {
} }
{ {
let _tx = db.transaction().unwrap(); let _tx = db.transaction().unwrap();
assert_eq!(2i32, db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap()); assert_eq!(2i32,
db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap());
} }
} }
@ -200,7 +216,8 @@ mod test {
} }
{ {
let _tx = db.transaction().unwrap(); let _tx = db.transaction().unwrap();
assert_eq!(2i32, db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap()); assert_eq!(2i32,
db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap());
} }
} }
@ -228,6 +245,7 @@ mod test {
} }
} }
} }
assert_eq!(3i32, db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap()); assert_eq!(3i32,
db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap());
} }
} }

View File

@ -55,14 +55,14 @@
extern crate time; extern crate time;
use libc::{c_int, c_double, c_char}; use libc::{c_int, c_double, c_char};
use std::ffi::{CStr}; use std::ffi::CStr;
use std::mem; use std::mem;
use std::str; use std::str;
use super::ffi; use super::ffi;
use super::{SqliteResult, SqliteError, str_to_cstring}; use super::{SqliteResult, SqliteError, str_to_cstring};
pub use ffi::sqlite3_stmt as sqlite3_stmt; pub use ffi::sqlite3_stmt;
pub use ffi::sqlite3_column_type as sqlite3_column_type; pub use ffi::sqlite3_column_type;
pub use ffi::{SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, SQLITE_NULL}; pub use ffi::{SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, SQLITE_NULL};
@ -107,9 +107,14 @@ impl<'a> ToSql for &'a str {
return ffi::SQLITE_TOOBIG; return ffi::SQLITE_TOOBIG;
} }
match str_to_cstring(self) { match str_to_cstring(self) {
Ok(c_str) => ffi::sqlite3_bind_text(stmt, col, c_str.as_ptr(), length as c_int, Ok(c_str) => {
ffi::SQLITE_TRANSIENT()), ffi::sqlite3_bind_text(stmt,
Err(_) => ffi::SQLITE_MISUSE, col,
c_str.as_ptr(),
length as c_int,
ffi::SQLITE_TRANSIENT())
}
Err(_) => ffi::SQLITE_MISUSE,
} }
} }
} }
@ -125,8 +130,11 @@ impl<'a> ToSql for &'a [u8] {
if self.len() > ::std::i32::MAX as usize { if self.len() > ::std::i32::MAX as usize {
return ffi::SQLITE_TOOBIG; return ffi::SQLITE_TOOBIG;
} }
ffi::sqlite3_bind_blob( ffi::sqlite3_bind_blob(stmt,
stmt, col, mem::transmute(self.as_ptr()), self.len() as c_int, ffi::SQLITE_TRANSIENT()) col,
mem::transmute(self.as_ptr()),
self.len() as c_int,
ffi::SQLITE_TRANSIENT())
} }
} }
@ -203,9 +211,13 @@ impl FromSql for String {
} else { } else {
let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes(); let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
let utf8_str = str::from_utf8(c_slice); let utf8_str = str::from_utf8(c_slice);
utf8_str utf8_str.map(|s| s.to_string())
.map(|s| { s.to_string() }) .map_err(|e| {
.map_err(|e| { SqliteError{code: 0, message: e.to_string()} }) SqliteError {
code: 0,
message: e.to_string(),
}
})
} }
} }
@ -222,7 +234,8 @@ impl FromSql for Vec<u8> {
// The documentation for sqlite3_column_bytes indicates it is always non-negative, // The documentation for sqlite3_column_bytes indicates it is always non-negative,
// but we should assert here just to be sure. // but we should assert here just to be sure.
assert!(len >= 0, "unexpected negative return from sqlite3_column_bytes"); assert!(len >= 0,
"unexpected negative return from sqlite3_column_bytes");
let len = len as usize; let len = len as usize;
Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec()) Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
@ -234,15 +247,17 @@ impl FromSql for Vec<u8> {
} }
impl FromSql for time::Timespec { impl FromSql for time::Timespec {
unsafe fn column_result(stmt: *mut sqlite3_stmt, unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<time::Timespec> {
col: c_int) -> SqliteResult<time::Timespec> {
let col_str = FromSql::column_result(stmt, col); let col_str = FromSql::column_result(stmt, col);
col_str.and_then(|txt: String| { col_str.and_then(|txt: String| {
time::strptime(&txt, SQLITE_DATETIME_FMT).map(|tm| { time::strptime(&txt, SQLITE_DATETIME_FMT)
tm.to_timespec() .map(|tm| tm.to_timespec())
}).map_err(|parse_error| { .map_err(|parse_error| {
SqliteError{ code: ffi::SQLITE_MISMATCH, message: format!("{}", parse_error) } SqliteError {
}) code: ffi::SQLITE_MISMATCH,
message: format!("{}", parse_error),
}
})
}) })
} }
@ -262,7 +277,7 @@ impl<T: FromSql> FromSql for Option<T> {
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool { unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL || sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL ||
T::column_has_valid_sqlite_type(stmt, col) T::column_has_valid_sqlite_type(stmt, col)
} }
} }
@ -283,7 +298,7 @@ mod test {
fn test_blob() { fn test_blob() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let v1234 = vec![1u8,2,3,4]; let v1234 = vec![1u8, 2, 3, 4];
db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234]).unwrap(); db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234]).unwrap();
let v: Vec<u8> = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap(); let v: Vec<u8> = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap();
@ -305,7 +320,10 @@ mod test {
fn test_timespec() { fn test_timespec() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let ts = time::Timespec{sec: 10_000, nsec: 0 }; let ts = time::Timespec {
sec: 10_000,
nsec: 0,
};
db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]).unwrap(); db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]).unwrap();
let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap();
@ -317,7 +335,7 @@ mod test {
let db = checked_memory_handle(); let db = checked_memory_handle();
let s = Some("hello, world!"); let s = Some("hello, world!");
let b = Some(vec![1u8,2,3,4]); let b = Some(vec![1u8, 2, 3, 4]);
db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap(); db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap();
db.execute("INSERT INTO foo(b) VALUES (?)", &[&b]).unwrap(); db.execute("INSERT INTO foo(b) VALUES (?)", &[&b]).unwrap();
@ -342,7 +360,9 @@ mod test {
fn test_mismatched_types() { fn test_mismatched_types() {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute("INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)", &[]).unwrap(); db.execute("INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)",
&[])
.unwrap();
let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo").unwrap(); let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo").unwrap();
let mut rows = stmt.query(&[]).unwrap(); let mut rows = stmt.query(&[]).unwrap();
@ -350,10 +370,10 @@ mod test {
let row = rows.next().unwrap().unwrap(); let row = rows.next().unwrap().unwrap();
// check the correct types come back as expected // check the correct types come back as expected
assert_eq!(vec![1,2], row.get_checked::<Vec<u8>>(0).unwrap()); assert_eq!(vec![1, 2], row.get_checked::<Vec<u8>>(0).unwrap());
assert_eq!("text", row.get_checked::<String>(1).unwrap()); assert_eq!("text", row.get_checked::<String>(1).unwrap());
assert_eq!(1, row.get_checked::<c_int>(2).unwrap()); assert_eq!(1, row.get_checked::<c_int>(2).unwrap());
assert_eq!(1.5, row.get_checked::<c_double>(3).unwrap()); assert_eq!(1.5, row.get_checked::<c_double>(3).unwrap());
assert!(row.get_checked::<Option<c_int>>(4).unwrap().is_none()); assert!(row.get_checked::<Option<c_int>>(4).unwrap().is_none());
assert!(row.get_checked::<Option<c_double>>(4).unwrap().is_none()); assert!(row.get_checked::<Option<c_double>>(4).unwrap().is_none());
assert!(row.get_checked::<Option<String>>(4).unwrap().is_none()); assert!(row.get_checked::<Option<String>>(4).unwrap().is_none());
@ -361,41 +381,69 @@ mod test {
// check some invalid types // check some invalid types
// 0 is actually a blob (Vec<u8>) // 0 is actually a blob (Vec<u8>)
assert_eq!(row.get_checked::<c_int>(0).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_int>(0).err().unwrap().code,
assert_eq!(row.get_checked::<i64>(0).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<c_double>(0).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<i64>(0).err().unwrap().code,
assert_eq!(row.get_checked::<String>(0).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<time::Timespec>(0).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_double>(0).err().unwrap().code,
assert_eq!(row.get_checked::<Option<c_int>>(0).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<String>(0).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<time::Timespec>(0).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Option<c_int>>(0).err().unwrap().code,
ffi::SQLITE_MISMATCH);
// 1 is actually a text (String) // 1 is actually a text (String)
assert_eq!(row.get_checked::<c_int>(1).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_int>(1).err().unwrap().code,
assert_eq!(row.get_checked::<i64>(1).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<c_double>(1).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<i64>(1).err().unwrap().code,
assert_eq!(row.get_checked::<Vec<u8>>(1).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Option<c_int>>(1).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_double>(1).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Vec<u8>>(1).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Option<c_int>>(1).err().unwrap().code,
ffi::SQLITE_MISMATCH);
// 2 is actually an integer // 2 is actually an integer
assert_eq!(row.get_checked::<c_double>(2).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_double>(2).err().unwrap().code,
assert_eq!(row.get_checked::<String>(2).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Vec<u8>>(2).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<String>(2).err().unwrap().code,
assert_eq!(row.get_checked::<time::Timespec>(2).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Option<c_double>>(2).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<Vec<u8>>(2).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<time::Timespec>(2).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Option<c_double>>(2).err().unwrap().code,
ffi::SQLITE_MISMATCH);
// 3 is actually a float (c_double) // 3 is actually a float (c_double)
assert_eq!(row.get_checked::<c_int>(3).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_int>(3).err().unwrap().code,
assert_eq!(row.get_checked::<i64>(3).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<String>(3).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<i64>(3).err().unwrap().code,
assert_eq!(row.get_checked::<Vec<u8>>(3).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<time::Timespec>(3).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<String>(3).err().unwrap().code,
assert_eq!(row.get_checked::<Option<c_int>>(3).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Vec<u8>>(3).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<time::Timespec>(3).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Option<c_int>>(3).err().unwrap().code,
ffi::SQLITE_MISMATCH);
// 4 is actually NULL // 4 is actually NULL
assert_eq!(row.get_checked::<c_int>(4).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_int>(4).err().unwrap().code,
assert_eq!(row.get_checked::<i64>(4).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<c_double>(4).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<i64>(4).err().unwrap().code,
assert_eq!(row.get_checked::<String>(4).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Vec<u8>>(4).err().unwrap().code, ffi::SQLITE_MISMATCH); assert_eq!(row.get_checked::<c_double>(4).err().unwrap().code,
assert_eq!(row.get_checked::<time::Timespec>(4).err().unwrap().code, ffi::SQLITE_MISMATCH); ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<String>(4).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<Vec<u8>>(4).err().unwrap().code,
ffi::SQLITE_MISMATCH);
assert_eq!(row.get_checked::<time::Timespec>(4).err().unwrap().code,
ffi::SQLITE_MISMATCH);
} }
} }