Merge branch 'master' into remove-rows-iterator-impl

This commit is contained in:
John Gallagher
2016-05-19 14:06:56 -05:00
10 changed files with 762 additions and 161 deletions

View File

@@ -55,6 +55,7 @@
extern crate libc;
extern crate libsqlite3_sys as ffi;
extern crate lru_cache;
#[macro_use]
extern crate bitflags;
#[cfg(test)]
@@ -76,24 +77,32 @@ use libc::{c_int, c_char};
use types::{ToSql, FromSql};
use error::{error_from_sqlite_code, error_from_handle};
use raw_statement::RawStatement;
use cache::StatementCache;
pub use transaction::{SqliteTransaction, Transaction, TransactionBehavior};
pub use error::{SqliteError, Error};
pub use cache::CachedStatement;
#[cfg(feature = "load_extension")]
pub use load_extension_guard::{SqliteLoadExtensionGuard, LoadExtensionGuard};
pub mod types;
mod transaction;
mod cache;
mod named_params;
mod error;
mod convenient;
mod raw_statement;
#[cfg(feature = "load_extension")]mod load_extension_guard;
#[cfg(feature = "trace")]pub mod trace;
#[cfg(feature = "backup")]pub mod backup;
#[cfg(feature = "functions")]pub mod functions;
#[cfg(feature = "blob")]pub mod blob;
// Number of cached prepared statements we'll hold on to.
const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
/// Old name for `Result`. `SqliteResult` is deprecated.
pub type SqliteResult<T> = Result<T>;
@@ -146,6 +155,7 @@ pub type SqliteConnection = Connection;
/// A connection to a SQLite database.
pub struct Connection {
db: RefCell<InnerConnection>,
cache: StatementCache,
path: Option<PathBuf>,
}
@@ -190,6 +200,7 @@ impl Connection {
InnerConnection::open_with_flags(&c_path, flags).map(|db| {
Connection {
db: RefCell::new(db),
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
path: Some(path.as_ref().to_path_buf()),
}
})
@@ -208,50 +219,12 @@ impl Connection {
InnerConnection::open_with_flags(&c_memory, flags).map(|db| {
Connection {
db: RefCell::new(db),
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
path: None,
}
})
}
/// Begin a new transaction with the default behavior (DEFERRED).
///
/// The transaction defaults to rolling back when it is dropped. If you want the transaction to
/// commit, you must call `commit` or `set_commit`.
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result};
/// # fn do_queries_part_1(conn: &Connection) -> Result<()> { Ok(()) }
/// # fn do_queries_part_2(conn: &Connection) -> Result<()> { Ok(()) }
/// fn perform_queries(conn: &Connection) -> Result<()> {
/// let tx = try!(conn.transaction());
///
/// try!(do_queries_part_1(conn)); // tx causes rollback if this fails
/// try!(do_queries_part_2(conn)); // tx causes rollback if this fails
///
/// tx.commit()
/// }
/// ```
///
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
pub fn transaction(&mut self) -> Result<Transaction> {
Transaction::new(self, TransactionBehavior::Deferred)
}
/// Begin a new transaction with a specified behavior.
///
/// See `transaction`.
///
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
pub fn transaction_with_behavior(&mut self, behavior: TransactionBehavior) -> Result<Transaction> {
Transaction::new(self, behavior)
}
/// Convenience method to run multiple SQL statements (that cannot take any parameters).
///
/// Uses [sqlite3_exec](http://www.sqlite.org/c3ref/exec.html) under the hood.
@@ -686,7 +659,7 @@ impl InnerConnection {
&mut c_stmt,
ptr::null_mut())
};
self.decode_result(r).map(|_| Statement::new(conn, c_stmt))
self.decode_result(r).map(|_| Statement::new(conn, RawStatement::new(c_stmt)))
}
fn changes(&mut self) -> c_int {
@@ -707,25 +680,23 @@ pub type SqliteStatement<'conn> = Statement<'conn>;
/// A prepared statement.
pub struct Statement<'conn> {
conn: &'conn Connection,
stmt: *mut ffi::sqlite3_stmt,
column_count: c_int,
stmt: RawStatement,
}
impl<'conn> Statement<'conn> {
fn new(conn: &Connection, stmt: *mut ffi::sqlite3_stmt) -> Statement {
fn new(conn: &Connection, stmt: RawStatement) -> Statement {
Statement {
conn: conn,
stmt: stmt,
column_count: unsafe { ffi::sqlite3_column_count(stmt) },
}
}
/// Get all the column names in the result set of the prepared statement.
pub fn column_names(&self) -> Vec<&str> {
let n = self.column_count;
let n = self.column_count();
let mut cols = Vec::with_capacity(n as usize);
for i in 0..n {
let slice = unsafe { CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, i)) };
let slice = self.stmt.column_name(i);
let s = str::from_utf8(slice.to_bytes()).unwrap();
cols.push(s);
}
@@ -734,7 +705,7 @@ impl<'conn> Statement<'conn> {
/// Return the number of columns in the result set returned by the prepared statement.
pub fn column_count(&self) -> i32 {
self.column_count
self.stmt.column_count()
}
/// Returns the column index in the result set for a given column name.
@@ -744,10 +715,9 @@ impl<'conn> Statement<'conn> {
/// Will return an `Error::InvalidColumnName` when there is no column with the specified `name`.
pub fn column_index(&self, name: &str) -> Result<i32> {
let bytes = name.as_bytes();
let n = self.column_count;
let n = self.column_count();
for i in 0..n {
let slice = unsafe { CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, i)) };
if bytes == slice.to_bytes() {
if bytes == self.stmt.column_name(i).to_bytes() {
return Ok(i);
}
}
@@ -778,18 +748,16 @@ impl<'conn> Statement<'conn> {
/// Will return `Err` if binding parameters fails, the executed statement returns rows (in
/// which case `query` should be used instead), or the underling SQLite call fails.
pub fn execute(&mut self, params: &[&ToSql]) -> Result<c_int> {
unsafe {
try!(self.bind_parameters(params));
self.execute_()
}
try!(self.bind_parameters(params));
self.execute_()
}
unsafe fn execute_(&mut self) -> Result<c_int> {
let r = ffi::sqlite3_step(self.stmt);
ffi::sqlite3_reset(self.stmt);
fn execute_(&mut self) -> Result<c_int> {
let r = self.stmt.step();
self.stmt.reset();
match r {
ffi::SQLITE_DONE => {
if self.column_count == 0 {
if self.column_count() == 0 {
Ok(self.conn.changes())
} else {
Err(Error::ExecuteReturnedResults)
@@ -828,10 +796,7 @@ impl<'conn> Statement<'conn> {
///
/// Will return `Err` if binding parameters fails.
pub fn query<'a>(&'a mut self, params: &[&ToSql]) -> Result<Rows<'a>> {
unsafe {
try!(self.bind_parameters(params));
}
try!(self.bind_parameters(params));
Ok(Rows::new(self))
}
@@ -903,32 +868,39 @@ impl<'conn> Statement<'conn> {
self.finalize_()
}
unsafe fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> {
assert!(params.len() as c_int == ffi::sqlite3_bind_parameter_count(self.stmt),
fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> {
assert!(params.len() as c_int == self.stmt.bind_parameter_count(),
"incorrect number of parameters to query(): expected {}, got {}",
ffi::sqlite3_bind_parameter_count(self.stmt),
self.stmt.bind_parameter_count(),
params.len());
for (i, p) in params.iter().enumerate() {
try!(self.conn.decode_result(p.bind_parameter(self.stmt, (i + 1) as c_int)));
try!(unsafe {
self.conn.decode_result(p.bind_parameter(self.stmt.ptr(), (i + 1) as c_int))
});
}
Ok(())
}
fn finalize_(&mut self) -> Result<()> {
let r = unsafe { ffi::sqlite3_finalize(self.stmt) };
self.stmt = ptr::null_mut();
self.conn.decode_result(r)
let mut stmt = RawStatement::new(ptr::null_mut());
mem::swap(&mut stmt, &mut self.stmt);
self.conn.decode_result(stmt.finalize())
}
}
impl<'conn> Into<RawStatement> for Statement<'conn> {
fn into(mut self) -> RawStatement {
let mut stmt = RawStatement::new(ptr::null_mut());
mem::swap(&mut stmt, &mut self.stmt);
stmt
}
}
impl<'conn> fmt::Debug for Statement<'conn> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let sql = unsafe {
let c_slice = CStr::from_ptr(ffi::sqlite3_sql(self.stmt)).to_bytes();
str::from_utf8(c_slice)
};
let sql = str::from_utf8(self.stmt.sql().to_bytes());
f.debug_struct("Statement")
.field("conn", self.conn)
.field("stmt", &self.stmt)
@@ -1007,9 +979,7 @@ impl<'stmt> Rows<'stmt> {
fn reset(&mut self) {
if let Some(stmt) = self.stmt.take() {
unsafe {
ffi::sqlite3_reset(stmt.stmt);
}
stmt.stmt.reset();
}
}
@@ -1025,7 +995,7 @@ impl<'stmt> Rows<'stmt> {
/// or `query_and_then` instead, which return types that implement `Iterator`.
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
self.stmt.and_then(|stmt| {
match unsafe { ffi::sqlite3_step(stmt.stmt) } {
match stmt.stmt.step() {
ffi::SQLITE_ROW => {
Some(Ok(Row {
stmt: stmt,
@@ -1088,8 +1058,8 @@ impl<'a, 'stmt> Row<'a, 'stmt> {
unsafe {
let idx = try!(idx.idx(self.stmt));
if T::column_has_valid_sqlite_type(self.stmt.stmt, idx) {
FromSql::column_result(self.stmt.stmt, idx)
if T::column_has_valid_sqlite_type(self.stmt.stmt.ptr(), idx) {
FromSql::column_result(self.stmt.stmt.ptr(), idx)
} else {
Err(Error::InvalidColumnType)
}
@@ -1112,7 +1082,7 @@ pub trait RowIndex {
impl RowIndex for i32 {
#[inline]
fn idx(&self, stmt: &Statement) -> Result<i32> {
if *self < 0 || *self >= stmt.column_count {
if *self < 0 || *self >= stmt.column_count() {
Err(Error::InvalidColumnIndex(*self))
} else {
Ok(*self)