mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Run rustfmt on all crate files
This commit is contained in:
parent
26a7930d73
commit
a1f1480b18
572
src/lib.rs
572
src/lib.rs
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
src/trace.rs
27
src/trace.rs
@ -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()) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
160
src/types.rs
160
src/types.rs
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user