2014-11-11 01:56:32 +08:00
|
|
|
//! Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
|
2014-11-04 06:11:00 +08:00
|
|
|
//! an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres).
|
|
|
|
//!
|
|
|
|
//! ```rust
|
|
|
|
//! extern crate rusqlite;
|
|
|
|
//! extern crate time;
|
|
|
|
//!
|
|
|
|
//! use time::Timespec;
|
2015-12-13 02:50:12 +08:00
|
|
|
//! use rusqlite::Connection;
|
2014-11-04 06:11:00 +08:00
|
|
|
//!
|
2015-02-04 07:59:58 +08:00
|
|
|
//! #[derive(Debug)]
|
2014-11-04 06:11:00 +08:00
|
|
|
//! struct Person {
|
|
|
|
//! id: i32,
|
|
|
|
//! name: String,
|
|
|
|
//! time_created: Timespec,
|
|
|
|
//! data: Option<Vec<u8>>
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! fn main() {
|
2015-12-13 02:50:12 +08:00
|
|
|
//! let conn = Connection::open_in_memory().unwrap();
|
2014-11-04 06:11:00 +08:00
|
|
|
//!
|
|
|
|
//! conn.execute("CREATE TABLE person (
|
|
|
|
//! id INTEGER PRIMARY KEY,
|
|
|
|
//! name TEXT NOT NULL,
|
|
|
|
//! time_created TEXT NOT NULL,
|
|
|
|
//! data BLOB
|
2014-11-19 23:48:40 +08:00
|
|
|
//! )", &[]).unwrap();
|
2014-11-04 06:11:00 +08:00
|
|
|
//! let me = Person {
|
|
|
|
//! id: 0,
|
|
|
|
//! name: "Steven".to_string(),
|
|
|
|
//! time_created: time::get_time(),
|
|
|
|
//! data: None
|
|
|
|
//! };
|
|
|
|
//! conn.execute("INSERT INTO person (name, time_created, data)
|
2016-07-02 16:22:47 +08:00
|
|
|
//! VALUES (?1, ?2, ?3)",
|
2014-11-04 06:11:00 +08:00
|
|
|
//! &[&me.name, &me.time_created, &me.data]).unwrap();
|
|
|
|
//!
|
|
|
|
//! let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap();
|
2016-08-15 18:41:15 +08:00
|
|
|
//! let person_iter = stmt.query_map(&[], |row| {
|
2015-05-07 21:36:29 +08:00
|
|
|
//! Person {
|
2014-11-04 06:11:00 +08:00
|
|
|
//! id: row.get(0),
|
|
|
|
//! name: row.get(1),
|
|
|
|
//! time_created: row.get(2),
|
|
|
|
//! data: row.get(3)
|
2015-05-07 21:36:29 +08:00
|
|
|
//! }
|
|
|
|
//! }).unwrap();
|
|
|
|
//!
|
|
|
|
//! for person in person_iter {
|
|
|
|
//! println!("Found person {:?}", person.unwrap());
|
2014-11-04 06:11:00 +08:00
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//! ```
|
2016-08-08 21:23:55 +08:00
|
|
|
#![allow(unknown_lints)]
|
2016-02-14 23:11:59 +08:00
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
extern crate libc;
|
2015-03-27 03:48:29 +08:00
|
|
|
extern crate libsqlite3_sys as ffi;
|
2016-05-18 01:26:17 +08:00
|
|
|
extern crate lru_cache;
|
2015-12-11 05:48:09 +08:00
|
|
|
#[macro_use]
|
|
|
|
extern crate bitflags;
|
|
|
|
#[cfg(test)]
|
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-07-07 02:24:27 +08:00
|
|
|
use std::default::Default;
|
2015-08-28 01:43:43 +08:00
|
|
|
use std::convert;
|
2016-05-19 00:33:58 +08:00
|
|
|
use std::marker::PhantomData;
|
2014-10-20 07:56:41 +08:00
|
|
|
use std::mem;
|
2015-04-04 03:48:35 +08:00
|
|
|
use std::ptr;
|
2014-10-20 07:56:41 +08:00
|
|
|
use std::fmt;
|
2015-12-11 05:48:09 +08:00
|
|
|
use std::path::{Path, PathBuf};
|
2016-05-19 00:33:58 +08:00
|
|
|
use std::cell::RefCell;
|
2015-02-24 08:52:48 +08:00
|
|
|
use std::ffi::{CStr, CString};
|
2015-12-13 03:06:03 +08:00
|
|
|
use std::result;
|
2015-01-08 03:05:36 +08:00
|
|
|
use std::str;
|
2016-05-26 10:57:43 +08:00
|
|
|
use libc::{c_int, c_char, c_void};
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2016-12-31 13:35:47 +08:00
|
|
|
use types::{ToSql, ToSqlOutput, FromSql, FromSqlError, ValueRef};
|
2015-12-13 14:04:09 +08:00
|
|
|
use error::{error_from_sqlite_code, error_from_handle};
|
2016-05-17 23:06:43 +08:00
|
|
|
use raw_statement::RawStatement;
|
2016-05-18 01:11:25 +08:00
|
|
|
use cache::StatementCache;
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2017-01-06 14:23:51 +08:00
|
|
|
#[allow(deprecated)]
|
|
|
|
pub use transaction::{SqliteTransaction, SqliteTransactionBehavior};
|
|
|
|
pub use transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
|
|
|
|
|
|
|
|
#[allow(deprecated)]
|
|
|
|
pub use error::SqliteError;
|
|
|
|
pub use error::Error;
|
|
|
|
|
2016-05-18 01:01:55 +08:00
|
|
|
pub use cache::CachedStatement;
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg(feature = "load_extension")]
|
2017-01-07 03:25:55 +08:00
|
|
|
#[allow(deprecated)]
|
2015-12-13 03:20:11 +08:00
|
|
|
pub use load_extension_guard::{SqliteLoadExtensionGuard, LoadExtensionGuard};
|
2015-02-24 09:16:49 +08:00
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
pub mod types;
|
|
|
|
mod transaction;
|
2016-05-18 01:01:55 +08:00
|
|
|
mod cache;
|
2015-12-11 05:53:43 +08:00
|
|
|
mod named_params;
|
2015-12-13 14:04:09 +08:00
|
|
|
mod error;
|
2016-05-17 00:02:56 +08:00
|
|
|
mod convenient;
|
2016-05-17 23:06:43 +08:00
|
|
|
mod raw_statement;
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg(feature = "load_extension")]mod load_extension_guard;
|
|
|
|
#[cfg(feature = "trace")]pub mod trace;
|
|
|
|
#[cfg(feature = "backup")]pub mod backup;
|
2016-02-03 02:12:00 +08:00
|
|
|
#[cfg(feature = "functions")]pub mod functions;
|
|
|
|
#[cfg(feature = "blob")]pub mod blob;
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2016-05-18 01:11:25 +08:00
|
|
|
// Number of cached prepared statements we'll hold on to.
|
|
|
|
const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
/// Old name for `Result`. `SqliteResult` is deprecated.
|
2016-05-30 08:36:20 +08:00
|
|
|
#[deprecated(since = "0.6.0", note = "Use Result instead")]
|
2015-12-13 03:06:03 +08:00
|
|
|
pub type SqliteResult<T> = Result<T>;
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// A typedef of the result returned by many methods.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub type Result<T> = result::Result<T, Error>;
|
2014-10-20 07:56:41 +08:00
|
|
|
|
|
|
|
unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
|
2015-02-24 08:52:48 +08:00
|
|
|
let c_slice = CStr::from_ptr(errmsg).to_bytes();
|
2016-05-07 18:08:57 +08:00
|
|
|
String::from_utf8_lossy(c_slice).into_owned()
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn str_to_cstring(s: &str) -> Result<CString> {
|
2015-12-13 13:54:08 +08:00
|
|
|
Ok(try!(CString::new(s)))
|
2015-02-24 08:52:48 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn path_to_cstring(p: &Path) -> Result<CString> {
|
2015-12-13 13:54:08 +08:00
|
|
|
let s = try!(p.to_str().ok_or(Error::InvalidPath(p.to_owned())));
|
2015-02-24 08:52:48 +08:00
|
|
|
str_to_cstring(s)
|
|
|
|
}
|
|
|
|
|
2015-12-10 05:27:18 +08:00
|
|
|
/// Name for a database within a SQLite connection.
|
|
|
|
pub enum DatabaseName<'a> {
|
|
|
|
/// The main database.
|
|
|
|
Main,
|
|
|
|
|
|
|
|
/// The temporary database (e.g., any "CREATE TEMPORARY TABLE" tables).
|
|
|
|
Temp,
|
|
|
|
|
|
|
|
/// A database that has been attached via "ATTACH DATABASE ...".
|
|
|
|
Attached(&'a str),
|
|
|
|
}
|
|
|
|
|
2015-12-15 02:38:36 +08:00
|
|
|
// Currently DatabaseName is only used by the backup and blob mods, so hide this (private)
|
2015-12-10 05:27:18 +08:00
|
|
|
// impl to avoid dead code warnings.
|
2015-12-15 02:38:36 +08:00
|
|
|
#[cfg(any(feature = "backup", feature = "blob"))]
|
2015-12-10 05:27:18 +08:00
|
|
|
impl<'a> DatabaseName<'a> {
|
2016-02-14 23:11:59 +08:00
|
|
|
fn to_cstring(&self) -> Result<CString> {
|
2015-12-10 05:27:18 +08:00
|
|
|
use self::DatabaseName::{Main, Temp, Attached};
|
2016-02-14 23:11:59 +08:00
|
|
|
match *self {
|
2015-12-11 05:48:09 +08:00
|
|
|
Main => str_to_cstring("main"),
|
|
|
|
Temp => str_to_cstring("temp"),
|
2015-12-10 05:27:18 +08:00
|
|
|
Attached(s) => str_to_cstring(s),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
/// Old name for `Connection`. `SqliteConnection` is deprecated.
|
2016-05-30 08:36:20 +08:00
|
|
|
#[deprecated(since = "0.6.0", note = "Use Connection instead")]
|
2015-12-13 02:50:12 +08:00
|
|
|
pub type SqliteConnection = Connection;
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// A connection to a SQLite database.
|
2015-12-13 02:50:12 +08:00
|
|
|
pub struct Connection {
|
|
|
|
db: RefCell<InnerConnection>,
|
2016-05-18 01:11:25 +08:00
|
|
|
cache: StatementCache,
|
2015-08-01 18:04:02 +08:00
|
|
|
path: Option<PathBuf>,
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
unsafe impl Send for Connection {}
|
2015-04-04 03:48:35 +08:00
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
impl Connection {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Open a new connection to a SQLite database.
|
|
|
|
///
|
2015-12-13 02:50:12 +08:00
|
|
|
/// `Connection::open(path)` is equivalent to `Connection::open_with_flags(path,
|
2014-11-04 06:11:00 +08:00
|
|
|
/// SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE)`.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if `path` cannot be converted to a C-compatible string or if the
|
|
|
|
/// underlying SQLite open call fails.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
|
2015-07-07 02:24:27 +08:00
|
|
|
let flags = Default::default();
|
2015-12-13 02:50:12 +08:00
|
|
|
Connection::open_with_flags(path, flags)
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-02-07 09:07:23 +08:00
|
|
|
/// Open a new connection to an in-memory SQLite database.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if the underlying SQLite open call fails.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn open_in_memory() -> Result<Connection> {
|
2015-07-07 02:24:27 +08:00
|
|
|
let flags = Default::default();
|
2015-12-13 02:50:12 +08:00
|
|
|
Connection::open_in_memory_with_flags(flags)
|
2015-02-07 09:07:23 +08:00
|
|
|
}
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Open a new connection to a SQLite database.
|
|
|
|
///
|
|
|
|
/// Database Connection](http://www.sqlite.org/c3ref/open.html) for a description of valid
|
|
|
|
/// flag combinations.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if `path` cannot be converted to a C-compatible string or if the
|
|
|
|
/// underlying SQLite open call fails.
|
2016-02-03 02:12:00 +08:00
|
|
|
pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
|
|
|
|
let c_path = try!(path_to_cstring(path.as_ref()));
|
|
|
|
InnerConnection::open_with_flags(&c_path, flags).map(|db| {
|
|
|
|
Connection {
|
|
|
|
db: RefCell::new(db),
|
2016-05-18 01:11:25 +08:00
|
|
|
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
|
2016-02-03 02:12:00 +08:00
|
|
|
path: Some(path.as_ref().to_path_buf()),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2015-02-07 09:07:23 +08:00
|
|
|
|
|
|
|
/// Open a new connection to an in-memory SQLite database.
|
|
|
|
///
|
|
|
|
/// Database Connection](http://www.sqlite.org/c3ref/open.html) for a description of valid
|
|
|
|
/// flag combinations.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if the underlying SQLite open call fails.
|
2015-12-13 03:13:29 +08:00
|
|
|
pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> {
|
2015-02-24 10:44:29 +08:00
|
|
|
let c_memory = try!(str_to_cstring(":memory:"));
|
2015-12-13 02:50:12 +08:00
|
|
|
InnerConnection::open_with_flags(&c_memory, flags).map(|db| {
|
|
|
|
Connection {
|
2015-12-11 05:48:09 +08:00
|
|
|
db: RefCell::new(db),
|
2016-05-18 01:11:25 +08:00
|
|
|
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
|
2015-12-11 05:48:09 +08:00
|
|
|
path: None,
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// 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.
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Connection, Result};
|
|
|
|
/// fn create_tables(conn: &Connection) -> Result<()> {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// conn.execute_batch("BEGIN;
|
|
|
|
/// CREATE TABLE foo(x INTEGER);
|
|
|
|
/// CREATE TABLE bar(y TEXT);
|
|
|
|
/// COMMIT;")
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
|
|
|
/// underlying SQLite call fails.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn execute_batch(&self, sql: &str) -> Result<()> {
|
2014-10-20 07:56:41 +08:00
|
|
|
self.db.borrow_mut().execute_batch(sql)
|
|
|
|
}
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Convenience method to prepare and execute a single SQL statement.
|
|
|
|
///
|
|
|
|
/// On success, returns the number of rows that were changed or inserted or deleted (via
|
|
|
|
/// `sqlite3_changes`).
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 02:50:12 +08:00
|
|
|
/// # use rusqlite::{Connection};
|
|
|
|
/// fn update_rows(conn: &Connection) {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// match conn.execute("UPDATE foo SET bar = 'baz' WHERE qux = ?", &[&1i32]) {
|
|
|
|
/// Ok(updated) => println!("{} rows were updated", updated),
|
|
|
|
/// Err(err) => println!("update failed: {}", err),
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
|
|
|
/// underlying SQLite call fails.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn execute(&self, sql: &str, params: &[&ToSql]) -> Result<c_int> {
|
2014-10-20 07:56:41 +08:00
|
|
|
self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
|
|
|
|
}
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Get the SQLite rowid of the most recent successful INSERT.
|
|
|
|
///
|
|
|
|
/// Uses [sqlite3_last_insert_rowid](https://www.sqlite.org/c3ref/last_insert_rowid.html) under
|
|
|
|
/// the hood.
|
2014-10-20 07:56:41 +08:00
|
|
|
pub fn last_insert_rowid(&self) -> i64 {
|
|
|
|
self.db.borrow_mut().last_insert_rowid()
|
|
|
|
}
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Convenience method to execute a query that is expected to return a single row.
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Result,Connection};
|
|
|
|
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
2015-05-07 21:41:02 +08:00
|
|
|
/// conn.query_row("SELECT value FROM preferences WHERE name='locale'", &[], |row| {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// row.get(0)
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// If the query returns more than one row, all rows except the first are ignored.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
|
|
|
/// underlying SQLite call fails.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
|
2016-10-08 00:42:27 +08:00
|
|
|
where F: FnOnce(&Row) -> T
|
2015-12-11 09:48:38 +08:00
|
|
|
{
|
|
|
|
let mut stmt = try!(self.prepare(sql));
|
2016-07-14 12:27:46 +08:00
|
|
|
stmt.query_row(params, f)
|
2015-12-11 09:48:38 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-08-28 02:01:01 +08:00
|
|
|
/// 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.
|
2015-12-13 02:53:58 +08:00
|
|
|
/// The `Result` type of `f` must implement `std::convert::From<Error>`.
|
2015-08-28 02:01:01 +08:00
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Result,Connection};
|
|
|
|
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
2016-05-20 09:09:40 +08:00
|
|
|
/// conn.query_row_and_then("SELECT value FROM preferences WHERE name='locale'",
|
|
|
|
/// &[],
|
|
|
|
/// |row| {
|
2015-08-28 02:01:01 +08:00
|
|
|
/// row.get_checked(0)
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// If the query returns more than one row, all rows except the first are ignored.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
|
|
|
/// underlying SQLite call fails.
|
2016-02-03 02:12:00 +08:00
|
|
|
pub fn query_row_and_then<T, E, F>(&self,
|
|
|
|
sql: &str,
|
|
|
|
params: &[&ToSql],
|
|
|
|
f: F)
|
|
|
|
-> result::Result<T, E>
|
2016-10-08 00:42:27 +08:00
|
|
|
where F: FnOnce(&Row) -> result::Result<T, E>,
|
2015-12-13 02:53:58 +08:00
|
|
|
E: convert::From<Error>
|
2015-12-11 09:48:38 +08:00
|
|
|
{
|
|
|
|
let mut stmt = try!(self.prepare(sql));
|
|
|
|
let mut rows = try!(stmt.query(params));
|
|
|
|
|
2016-10-08 00:42:27 +08:00
|
|
|
rows.get_expected_row().map_err(E::from).and_then(|r| f(&r))
|
2015-12-11 09:48:38 +08:00
|
|
|
}
|
2015-08-28 02:01:01 +08:00
|
|
|
|
2015-01-11 11:17:49 +08:00
|
|
|
/// Convenience method to execute a query that is expected to return a single row.
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Result,Connection};
|
|
|
|
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
2015-01-11 11:17:49 +08:00
|
|
|
/// conn.query_row_safe("SELECT value FROM preferences WHERE name='locale'", &[], |row| {
|
|
|
|
/// row.get(0)
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// If the query returns more than one row, all rows except the first are ignored.
|
2015-05-05 08:12:18 +08:00
|
|
|
///
|
|
|
|
/// ## Deprecated
|
|
|
|
///
|
|
|
|
/// This method should be considered deprecated. Use `query_row` instead, which now
|
|
|
|
/// does exactly the same thing.
|
2016-05-30 08:36:20 +08:00
|
|
|
#[deprecated(since = "0.1.0", note = "Use query_row instead")]
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn query_row_safe<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
|
2016-10-08 00:42:27 +08:00
|
|
|
where F: FnOnce(&Row) -> T
|
2016-02-03 02:12:00 +08:00
|
|
|
{
|
|
|
|
self.query_row(sql, params, f)
|
|
|
|
}
|
2015-01-11 11:17:49 +08:00
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Prepare a SQL statement for execution.
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Connection, Result};
|
|
|
|
/// fn insert_new_people(conn: &Connection) -> Result<()> {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// let mut stmt = try!(conn.prepare("INSERT INTO People (name) VALUES (?)"));
|
|
|
|
/// try!(stmt.execute(&[&"Joe Smith"]));
|
|
|
|
/// try!(stmt.execute(&[&"Bob Jones"]));
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
|
|
|
/// underlying SQLite call fails.
|
2015-12-13 03:08:04 +08:00
|
|
|
pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>> {
|
2014-10-20 07:56:41 +08:00
|
|
|
self.db.borrow_mut().prepare(self, sql)
|
|
|
|
}
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Close the SQLite connection.
|
|
|
|
///
|
2015-12-13 02:50:12 +08:00
|
|
|
/// This is functionally equivalent to the `Drop` implementation for `Connection` except
|
2017-01-04 09:00:29 +08:00
|
|
|
/// that on failure, it returns an error and the connection itself (presumably so closing
|
|
|
|
/// can be attempted again).
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if the underlying SQLite call fails.
|
2017-01-04 09:00:29 +08:00
|
|
|
pub fn close(self) -> std::result::Result<(), (Connection, Error)> {
|
2016-11-05 03:47:28 +08:00
|
|
|
self.flush_prepared_statement_cache();
|
2017-01-04 09:00:29 +08:00
|
|
|
{
|
|
|
|
let mut db = self.db.borrow_mut();
|
|
|
|
db.close()
|
|
|
|
}
|
|
|
|
.map_err(move |err| (self, err))
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 03:20:11 +08:00
|
|
|
/// Enable loading of SQLite extensions. Strongly consider using `LoadExtensionGuard`
|
2015-02-24 09:16:49 +08:00
|
|
|
/// instead of this function.
|
2015-02-24 08:52:48 +08:00
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Connection, Result};
|
2015-02-24 08:52:48 +08:00
|
|
|
/// # use std::path::{Path};
|
2015-12-13 03:06:03 +08:00
|
|
|
/// fn load_my_extension(conn: &Connection) -> Result<()> {
|
2015-02-24 08:52:48 +08:00
|
|
|
/// try!(conn.load_extension_enable());
|
|
|
|
/// try!(conn.load_extension(Path::new("my_sqlite_extension"), None));
|
|
|
|
/// conn.load_extension_disable()
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if the underlying SQLite call fails.
|
2015-02-24 08:52:48 +08:00
|
|
|
#[cfg(feature = "load_extension")]
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn load_extension_enable(&self) -> Result<()> {
|
2015-02-24 08:52:48 +08:00
|
|
|
self.db.borrow_mut().enable_load_extension(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Disable loading of SQLite extensions.
|
|
|
|
///
|
|
|
|
/// See `load_extension_enable` for an example.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if the underlying SQLite call fails.
|
2015-02-24 08:52:48 +08:00
|
|
|
#[cfg(feature = "load_extension")]
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn load_extension_disable(&self) -> Result<()> {
|
2015-02-24 08:52:48 +08:00
|
|
|
self.db.borrow_mut().enable_load_extension(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Load the SQLite extension at `dylib_path`. `dylib_path` is passed through to
|
|
|
|
/// `sqlite3_load_extension`, which may attempt OS-specific modifications if the file
|
|
|
|
/// cannot be loaded directly.
|
|
|
|
///
|
|
|
|
/// If `entry_point` is `None`, SQLite will attempt to find the entry point. If it is not
|
|
|
|
/// `None`, the entry point will be passed through to `sqlite3_load_extension`.
|
2015-02-24 09:16:49 +08:00
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:20:11 +08:00
|
|
|
/// # use rusqlite::{Connection, Result, LoadExtensionGuard};
|
2015-02-24 09:16:49 +08:00
|
|
|
/// # use std::path::{Path};
|
2015-12-13 03:06:03 +08:00
|
|
|
/// fn load_my_extension(conn: &Connection) -> Result<()> {
|
2015-12-13 03:20:11 +08:00
|
|
|
/// let _guard = try!(LoadExtensionGuard::new(conn));
|
2015-02-24 09:16:49 +08:00
|
|
|
///
|
2015-09-08 16:06:41 +08:00
|
|
|
/// conn.load_extension("my_sqlite_extension", None)
|
2015-02-24 09:16:49 +08:00
|
|
|
/// }
|
2015-12-09 10:15:23 +08:00
|
|
|
/// ```
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if the underlying SQLite call fails.
|
2015-02-24 08:52:48 +08:00
|
|
|
#[cfg(feature = "load_extension")]
|
2015-12-11 05:48:09 +08:00
|
|
|
pub fn load_extension<P: AsRef<Path>>(&self,
|
|
|
|
dylib_path: P,
|
|
|
|
entry_point: Option<&str>)
|
2016-02-03 02:12:00 +08:00
|
|
|
-> Result<()> {
|
|
|
|
self.db.borrow_mut().load_extension(dylib_path.as_ref(), entry_point)
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2016-02-02 04:21:03 +08:00
|
|
|
/// Get access to the underlying SQLite database connection handle.
|
|
|
|
///
|
|
|
|
/// # Warning
|
|
|
|
///
|
|
|
|
/// You should not need to use this function. If you do need to, please [open an issue
|
|
|
|
/// on the rusqlite repository](https://github.com/jgallagher/rusqlite/issues) and describe
|
|
|
|
/// your use case. This function is unsafe because it gives you raw access to the SQLite
|
|
|
|
/// connection, and what you do with it could impact the safety of this `Connection`.
|
|
|
|
pub unsafe fn handle(&self) -> *mut ffi::Struct_sqlite3 {
|
|
|
|
self.db.borrow().db()
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn decode_result(&self, code: c_int) -> Result<()> {
|
2014-10-20 07:56:41 +08:00
|
|
|
self.db.borrow_mut().decode_result(code)
|
|
|
|
}
|
|
|
|
|
2015-01-11 10:39:59 +08:00
|
|
|
fn changes(&self) -> c_int {
|
2014-10-20 07:56:41 +08:00
|
|
|
self.db.borrow_mut().changes()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
impl fmt::Debug for Connection {
|
2014-10-20 07:56:41 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2015-12-13 02:50:12 +08:00
|
|
|
f.debug_struct("Connection")
|
2016-05-17 01:52:17 +08:00
|
|
|
.field("path", &self.path)
|
|
|
|
.finish()
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
struct InnerConnection {
|
2015-04-04 03:48:35 +08:00
|
|
|
db: *mut ffi::Struct_sqlite3,
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 03:13:29 +08:00
|
|
|
/// Old name for `OpenFlags`. `SqliteOpenFlags` is deprecated.
|
2016-05-30 08:36:20 +08:00
|
|
|
#[deprecated(since = "0.6.0", note = "Use OpenFlags instead")]
|
2015-12-13 03:13:29 +08:00
|
|
|
pub type SqliteOpenFlags = OpenFlags;
|
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
bitflags! {
|
2014-11-04 06:11:00 +08:00
|
|
|
#[doc = "Flags for opening SQLite database connections."]
|
|
|
|
#[doc = "See [sqlite3_open_v2](http://www.sqlite.org/c3ref/open.html) for details."]
|
|
|
|
#[repr(C)]
|
2016-05-17 00:36:48 +08:00
|
|
|
pub flags OpenFlags: ::libc::c_int {
|
2014-10-20 07:56:41 +08:00
|
|
|
const SQLITE_OPEN_READ_ONLY = 0x00000001,
|
|
|
|
const SQLITE_OPEN_READ_WRITE = 0x00000002,
|
|
|
|
const SQLITE_OPEN_CREATE = 0x00000004,
|
|
|
|
const SQLITE_OPEN_URI = 0x00000040,
|
|
|
|
const SQLITE_OPEN_MEMORY = 0x00000080,
|
|
|
|
const SQLITE_OPEN_NO_MUTEX = 0x00008000,
|
|
|
|
const SQLITE_OPEN_FULL_MUTEX = 0x00010000,
|
|
|
|
const SQLITE_OPEN_SHARED_CACHE = 0x00020000,
|
|
|
|
const SQLITE_OPEN_PRIVATE_CACHE = 0x00040000,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:13:29 +08:00
|
|
|
impl Default for OpenFlags {
|
|
|
|
fn default() -> OpenFlags {
|
2015-12-11 05:48:09 +08:00
|
|
|
SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NO_MUTEX | SQLITE_OPEN_URI
|
2015-07-07 02:24:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
impl InnerConnection {
|
2016-02-03 02:12:00 +08:00
|
|
|
fn open_with_flags(c_path: &CString, flags: OpenFlags) -> Result<InnerConnection> {
|
|
|
|
unsafe {
|
|
|
|
// Before opening the database, we need to check that SQLite hasn't been
|
|
|
|
// compiled or configured to be in single-threaded mode. If it has, we're
|
|
|
|
// exposing a very unsafe API to Rust, so refuse to open connections at all.
|
|
|
|
// Unfortunately, the check for this is quite gross. sqlite3_threadsafe() only
|
|
|
|
// returns how SQLite was _compiled_; there is no public API to check whether
|
|
|
|
// someone called sqlite3_config() to set single-threaded mode. We can cheat
|
|
|
|
// by trying to allocate a mutex, though; in single-threaded mode due to
|
|
|
|
// compilation settings, the magic value 8 is returned (see the definition of
|
|
|
|
// sqlite3_mutex_alloc at https://github.com/mackyle/sqlite/blob/master/src/mutex.h);
|
|
|
|
// in single-threaded mode due to sqlite3_config(), the magic value 8 is also
|
|
|
|
// returned (see the definition of noopMutexAlloc at
|
|
|
|
// https://github.com/mackyle/sqlite/blob/master/src/mutex_noop.c).
|
|
|
|
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
|
|
|
let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
|
2016-02-14 23:11:59 +08:00
|
|
|
let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
|
2016-02-03 02:12:00 +08:00
|
|
|
ffi::sqlite3_mutex_free(mutex_ptr);
|
|
|
|
if is_singlethreaded {
|
|
|
|
return Err(Error::SqliteSingleThreadedMode);
|
|
|
|
}
|
2015-12-17 12:33:56 +08:00
|
|
|
|
2016-02-03 02:12:00 +08:00
|
|
|
let mut db: *mut ffi::sqlite3 = mem::uninitialized();
|
|
|
|
let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), ptr::null());
|
|
|
|
if r != ffi::SQLITE_OK {
|
|
|
|
let e = if db.is_null() {
|
|
|
|
error_from_sqlite_code(r, None)
|
|
|
|
} else {
|
2015-12-13 14:04:09 +08:00
|
|
|
let e = error_from_handle(db, r);
|
2014-10-20 07:56:41 +08:00
|
|
|
ffi::sqlite3_close(db);
|
2016-02-03 02:12:00 +08:00
|
|
|
e
|
|
|
|
};
|
2015-12-13 12:10:35 +08:00
|
|
|
|
2016-02-03 02:12:00 +08:00
|
|
|
return Err(e);
|
2014-12-24 01:26:57 +08:00
|
|
|
}
|
2016-02-03 02:12:00 +08:00
|
|
|
let r = ffi::sqlite3_busy_timeout(db, 5000);
|
|
|
|
if r != ffi::SQLITE_OK {
|
|
|
|
let e = error_from_handle(db, r);
|
|
|
|
ffi::sqlite3_close(db);
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// attempt to turn on extended results code; don't fail if we can't.
|
|
|
|
ffi::sqlite3_extended_result_codes(db, 1);
|
|
|
|
|
|
|
|
Ok(InnerConnection { db: db })
|
2015-01-08 03:05:36 +08:00
|
|
|
}
|
2016-02-03 02:12:00 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-03-29 18:25:46 +08:00
|
|
|
fn db(&self) -> *mut ffi::Struct_sqlite3 {
|
2015-04-04 03:48:35 +08:00
|
|
|
self.db
|
2015-03-29 18:25:46 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn decode_result(&mut self, code: c_int) -> Result<()> {
|
2014-10-20 07:56:41 +08:00
|
|
|
if code == ffi::SQLITE_OK {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
2015-12-13 14:04:09 +08:00
|
|
|
Err(error_from_handle(self.db(), code))
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn close(&mut self) -> Result<()> {
|
2015-03-29 18:25:46 +08:00
|
|
|
unsafe {
|
|
|
|
let r = ffi::sqlite3_close(self.db());
|
2017-01-07 03:32:27 +08:00
|
|
|
let r = self.decode_result(r);
|
|
|
|
if r.is_ok() {
|
|
|
|
self.db = ptr::null_mut();
|
|
|
|
}
|
|
|
|
r
|
2015-03-29 18:25:46 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn execute_batch(&mut self, sql: &str) -> Result<()> {
|
2015-02-24 09:20:35 +08:00
|
|
|
let c_sql = try!(str_to_cstring(sql));
|
2015-01-08 03:05:36 +08:00
|
|
|
unsafe {
|
2015-12-11 05:48:09 +08:00
|
|
|
let r = ffi::sqlite3_exec(self.db(),
|
2016-02-03 02:12:00 +08:00
|
|
|
c_sql.as_ptr(),
|
|
|
|
None,
|
|
|
|
ptr::null_mut(),
|
|
|
|
ptr::null_mut());
|
2015-12-13 21:15:56 +08:00
|
|
|
self.decode_result(r)
|
2015-02-24 08:52:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "load_extension")]
|
2015-12-13 03:06:03 +08:00
|
|
|
fn enable_load_extension(&mut self, onoff: c_int) -> Result<()> {
|
2015-02-24 08:52:48 +08:00
|
|
|
let r = unsafe { ffi::sqlite3_enable_load_extension(self.db, onoff) };
|
|
|
|
self.decode_result(r)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "load_extension")]
|
2015-12-13 03:06:03 +08:00
|
|
|
fn load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> Result<()> {
|
2015-02-24 08:52:48 +08:00
|
|
|
let dylib_str = try!(path_to_cstring(dylib_path));
|
|
|
|
unsafe {
|
|
|
|
let mut errmsg: *mut c_char = mem::uninitialized();
|
|
|
|
let r = if let Some(entry_point) = entry_point {
|
|
|
|
let c_entry = try!(str_to_cstring(entry_point));
|
2015-12-11 05:48:09 +08:00
|
|
|
ffi::sqlite3_load_extension(self.db,
|
|
|
|
dylib_str.as_ptr(),
|
|
|
|
c_entry.as_ptr(),
|
|
|
|
&mut errmsg)
|
2014-10-20 07:56:41 +08:00
|
|
|
} else {
|
2015-02-24 08:52:48 +08:00
|
|
|
ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), ptr::null(), &mut errmsg)
|
|
|
|
};
|
2015-12-14 03:59:47 +08:00
|
|
|
if r == ffi::SQLITE_OK {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
let message = errmsg_to_string(&*errmsg);
|
|
|
|
ffi::sqlite3_free(errmsg as *mut libc::c_void);
|
2015-12-13 14:04:09 +08:00
|
|
|
Err(error_from_sqlite_code(r, Some(message)))
|
2015-12-14 03:59:47 +08:00
|
|
|
}
|
2015-01-08 03:05:36 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn last_insert_rowid(&self) -> i64 {
|
2015-12-11 05:48:09 +08:00
|
|
|
unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2016-02-03 02:12:00 +08:00
|
|
|
fn prepare<'a>(&mut self, conn: &'a Connection, sql: &str) -> Result<Statement<'a>> {
|
|
|
|
if sql.len() >= ::std::i32::MAX as usize {
|
|
|
|
return Err(error_from_sqlite_code(ffi::SQLITE_TOOBIG, None));
|
2015-08-08 15:30:50 +08:00
|
|
|
}
|
2016-02-03 02:12:00 +08:00
|
|
|
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())
|
|
|
|
};
|
2016-05-17 23:06:43 +08:00
|
|
|
self.decode_result(r).map(|_| Statement::new(conn, RawStatement::new(c_stmt)))
|
2016-02-03 02:12:00 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-01-11 10:39:59 +08:00
|
|
|
fn changes(&mut self) -> c_int {
|
2015-12-11 05:48:09 +08:00
|
|
|
unsafe { ffi::sqlite3_changes(self.db()) }
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
impl Drop for InnerConnection {
|
2014-10-20 07:56:41 +08:00
|
|
|
#[allow(unused_must_use)]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:08:04 +08:00
|
|
|
/// Old name for `Statement`. `SqliteStatement` is deprecated.
|
2016-05-30 08:36:20 +08:00
|
|
|
#[deprecated(since = "0.6.0", note = "Use Statement instead")]
|
2015-12-13 03:08:04 +08:00
|
|
|
pub type SqliteStatement<'conn> = Statement<'conn>;
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// A prepared statement.
|
2015-12-13 03:08:04 +08:00
|
|
|
pub struct Statement<'conn> {
|
2015-12-13 02:50:12 +08:00
|
|
|
conn: &'conn Connection,
|
2016-05-17 23:06:43 +08:00
|
|
|
stmt: RawStatement,
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 03:08:04 +08:00
|
|
|
impl<'conn> Statement<'conn> {
|
2016-05-17 23:06:43 +08:00
|
|
|
fn new(conn: &Connection, stmt: RawStatement) -> Statement {
|
2015-12-13 03:08:04 +08:00
|
|
|
Statement {
|
2015-12-11 05:48:09 +08:00
|
|
|
conn: conn,
|
|
|
|
stmt: stmt,
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-07-25 10:11:59 +08:00
|
|
|
/// Get all the column names in the result set of the prepared statement.
|
|
|
|
pub fn column_names(&self) -> Vec<&str> {
|
2016-05-19 11:19:04 +08:00
|
|
|
let n = self.column_count();
|
2015-07-25 10:11:59 +08:00
|
|
|
let mut cols = Vec::with_capacity(n as usize);
|
|
|
|
for i in 0..n {
|
2016-05-17 23:06:43 +08:00
|
|
|
let slice = self.stmt.column_name(i);
|
2015-07-25 10:11:59 +08:00
|
|
|
let s = str::from_utf8(slice.to_bytes()).unwrap();
|
|
|
|
cols.push(s);
|
|
|
|
}
|
|
|
|
cols
|
|
|
|
}
|
|
|
|
|
2016-01-02 17:28:00 +08:00
|
|
|
/// Return the number of columns in the result set returned by the prepared statement.
|
|
|
|
pub fn column_count(&self) -> i32 {
|
2016-05-19 11:19:04 +08:00
|
|
|
self.stmt.column_count()
|
2016-01-02 17:28:00 +08:00
|
|
|
}
|
|
|
|
|
2016-01-02 19:13:37 +08:00
|
|
|
/// Returns the column index in the result set for a given column name.
|
2016-05-20 09:09:40 +08:00
|
|
|
///
|
|
|
|
/// If there is no AS clause then the name of the column is unspecified and may change from one
|
|
|
|
/// release of SQLite to the next.
|
2016-01-02 19:13:37 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
2016-05-20 09:09:40 +08:00
|
|
|
///
|
2016-01-02 19:13:37 +08:00
|
|
|
/// 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();
|
2016-05-19 11:19:04 +08:00
|
|
|
let n = self.column_count();
|
2016-01-02 19:13:37 +08:00
|
|
|
for i in 0..n {
|
2016-05-17 23:06:43 +08:00
|
|
|
if bytes == self.stmt.column_name(i).to_bytes() {
|
2016-01-02 19:13:37 +08:00
|
|
|
return Ok(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(Error::InvalidColumnName(String::from(name)))
|
|
|
|
}
|
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Execute the prepared statement.
|
|
|
|
///
|
|
|
|
/// On success, returns the number of rows that were changed or inserted or deleted (via
|
|
|
|
/// `sqlite3_changes`).
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Connection, Result};
|
|
|
|
/// fn update_rows(conn: &Connection) -> Result<()> {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// let mut stmt = try!(conn.prepare("UPDATE foo SET bar = 'baz' WHERE qux = ?"));
|
|
|
|
///
|
|
|
|
/// try!(stmt.execute(&[&1i32]));
|
|
|
|
/// try!(stmt.execute(&[&2i32]));
|
|
|
|
///
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// 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.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn execute(&mut self, params: &[&ToSql]) -> Result<c_int> {
|
2016-05-17 23:06:43 +08:00
|
|
|
try!(self.bind_parameters(params));
|
|
|
|
self.execute_()
|
2015-08-05 03:48:54 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2016-05-17 23:06:43 +08:00
|
|
|
fn execute_(&mut self) -> Result<c_int> {
|
|
|
|
let r = self.stmt.step();
|
|
|
|
self.stmt.reset();
|
2015-08-05 03:48:54 +08:00
|
|
|
match r {
|
2015-11-11 21:39:15 +08:00
|
|
|
ffi::SQLITE_DONE => {
|
2016-05-19 11:19:04 +08:00
|
|
|
if self.column_count() == 0 {
|
2015-11-11 21:39:15 +08:00
|
|
|
Ok(self.conn.changes())
|
2016-03-29 23:54:02 +08:00
|
|
|
} else {
|
|
|
|
Err(Error::ExecuteReturnedResults)
|
2015-12-11 05:48:09 +08:00
|
|
|
}
|
2016-02-03 02:12:00 +08:00
|
|
|
}
|
2015-12-13 13:54:08 +08:00
|
|
|
ffi::SQLITE_ROW => Err(Error::ExecuteReturnedResults),
|
2015-08-05 03:48:54 +08:00
|
|
|
_ => Err(self.conn.decode_result(r).unwrap_err()),
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-19 00:33:58 +08:00
|
|
|
/// Execute the prepared statement, returning a handle to the resulting rows.
|
|
|
|
///
|
|
|
|
/// Due to lifetime restricts, the rows handle returned by `query` does not
|
|
|
|
/// implement the `Iterator` trait. Consider using `query_map` or `query_and_then`
|
|
|
|
/// instead, which do.
|
2014-11-04 06:11:00 +08:00
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-12-13 03:06:03 +08:00
|
|
|
/// # use rusqlite::{Connection, Result};
|
|
|
|
/// fn get_names(conn: &Connection) -> Result<Vec<String>> {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// let mut stmt = try!(conn.prepare("SELECT name FROM people"));
|
2014-11-19 23:48:40 +08:00
|
|
|
/// let mut rows = try!(stmt.query(&[]));
|
2014-11-04 06:11:00 +08:00
|
|
|
///
|
|
|
|
/// let mut names = Vec::new();
|
2016-05-19 00:33:58 +08:00
|
|
|
/// while let Some(result_row) = rows.next() {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// let row = try!(result_row);
|
|
|
|
/// names.push(row.get(0));
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// Ok(names)
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
2016-05-19 03:15:56 +08:00
|
|
|
/// ## Failure
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// Will return `Err` if binding parameters fails.
|
2015-12-13 03:09:37 +08:00
|
|
|
pub fn query<'a>(&'a mut self, params: &[&ToSql]) -> Result<Rows<'a>> {
|
2016-05-17 23:06:43 +08:00
|
|
|
try!(self.bind_parameters(params));
|
2015-12-13 03:09:37 +08:00
|
|
|
Ok(Rows::new(self))
|
2015-05-05 21:29:46 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2016-05-19 00:33:58 +08:00
|
|
|
/// Executes the prepared statement and maps a function over the resulting rows, returning
|
|
|
|
/// an iterator over the mapped function results.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
2016-05-19 03:15:56 +08:00
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use rusqlite::{Connection, Result};
|
|
|
|
/// fn get_names(conn: &Connection) -> Result<Vec<String>> {
|
|
|
|
/// let mut stmt = try!(conn.prepare("SELECT name FROM people"));
|
|
|
|
/// let rows = try!(stmt.query_map(&[], |row| row.get(0)));
|
|
|
|
///
|
|
|
|
/// let mut names = Vec::new();
|
|
|
|
/// for name_result in rows {
|
|
|
|
/// names.push(try!(name_result));
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// Ok(names)
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ## Failure
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// Will return `Err` if binding parameters fails.
|
2016-02-03 02:12:00 +08:00
|
|
|
pub fn query_map<'a, T, F>(&'a mut self, params: &[&ToSql], f: F) -> Result<MappedRows<'a, F>>
|
2015-12-13 03:11:24 +08:00
|
|
|
where F: FnMut(&Row) -> T
|
2016-02-03 02:12:00 +08:00
|
|
|
{
|
|
|
|
let row_iter = try!(self.query(params));
|
2015-12-11 05:48:09 +08:00
|
|
|
|
2016-02-03 02:12:00 +08:00
|
|
|
Ok(MappedRows {
|
|
|
|
rows: row_iter,
|
|
|
|
map: f,
|
|
|
|
})
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-08-28 01:43:43 +08:00
|
|
|
/// Executes the prepared statement and maps a function over the resulting
|
|
|
|
/// rows, where the function returns a `Result` with `Error` type implementing
|
2015-12-13 02:53:58 +08:00
|
|
|
/// `std::convert::From<Error>` (so errors can be unified).
|
2015-08-28 01:43:43 +08:00
|
|
|
///
|
2015-12-02 01:05:29 +08:00
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if binding parameters fails.
|
2015-12-11 05:48:09 +08:00
|
|
|
pub fn query_and_then<'a, T, E, F>(&'a mut self,
|
|
|
|
params: &[&ToSql],
|
|
|
|
f: F)
|
2016-02-03 02:12:00 +08:00
|
|
|
-> Result<AndThenRows<'a, F>>
|
2015-12-13 02:53:58 +08:00
|
|
|
where E: convert::From<Error>,
|
2015-12-13 03:11:24 +08:00
|
|
|
F: FnMut(&Row) -> result::Result<T, E>
|
2016-02-03 02:12:00 +08:00
|
|
|
{
|
|
|
|
let row_iter = try!(self.query(params));
|
2015-12-11 05:48:09 +08:00
|
|
|
|
2016-02-03 02:12:00 +08:00
|
|
|
Ok(AndThenRows {
|
|
|
|
rows: row_iter,
|
|
|
|
map: f,
|
|
|
|
})
|
|
|
|
}
|
2015-08-28 01:43:43 +08:00
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Consumes the statement.
|
|
|
|
///
|
|
|
|
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any errors
|
|
|
|
/// that occur.
|
2015-12-02 01:05:29 +08:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Will return `Err` if the underlying SQLite call fails.
|
2015-12-13 03:06:03 +08:00
|
|
|
pub fn finalize(mut self) -> Result<()> {
|
2014-10-20 07:56:41 +08:00
|
|
|
self.finalize_()
|
|
|
|
}
|
|
|
|
|
2016-05-26 10:57:43 +08:00
|
|
|
fn bind_parameter(&self, param: &ToSql, col: c_int) -> Result<()> {
|
2016-12-31 12:25:21 +08:00
|
|
|
let value = try!(param.to_sql());
|
2016-05-26 10:57:43 +08:00
|
|
|
|
|
|
|
let ptr = unsafe { self.stmt.ptr() };
|
|
|
|
let value = match value {
|
|
|
|
ToSqlOutput::Borrowed(v) => v,
|
|
|
|
ToSqlOutput::Owned(ref v) => ValueRef::from(v),
|
|
|
|
|
|
|
|
#[cfg(feature = "blob")]
|
|
|
|
ToSqlOutput::ZeroBlob(len) => {
|
2016-05-26 12:28:18 +08:00
|
|
|
return self.conn
|
|
|
|
.decode_result(unsafe { ffi::sqlite3_bind_zeroblob(ptr, col, len) });
|
2016-05-26 10:57:43 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
self.conn.decode_result(match value {
|
|
|
|
ValueRef::Null => unsafe { ffi::sqlite3_bind_null(ptr, col) },
|
|
|
|
ValueRef::Integer(i) => unsafe { ffi::sqlite3_bind_int64(ptr, col, i) },
|
|
|
|
ValueRef::Real(r) => unsafe { ffi::sqlite3_bind_double(ptr, col, r) },
|
|
|
|
ValueRef::Text(ref s) => unsafe {
|
|
|
|
let length = s.len();
|
|
|
|
if length > ::std::i32::MAX as usize {
|
|
|
|
ffi::SQLITE_TOOBIG
|
|
|
|
} else {
|
|
|
|
let c_str = try!(str_to_cstring(s));
|
|
|
|
let destructor = if length > 0 {
|
|
|
|
ffi::SQLITE_TRANSIENT()
|
|
|
|
} else {
|
|
|
|
ffi::SQLITE_STATIC()
|
|
|
|
};
|
|
|
|
ffi::sqlite3_bind_text(ptr, col, c_str.as_ptr(), length as c_int, destructor)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ValueRef::Blob(ref b) => unsafe {
|
|
|
|
let length = b.len();
|
|
|
|
if length > ::std::i32::MAX as usize {
|
|
|
|
ffi::SQLITE_TOOBIG
|
|
|
|
} else if length == 0 {
|
|
|
|
ffi::sqlite3_bind_zeroblob(ptr, col, 0)
|
|
|
|
} else {
|
2016-05-26 12:28:18 +08:00
|
|
|
ffi::sqlite3_bind_blob(ptr,
|
|
|
|
col,
|
|
|
|
b.as_ptr() as *const c_void,
|
|
|
|
length as c_int,
|
|
|
|
ffi::SQLITE_TRANSIENT())
|
2016-05-26 10:57:43 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-05-17 23:06:43 +08:00
|
|
|
fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> {
|
|
|
|
assert!(params.len() as c_int == self.stmt.bind_parameter_count(),
|
2016-02-03 02:12:00 +08:00
|
|
|
"incorrect number of parameters to query(): expected {}, got {}",
|
2016-05-17 23:06:43 +08:00
|
|
|
self.stmt.bind_parameter_count(),
|
2016-02-03 02:12:00 +08:00
|
|
|
params.len());
|
2015-05-05 21:29:46 +08:00
|
|
|
|
|
|
|
for (i, p) in params.iter().enumerate() {
|
2016-05-26 10:57:43 +08:00
|
|
|
try!(self.bind_parameter(*p, (i + 1) as c_int));
|
2015-05-05 21:29:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn finalize_(&mut self) -> Result<()> {
|
2016-05-17 23:06:43 +08:00
|
|
|
let mut stmt = RawStatement::new(ptr::null_mut());
|
|
|
|
mem::swap(&mut stmt, &mut self.stmt);
|
|
|
|
self.conn.decode_result(stmt.finalize())
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-18 00:55:10 +08:00
|
|
|
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
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:08:04 +08:00
|
|
|
impl<'conn> fmt::Debug for Statement<'conn> {
|
2014-10-20 07:56:41 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2016-05-17 23:06:43 +08:00
|
|
|
let sql = str::from_utf8(self.stmt.sql().to_bytes());
|
2015-12-13 03:08:04 +08:00
|
|
|
f.debug_struct("Statement")
|
2016-05-17 01:52:17 +08:00
|
|
|
.field("conn", self.conn)
|
|
|
|
.field("stmt", &self.stmt)
|
|
|
|
.field("sql", &sql)
|
|
|
|
.finish()
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:08:04 +08:00
|
|
|
impl<'conn> Drop for Statement<'conn> {
|
2014-10-20 07:56:41 +08:00
|
|
|
#[allow(unused_must_use)]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.finalize_();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-07 21:36:29 +08:00
|
|
|
/// An iterator over the mapped resulting rows of a query.
|
|
|
|
pub struct MappedRows<'stmt, F> {
|
2015-12-13 03:09:37 +08:00
|
|
|
rows: Rows<'stmt>,
|
2015-05-07 21:36:29 +08:00
|
|
|
map: F,
|
2015-05-05 21:29:46 +08:00
|
|
|
}
|
|
|
|
|
2016-05-17 01:52:17 +08:00
|
|
|
impl<'stmt, T, F> Iterator for MappedRows<'stmt, F>
|
|
|
|
where F: FnMut(&Row) -> T
|
2015-12-11 05:48:09 +08:00
|
|
|
{
|
2015-12-13 03:06:03 +08:00
|
|
|
type Item = Result<T>;
|
2015-05-05 21:29:46 +08:00
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
fn next(&mut self) -> Option<Result<T>> {
|
2016-05-19 00:33:58 +08:00
|
|
|
let map = &mut self.map;
|
|
|
|
self.rows.next().map(|row_result| row_result.map(|row| (map)(&row)))
|
2015-05-05 21:29:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-28 01:43:43 +08:00
|
|
|
/// An iterator over the mapped resulting rows of a query, with an Error type
|
2015-12-13 02:53:58 +08:00
|
|
|
/// unifying with Error.
|
2015-08-28 01:43:43 +08:00
|
|
|
pub struct AndThenRows<'stmt, F> {
|
2015-12-13 03:09:37 +08:00
|
|
|
rows: Rows<'stmt>,
|
2015-08-28 01:43:43 +08:00
|
|
|
map: F,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'stmt, T, E, F> Iterator for AndThenRows<'stmt, F>
|
2016-02-03 02:12:00 +08:00
|
|
|
where E: convert::From<Error>,
|
|
|
|
F: FnMut(&Row) -> result::Result<T, E>
|
2015-12-11 05:48:09 +08:00
|
|
|
{
|
2015-12-13 03:06:03 +08:00
|
|
|
type Item = result::Result<T, E>;
|
2015-08-28 01:43:43 +08:00
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
2016-05-19 00:33:58 +08:00
|
|
|
let map = &mut self.map;
|
2015-12-11 05:48:09 +08:00
|
|
|
self.rows.next().map(|row_result| {
|
|
|
|
row_result.map_err(E::from)
|
2016-05-19 00:33:58 +08:00
|
|
|
.and_then(|row| (map)(&row))
|
2015-12-11 05:48:09 +08:00
|
|
|
})
|
2015-08-28 01:43:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:09:37 +08:00
|
|
|
/// Old name for `Rows`. `SqliteRows` is deprecated.
|
2016-05-30 08:36:20 +08:00
|
|
|
#[deprecated(since = "0.6.0", note = "Use Rows instead")]
|
2015-12-13 03:09:37 +08:00
|
|
|
pub type SqliteRows<'stmt> = Rows<'stmt>;
|
|
|
|
|
2016-05-19 00:33:58 +08:00
|
|
|
/// An handle for the resulting rows of a query.
|
2015-12-13 03:09:37 +08:00
|
|
|
pub struct Rows<'stmt> {
|
2016-05-17 03:39:14 +08:00
|
|
|
stmt: Option<&'stmt Statement<'stmt>>,
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2016-08-08 21:23:55 +08:00
|
|
|
#[allow(should_implement_trait)]
|
2015-12-13 03:09:37 +08:00
|
|
|
impl<'stmt> Rows<'stmt> {
|
|
|
|
fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
|
2016-05-20 09:04:33 +08:00
|
|
|
Rows { stmt: Some(stmt) }
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
2015-12-11 09:48:38 +08:00
|
|
|
|
2016-05-19 00:33:58 +08:00
|
|
|
fn get_expected_row<'a>(&'a mut self) -> Result<Row<'a, 'stmt>> {
|
2015-12-11 09:48:38 +08:00
|
|
|
match self.next() {
|
|
|
|
Some(row) => row,
|
2015-12-13 13:54:08 +08:00
|
|
|
None => Err(Error::QueryReturnedNoRows),
|
2015-12-11 09:48:38 +08:00
|
|
|
}
|
|
|
|
}
|
2016-05-17 03:39:14 +08:00
|
|
|
|
|
|
|
fn reset(&mut self) {
|
|
|
|
if let Some(stmt) = self.stmt.take() {
|
2016-05-17 23:06:43 +08:00
|
|
|
stmt.stmt.reset();
|
2016-05-17 03:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2016-05-19 00:33:58 +08:00
|
|
|
/// Attempt to get the next row from the query. Returns `Some(Ok(Row))` if there
|
|
|
|
/// is another row, `Some(Err(...))` if there was an error getting the next
|
|
|
|
/// row, and `None` if all rows have been retrieved.
|
|
|
|
///
|
|
|
|
/// ## Note
|
|
|
|
///
|
|
|
|
/// This interface is not compatible with Rust's `Iterator` trait, because the
|
|
|
|
/// lifetime of the returned row is tied to the lifetime of `self`. This is a
|
|
|
|
/// "streaming iterator". For a more natural interface, consider using `query_map`
|
|
|
|
/// or `query_and_then` instead, which return types that implement `Iterator`.
|
|
|
|
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
|
2016-05-17 03:39:14 +08:00
|
|
|
self.stmt.and_then(|stmt| {
|
2016-05-17 23:06:43 +08:00
|
|
|
match stmt.stmt.step() {
|
2016-05-17 03:39:14 +08:00
|
|
|
ffi::SQLITE_ROW => {
|
|
|
|
Some(Ok(Row {
|
|
|
|
stmt: stmt,
|
2016-05-19 00:33:58 +08:00
|
|
|
phantom: PhantomData,
|
2016-05-17 03:39:14 +08:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
ffi::SQLITE_DONE => {
|
|
|
|
self.reset();
|
|
|
|
None
|
|
|
|
}
|
|
|
|
code => {
|
|
|
|
self.reset();
|
|
|
|
Some(Err(stmt.conn.decode_result(code).unwrap_err()))
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
2016-05-17 03:39:14 +08:00
|
|
|
})
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-17 03:02:39 +08:00
|
|
|
impl<'stmt> Drop for Rows<'stmt> {
|
|
|
|
fn drop(&mut self) {
|
2016-05-17 03:39:14 +08:00
|
|
|
self.reset();
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:11:24 +08:00
|
|
|
/// Old name for `Row`. `SqliteRow` is deprecated.
|
2016-05-30 08:36:20 +08:00
|
|
|
#[deprecated(since = "0.6.0", note = "Use Row instead")]
|
2016-05-19 00:33:58 +08:00
|
|
|
pub type SqliteRow<'a, 'stmt> = Row<'a, 'stmt>;
|
2015-12-13 03:11:24 +08:00
|
|
|
|
2014-11-04 06:11:00 +08:00
|
|
|
/// A single result row of a query.
|
2016-05-19 00:33:58 +08:00
|
|
|
pub struct Row<'a, 'stmt> {
|
2015-12-13 03:08:04 +08:00
|
|
|
stmt: &'stmt Statement<'stmt>,
|
2016-05-19 00:33:58 +08:00
|
|
|
phantom: PhantomData<&'a ()>,
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2016-05-19 00:33:58 +08:00
|
|
|
impl<'a, 'stmt> Row<'a, 'stmt> {
|
2014-11-04 06:11:00 +08:00
|
|
|
/// Get the value of a particular column of the result row.
|
|
|
|
///
|
|
|
|
/// ## Failure
|
|
|
|
///
|
2016-01-02 19:13:37 +08:00
|
|
|
/// Panics if the underlying SQLite column type is not a valid type as a source for `T`.
|
|
|
|
///
|
2016-05-19 00:33:58 +08:00
|
|
|
/// Panics if `idx` is outside the range of columns in the returned query.
|
2016-01-02 19:13:37 +08:00
|
|
|
pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
|
2015-09-21 22:31:11 +08:00
|
|
|
self.get_checked(idx).unwrap()
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-05-05 09:47:20 +08:00
|
|
|
/// Get the value of a particular column of the result row.
|
|
|
|
///
|
|
|
|
/// ## Failure
|
|
|
|
///
|
2016-01-02 19:13:37 +08:00
|
|
|
/// Returns an `Error::InvalidColumnType` if the underlying SQLite column
|
2015-05-05 09:47:20 +08:00
|
|
|
/// type is not a valid type as a source for `T`.
|
|
|
|
///
|
2016-01-02 19:13:37 +08:00
|
|
|
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid column range
|
|
|
|
/// for this row.
|
|
|
|
///
|
|
|
|
/// Returns an `Error::InvalidColumnName` if `idx` is not a valid column name
|
|
|
|
/// for this row.
|
|
|
|
pub fn get_checked<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
|
2016-05-24 09:49:54 +08:00
|
|
|
let idx = try!(idx.idx(self.stmt));
|
2016-05-25 09:34:18 +08:00
|
|
|
let value = unsafe { ValueRef::new(&self.stmt.stmt, idx) };
|
2016-05-31 02:35:56 +08:00
|
|
|
FromSql::column_result(value).map_err(|err| match err {
|
2016-06-03 03:03:25 +08:00
|
|
|
FromSqlError::InvalidType => Error::InvalidColumnType(idx, value.data_type()),
|
2017-01-23 08:26:19 +08:00
|
|
|
FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
|
2016-06-03 03:03:25 +08:00
|
|
|
FromSqlError::Other(err) => {
|
|
|
|
Error::FromSqlConversionFailure(idx as usize, value.data_type(), err)
|
|
|
|
}
|
2016-05-31 02:35:56 +08:00
|
|
|
})
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
2016-01-02 17:28:00 +08:00
|
|
|
|
|
|
|
/// Return the number of columns in the current row.
|
|
|
|
pub fn column_count(&self) -> i32 {
|
|
|
|
self.stmt.column_count()
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2016-01-02 19:13:37 +08:00
|
|
|
/// A trait implemented by types that can index into columns of a row.
|
|
|
|
pub trait RowIndex {
|
|
|
|
/// Returns the index of the appropriate column, or `None` if no such
|
|
|
|
/// column exists.
|
|
|
|
fn idx(&self, stmt: &Statement) -> Result<i32>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RowIndex for i32 {
|
|
|
|
#[inline]
|
|
|
|
fn idx(&self, stmt: &Statement) -> Result<i32> {
|
2016-05-19 11:19:04 +08:00
|
|
|
if *self < 0 || *self >= stmt.column_count() {
|
2016-01-02 19:13:37 +08:00
|
|
|
Err(Error::InvalidColumnIndex(*self))
|
|
|
|
} else {
|
|
|
|
Ok(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> RowIndex for &'a str {
|
|
|
|
#[inline]
|
|
|
|
fn idx(&self, stmt: &Statement) -> Result<i32> {
|
|
|
|
stmt.column_index(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 09:34:18 +08:00
|
|
|
impl<'a> ValueRef<'a> {
|
|
|
|
unsafe fn new(stmt: &RawStatement, col: c_int) -> ValueRef {
|
2016-05-24 09:49:54 +08:00
|
|
|
use std::slice::from_raw_parts;
|
|
|
|
|
|
|
|
let raw = stmt.ptr();
|
|
|
|
|
|
|
|
match stmt.column_type(col) {
|
2016-05-25 09:34:18 +08:00
|
|
|
ffi::SQLITE_NULL => ValueRef::Null,
|
|
|
|
ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_column_int64(raw, col)),
|
|
|
|
ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_column_double(raw, col)),
|
2016-05-24 09:49:54 +08:00
|
|
|
ffi::SQLITE_TEXT => {
|
|
|
|
let text = ffi::sqlite3_column_text(raw, col);
|
2016-05-27 03:03:05 +08:00
|
|
|
assert!(!text.is_null(),
|
|
|
|
"unexpected SQLITE_TEXT column type with NULL data");
|
2016-05-24 09:49:54 +08:00
|
|
|
let s = CStr::from_ptr(text as *const c_char);
|
|
|
|
|
|
|
|
// sqlite3_column_text returns UTF8 data, so our unwrap here should be fine.
|
|
|
|
let s = s.to_str().expect("sqlite3_column_text returned invalid UTF-8");
|
2016-05-25 09:34:18 +08:00
|
|
|
ValueRef::Text(s)
|
2016-05-24 09:49:54 +08:00
|
|
|
}
|
|
|
|
ffi::SQLITE_BLOB => {
|
|
|
|
let blob = ffi::sqlite3_column_blob(raw, col);
|
|
|
|
|
|
|
|
let len = ffi::sqlite3_column_bytes(raw, col);
|
|
|
|
assert!(len >= 0, "unexpected negative return from sqlite3_column_bytes");
|
2016-06-14 02:32:39 +08:00
|
|
|
if len > 0 {
|
|
|
|
assert!(!blob.is_null(), "unexpected SQLITE_BLOB column type with NULL data");
|
|
|
|
ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize))
|
|
|
|
} else {
|
|
|
|
// The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
|
|
|
|
ValueRef::Blob(&[])
|
|
|
|
}
|
2016-05-24 09:49:54 +08:00
|
|
|
}
|
2016-05-27 03:03:05 +08:00
|
|
|
_ => unreachable!("sqlite3_column_type returned invalid value"),
|
2016-05-24 09:49:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2015-05-05 03:22:11 +08:00
|
|
|
extern crate tempdir;
|
2015-09-21 09:28:50 +08:00
|
|
|
pub use super::*;
|
2016-02-14 23:24:35 +08:00
|
|
|
use ffi;
|
2015-05-05 03:22:11 +08:00
|
|
|
use self::tempdir::TempDir;
|
2015-09-21 09:28:50 +08:00
|
|
|
pub use std::error::Error as StdError;
|
|
|
|
pub use std::fmt;
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-03-29 18:25:46 +08:00
|
|
|
// this function is never called, but is still type checked; in
|
|
|
|
// particular, calls with specific instantiations will require
|
|
|
|
// that those types are `Send`.
|
|
|
|
#[allow(dead_code, unconditional_recursion)]
|
|
|
|
fn ensure_send<T: Send>() {
|
2015-12-13 02:50:12 +08:00
|
|
|
ensure_send::<Connection>();
|
2015-03-29 18:25:46 +08:00
|
|
|
}
|
|
|
|
|
2015-12-13 02:50:12 +08:00
|
|
|
pub fn checked_memory_handle() -> Connection {
|
|
|
|
Connection::open_in_memory().unwrap()
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-05-05 03:22:11 +08:00
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-05-05 03:22:11 +08:00
|
|
|
fn test_persistence() {
|
|
|
|
let temp_dir = TempDir::new("test_open_file").unwrap();
|
|
|
|
let path = temp_dir.path().join("test.db3");
|
|
|
|
|
|
|
|
{
|
2015-12-13 02:50:12 +08:00
|
|
|
let db = Connection::open(&path).unwrap();
|
2015-05-05 03:22:11 +08:00
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER);
|
|
|
|
INSERT INTO foo VALUES(42);
|
|
|
|
END;";
|
2015-12-11 05:48:09 +08:00
|
|
|
db.execute_batch(sql).unwrap();
|
2015-05-05 03:22:11 +08:00
|
|
|
}
|
2015-05-05 08:02:33 +08:00
|
|
|
|
2015-05-05 03:22:11 +08:00
|
|
|
let path_string = path.to_str().unwrap();
|
2015-12-13 02:50:12 +08:00
|
|
|
let db = Connection::open(&path_string).unwrap();
|
2016-01-02 19:13:37 +08:00
|
|
|
let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", &[], |r| r.get(0));
|
2015-05-05 03:22:11 +08:00
|
|
|
|
|
|
|
assert_eq!(42i64, the_answer.unwrap());
|
|
|
|
}
|
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
#[test]
|
|
|
|
fn test_open() {
|
2015-12-13 02:50:12 +08:00
|
|
|
assert!(Connection::open_in_memory().is_ok());
|
2014-10-20 07:56:41 +08:00
|
|
|
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
assert!(db.close().is_ok());
|
|
|
|
}
|
|
|
|
|
2017-01-04 09:00:29 +08:00
|
|
|
#[test]
|
|
|
|
fn test_close_retry() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
|
|
|
|
// force the DB to be busy by preparing a statement; this must be done at the FFI
|
|
|
|
// level to allow us to call .close() without dropping the prepared statement first.
|
|
|
|
let raw_stmt = {
|
|
|
|
use std::mem;
|
|
|
|
use std::ptr;
|
|
|
|
use libc::c_int;
|
|
|
|
use super::str_to_cstring;
|
|
|
|
|
|
|
|
let raw_db = db.db.borrow_mut().db;
|
|
|
|
let sql = "SELECT 1";
|
|
|
|
let mut raw_stmt: *mut ffi::sqlite3_stmt = unsafe { mem::uninitialized() };
|
|
|
|
let rc = unsafe {
|
|
|
|
ffi::sqlite3_prepare_v2(raw_db,
|
|
|
|
str_to_cstring(sql).unwrap().as_ptr(),
|
|
|
|
(sql.len() + 1) as c_int,
|
|
|
|
&mut raw_stmt,
|
|
|
|
ptr::null_mut())
|
|
|
|
};
|
|
|
|
assert_eq!(rc, ffi::SQLITE_OK);
|
|
|
|
raw_stmt
|
|
|
|
};
|
|
|
|
|
2017-01-07 03:32:27 +08:00
|
|
|
// now that we have an open statement, trying (and retrying) to close should fail.
|
|
|
|
let (db, _) = db.close().unwrap_err();
|
|
|
|
let (db, _) = db.close().unwrap_err();
|
|
|
|
let (db, _) = db.close().unwrap_err();
|
2017-01-04 09:00:29 +08:00
|
|
|
|
2017-01-07 03:32:27 +08:00
|
|
|
// finalize the open statement so a final close will succeed
|
2017-01-04 09:00:29 +08:00
|
|
|
assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
|
|
|
|
|
|
|
|
db.close().unwrap();
|
|
|
|
}
|
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
#[test]
|
|
|
|
fn test_open_with_flags() {
|
2016-03-30 02:18:56 +08:00
|
|
|
for bad_flags in &[OpenFlags::empty(),
|
|
|
|
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_READ_WRITE,
|
|
|
|
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_CREATE] {
|
2016-02-03 02:12:00 +08:00
|
|
|
assert!(Connection::open_in_memory_with_flags(*bad_flags).is_err());
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2014-10-20 07:56:41 +08:00
|
|
|
fn test_execute_batch() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER);
|
|
|
|
INSERT INTO foo VALUES(1);
|
|
|
|
INSERT INTO foo VALUES(2);
|
|
|
|
INSERT INTO foo VALUES(3);
|
|
|
|
INSERT INTO foo VALUES(4);
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3").unwrap();
|
|
|
|
|
|
|
|
assert!(db.execute_batch("INVALID SQL").is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_execute() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
assert_eq!(1,
|
|
|
|
db.execute("INSERT INTO foo(x) VALUES (?)", &[&1i32]).unwrap());
|
|
|
|
assert_eq!(1,
|
|
|
|
db.execute("INSERT INTO foo(x) VALUES (?)", &[&2i32]).unwrap());
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-12-11 05:48:09 +08:00
|
|
|
assert_eq!(3i32,
|
|
|
|
db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap());
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
2015-08-01 14:09:59 +08:00
|
|
|
#[test]
|
|
|
|
fn test_execute_select() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let err = db.execute("SELECT 1 WHERE 1 < ?", &[&1i32]).unwrap_err();
|
2015-12-13 13:54:08 +08:00
|
|
|
match err {
|
|
|
|
Error::ExecuteReturnedResults => (),
|
|
|
|
_ => panic!("Unexpected error: {}", err),
|
|
|
|
}
|
2015-08-01 14:09:59 +08:00
|
|
|
}
|
|
|
|
|
2015-07-25 10:11:59 +08:00
|
|
|
#[test]
|
|
|
|
fn test_prepare_column_names() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap();
|
|
|
|
|
|
|
|
let stmt = db.prepare("SELECT * FROM foo").unwrap();
|
2016-01-02 17:28:00 +08:00
|
|
|
assert_eq!(stmt.column_count(), 1);
|
2015-07-25 10:11:59 +08:00
|
|
|
assert_eq!(stmt.column_names(), vec!["x"]);
|
|
|
|
|
|
|
|
let stmt = db.prepare("SELECT x AS a, x AS b FROM foo").unwrap();
|
2016-01-02 17:28:00 +08:00
|
|
|
assert_eq!(stmt.column_count(), 2);
|
2015-07-25 10:11:59 +08:00
|
|
|
assert_eq!(stmt.column_names(), vec!["a", "b"]);
|
|
|
|
}
|
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
#[test]
|
|
|
|
fn test_prepare_execute() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap();
|
|
|
|
|
|
|
|
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)").unwrap();
|
|
|
|
assert_eq!(insert_stmt.execute(&[&1i32]).unwrap(), 1);
|
|
|
|
assert_eq!(insert_stmt.execute(&[&2i32]).unwrap(), 1);
|
|
|
|
assert_eq!(insert_stmt.execute(&[&3i32]).unwrap(), 1);
|
|
|
|
|
|
|
|
assert_eq!(insert_stmt.execute(&[&"hello".to_string()]).unwrap(), 1);
|
|
|
|
assert_eq!(insert_stmt.execute(&[&"goodbye".to_string()]).unwrap(), 1);
|
|
|
|
assert_eq!(insert_stmt.execute(&[&types::Null]).unwrap(), 1);
|
|
|
|
|
|
|
|
let mut update_stmt = db.prepare("UPDATE foo SET x=? WHERE x<?").unwrap();
|
|
|
|
assert_eq!(update_stmt.execute(&[&3i32, &3i32]).unwrap(), 2);
|
|
|
|
assert_eq!(update_stmt.execute(&[&3i32, &3i32]).unwrap(), 0);
|
|
|
|
assert_eq!(update_stmt.execute(&[&8i32, &8i32]).unwrap(), 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_prepare_query() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap();
|
|
|
|
|
|
|
|
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)").unwrap();
|
|
|
|
assert_eq!(insert_stmt.execute(&[&1i32]).unwrap(), 1);
|
|
|
|
assert_eq!(insert_stmt.execute(&[&2i32]).unwrap(), 1);
|
|
|
|
assert_eq!(insert_stmt.execute(&[&3i32]).unwrap(), 1);
|
|
|
|
|
|
|
|
let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC").unwrap();
|
|
|
|
{
|
2016-05-19 00:33:58 +08:00
|
|
|
let mut rows = query.query(&[&4i32]).unwrap();
|
|
|
|
let mut v = Vec::<i32>::new();
|
|
|
|
|
|
|
|
while let Some(row) = rows.next() {
|
|
|
|
v.push(row.unwrap().get(0));
|
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
|
2015-03-17 12:55:28 +08:00
|
|
|
assert_eq!(v, [3i32, 2, 1]);
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2016-05-19 00:33:58 +08:00
|
|
|
let mut rows = query.query(&[&3i32]).unwrap();
|
|
|
|
let mut v = Vec::<i32>::new();
|
|
|
|
|
|
|
|
while let Some(row) = rows.next() {
|
|
|
|
v.push(row.unwrap().get(0));
|
|
|
|
}
|
|
|
|
|
2015-03-17 12:55:28 +08:00
|
|
|
assert_eq!(v, [2i32, 1]);
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-05 21:29:46 +08:00
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-05-05 21:29:46 +08:00
|
|
|
fn test_query_map() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
INSERT INTO foo VALUES(3, \", \");
|
|
|
|
INSERT INTO foo VALUES(2, \"world\");
|
|
|
|
INSERT INTO foo VALUES(1, \"!\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
|
2015-12-13 03:06:03 +08:00
|
|
|
let results: Result<Vec<String>> = query.query_map(&[], |row| row.get(1))
|
2015-05-06 11:29:34 +08:00
|
|
|
.unwrap()
|
|
|
|
.collect();
|
2015-05-05 21:29:46 +08:00
|
|
|
|
|
|
|
assert_eq!(results.unwrap().concat(), "hello, world!");
|
|
|
|
}
|
|
|
|
|
2015-01-11 11:17:49 +08:00
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-05-07 21:41:02 +08:00
|
|
|
fn test_query_row() {
|
2015-01-11 11:17:49 +08:00
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER);
|
|
|
|
INSERT INTO foo VALUES(1);
|
|
|
|
INSERT INTO foo VALUES(2);
|
|
|
|
INSERT INTO foo VALUES(3);
|
|
|
|
INSERT INTO foo VALUES(4);
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
2015-12-11 05:48:09 +08:00
|
|
|
assert_eq!(10i64,
|
2016-01-02 19:13:37 +08:00
|
|
|
db.query_row("SELECT SUM(x) FROM foo", &[], |r| r.get(0))
|
2015-12-11 05:48:09 +08:00
|
|
|
.unwrap());
|
2015-01-11 11:17:49 +08:00
|
|
|
|
2016-01-02 19:13:37 +08:00
|
|
|
let result: Result<i64> = db.query_row("SELECT x FROM foo WHERE x > 5", &[], |r| r.get(0));
|
2015-12-13 13:54:08 +08:00
|
|
|
match result.unwrap_err() {
|
|
|
|
Error::QueryReturnedNoRows => (),
|
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-01-11 11:17:49 +08:00
|
|
|
|
2015-05-07 21:41:02 +08:00
|
|
|
let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", &[], |_| ());
|
2015-01-11 11:17:49 +08:00
|
|
|
|
|
|
|
assert!(bad_query_result.is_err());
|
|
|
|
}
|
|
|
|
|
2014-10-20 07:56:41 +08:00
|
|
|
#[test]
|
|
|
|
fn test_prepare_failures() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap();
|
|
|
|
|
|
|
|
let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
|
2015-12-13 13:54:08 +08:00
|
|
|
assert!(format!("{}", err).contains("does_not_exist"));
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_last_insert_rowid() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)").unwrap();
|
|
|
|
db.execute_batch("INSERT INTO foo DEFAULT VALUES").unwrap();
|
|
|
|
|
|
|
|
assert_eq!(db.last_insert_rowid(), 1);
|
|
|
|
|
|
|
|
let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES").unwrap();
|
2015-12-11 05:48:09 +08:00
|
|
|
for _ in 0i32..9 {
|
2014-11-19 23:48:40 +08:00
|
|
|
stmt.execute(&[]).unwrap();
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|
|
|
|
assert_eq!(db.last_insert_rowid(), 10);
|
|
|
|
}
|
2015-09-21 08:44:51 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_statement_debugging() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let query = "SELECT 12345";
|
|
|
|
let stmt = db.prepare(query).unwrap();
|
|
|
|
|
|
|
|
assert!(format!("{:?}", stmt).contains(query));
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
|
2015-12-13 12:10:35 +08:00
|
|
|
#[test]
|
|
|
|
fn test_notnull_constraint_error() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
db.execute_batch("CREATE TABLE foo(x NOT NULL)").unwrap();
|
|
|
|
|
|
|
|
let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", &[]);
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match result.unwrap_err() {
|
2015-12-16 03:41:54 +08:00
|
|
|
Error::SqliteFailure(err, _) => {
|
|
|
|
assert_eq!(err.code, ffi::ErrorCode::ConstraintViolation);
|
|
|
|
|
|
|
|
// extended error codes for constraints were added in SQLite 3.7.16; if we're
|
|
|
|
// running on a version at least that new, check for the extended code
|
|
|
|
let version = unsafe { ffi::sqlite3_libversion_number() };
|
|
|
|
if version >= 3007016 {
|
|
|
|
assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL)
|
|
|
|
}
|
2016-02-03 02:12:00 +08:00
|
|
|
}
|
2015-12-13 13:54:08 +08:00
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-12-13 12:10:35 +08:00
|
|
|
}
|
|
|
|
|
2015-09-21 09:28:50 +08:00
|
|
|
mod query_and_then_tests {
|
|
|
|
extern crate libsqlite3_sys as ffi;
|
|
|
|
use super::*;
|
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
#[derive(Debug)]
|
2015-09-21 09:28:50 +08:00
|
|
|
enum CustomError {
|
|
|
|
SomeError,
|
2015-12-13 02:53:58 +08:00
|
|
|
Sqlite(Error),
|
2015-09-21 09:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CustomError {
|
2015-12-13 03:06:03 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
|
2015-09-21 09:28:50 +08:00
|
|
|
match *self {
|
2015-12-11 05:48:09 +08:00
|
|
|
CustomError::SomeError => write!(f, "{}", self.description()),
|
2015-09-21 09:28:50 +08:00
|
|
|
CustomError::Sqlite(ref se) => write!(f, "{}: {}", self.description(), se),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StdError for CustomError {
|
2015-12-11 05:48:09 +08:00
|
|
|
fn description(&self) -> &str {
|
|
|
|
"my custom error"
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
fn cause(&self) -> Option<&StdError> {
|
|
|
|
match *self {
|
2015-12-11 05:48:09 +08:00
|
|
|
CustomError::SomeError => None,
|
2015-09-21 09:28:50 +08:00
|
|
|
CustomError::Sqlite(ref se) => Some(se),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 02:53:58 +08:00
|
|
|
impl From<Error> for CustomError {
|
|
|
|
fn from(se: Error) -> CustomError {
|
2015-09-21 09:28:50 +08:00
|
|
|
CustomError::Sqlite(se)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 03:06:03 +08:00
|
|
|
type CustomResult<T> = ::std::result::Result<T, CustomError>;
|
2015-09-21 09:28:50 +08:00
|
|
|
|
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-09-21 09:28:50 +08:00
|
|
|
fn test_query_and_then() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
INSERT INTO foo VALUES(3, \", \");
|
|
|
|
INSERT INTO foo VALUES(2, \"world\");
|
|
|
|
INSERT INTO foo VALUES(1, \"!\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
|
2015-12-13 03:06:03 +08:00
|
|
|
let results: Result<Vec<String>> = query.query_and_then(&[],
|
2015-12-11 05:48:09 +08:00
|
|
|
|row| row.get_checked(1))
|
2015-09-21 09:28:50 +08:00
|
|
|
.unwrap()
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
assert_eq!(results.unwrap().concat(), "hello, world!");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-09-21 09:28:50 +08:00
|
|
|
fn test_query_and_then_fails() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
INSERT INTO foo VALUES(3, \", \");
|
|
|
|
INSERT INTO foo VALUES(2, \"world\");
|
|
|
|
INSERT INTO foo VALUES(1, \"!\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
|
2015-12-13 13:54:08 +08:00
|
|
|
let bad_type: Result<Vec<f64>> = query.query_and_then(&[], |row| row.get_checked(1))
|
2015-09-21 09:28:50 +08:00
|
|
|
.unwrap()
|
|
|
|
.collect();
|
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match bad_type.unwrap_err() {
|
2016-05-27 03:03:05 +08:00
|
|
|
Error::InvalidColumnType(_, _) => (),
|
2015-12-13 13:54:08 +08:00
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
let bad_idx: Result<Vec<String>> = query.query_and_then(&[], |row| row.get_checked(3))
|
2015-09-21 09:28:50 +08:00
|
|
|
.unwrap()
|
|
|
|
.collect();
|
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match bad_idx.unwrap_err() {
|
|
|
|
Error::InvalidColumnIndex(_) => (),
|
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-09-21 09:28:50 +08:00
|
|
|
fn test_query_and_then_custom_error() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
INSERT INTO foo VALUES(3, \", \");
|
|
|
|
INSERT INTO foo VALUES(2, \"world\");
|
|
|
|
INSERT INTO foo VALUES(1, \"!\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
|
2015-12-11 05:48:09 +08:00
|
|
|
let results: CustomResult<Vec<String>> = query.query_and_then(&[], |row| {
|
|
|
|
row.get_checked(1)
|
|
|
|
.map_err(CustomError::Sqlite)
|
|
|
|
})
|
|
|
|
.unwrap()
|
2015-09-21 09:28:50 +08:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
assert_eq!(results.unwrap().concat(), "hello, world!");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-09-21 09:28:50 +08:00
|
|
|
fn test_query_and_then_custom_error_fails() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
INSERT INTO foo VALUES(3, \", \");
|
|
|
|
INSERT INTO foo VALUES(2, \"world\");
|
|
|
|
INSERT INTO foo VALUES(1, \"!\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
|
2015-12-11 05:48:09 +08:00
|
|
|
let bad_type: CustomResult<Vec<f64>> = query.query_and_then(&[], |row| {
|
|
|
|
row.get_checked(1)
|
|
|
|
.map_err(CustomError::Sqlite)
|
|
|
|
})
|
|
|
|
.unwrap()
|
2015-09-21 09:28:50 +08:00
|
|
|
.collect();
|
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match bad_type.unwrap_err() {
|
2016-05-27 03:03:05 +08:00
|
|
|
CustomError::Sqlite(Error::InvalidColumnType(_, _)) => (),
|
2015-12-13 13:54:08 +08:00
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
|
2015-12-11 05:48:09 +08:00
|
|
|
let bad_idx: CustomResult<Vec<String>> = query.query_and_then(&[], |row| {
|
|
|
|
row.get_checked(3)
|
|
|
|
.map_err(CustomError::Sqlite)
|
|
|
|
})
|
|
|
|
.unwrap()
|
2015-09-21 09:28:50 +08:00
|
|
|
.collect();
|
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match bad_idx.unwrap_err() {
|
|
|
|
CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
|
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
|
2015-12-11 05:48:09 +08:00
|
|
|
let non_sqlite_err: CustomResult<Vec<String>> = query.query_and_then(&[], |_| {
|
|
|
|
Err(CustomError::SomeError)
|
|
|
|
})
|
|
|
|
.unwrap()
|
2015-09-21 09:28:50 +08:00
|
|
|
.collect();
|
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match non_sqlite_err.unwrap_err() {
|
|
|
|
CustomError::SomeError => (),
|
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
}
|
|
|
|
|
2015-09-21 09:30:40 +08:00
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-09-21 09:30:40 +08:00
|
|
|
fn test_query_row_and_then_custom_error() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
let query = "SELECT x, y FROM foo ORDER BY x DESC";
|
2015-12-11 05:48:09 +08:00
|
|
|
let results: CustomResult<String> = db.query_row_and_then(query, &[], |row| {
|
|
|
|
row.get_checked(1).map_err(CustomError::Sqlite)
|
|
|
|
});
|
2015-09-21 09:30:40 +08:00
|
|
|
|
|
|
|
assert_eq!(results.unwrap(), "hello");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2015-12-11 05:48:09 +08:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-09-21 09:30:40 +08:00
|
|
|
fn test_query_row_and_then_custom_error_fails() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
let query = "SELECT x, y FROM foo ORDER BY x DESC";
|
2015-12-11 05:48:09 +08:00
|
|
|
let bad_type: CustomResult<f64> = db.query_row_and_then(query, &[], |row| {
|
|
|
|
row.get_checked(1).map_err(CustomError::Sqlite)
|
|
|
|
});
|
2015-09-21 09:30:40 +08:00
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match bad_type.unwrap_err() {
|
2016-05-27 03:03:05 +08:00
|
|
|
CustomError::Sqlite(Error::InvalidColumnType(_, _)) => (),
|
2015-12-13 13:54:08 +08:00
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:30:40 +08:00
|
|
|
|
2015-12-11 05:48:09 +08:00
|
|
|
let bad_idx: CustomResult<String> = db.query_row_and_then(query, &[], |row| {
|
|
|
|
row.get_checked(3).map_err(CustomError::Sqlite)
|
|
|
|
});
|
2015-09-21 09:30:40 +08:00
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match bad_idx.unwrap_err() {
|
|
|
|
CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
|
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:30:40 +08:00
|
|
|
|
2015-12-11 05:48:09 +08:00
|
|
|
let non_sqlite_err: CustomResult<String> = db.query_row_and_then(query, &[], |_| {
|
|
|
|
Err(CustomError::SomeError)
|
|
|
|
});
|
2015-09-21 09:30:40 +08:00
|
|
|
|
2015-12-13 13:54:08 +08:00
|
|
|
match non_sqlite_err.unwrap_err() {
|
|
|
|
CustomError::SomeError => (),
|
|
|
|
err => panic!("Unexpected error {}", err),
|
|
|
|
}
|
2015-09-21 09:30:40 +08:00
|
|
|
}
|
|
|
|
|
2016-01-02 17:28:00 +08:00
|
|
|
#[test]
|
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
|
|
|
fn test_dynamic() {
|
|
|
|
let db = checked_memory_handle();
|
|
|
|
let sql = "BEGIN;
|
|
|
|
CREATE TABLE foo(x INTEGER, y TEXT);
|
|
|
|
INSERT INTO foo VALUES(4, \"hello\");
|
|
|
|
END;";
|
|
|
|
db.execute_batch(sql).unwrap();
|
|
|
|
|
|
|
|
db.query_row("SELECT * FROM foo", &[], |r| assert_eq!(2, r.column_count())).unwrap();
|
|
|
|
}
|
2015-09-21 09:28:50 +08:00
|
|
|
}
|
2014-10-20 07:56:41 +08:00
|
|
|
}
|