This commit is contained in:
gwenn 2018-08-16 18:29:46 +02:00
parent 33271764b1
commit 5e9c7bac4e
25 changed files with 527 additions and 385 deletions

View File

@ -18,8 +18,11 @@
//! # use std::path::Path;
//! # use std::time;
//!
//! fn backup_db<P: AsRef<Path>>(src: &Connection, dst: P, progress: fn(backup::Progress))
//! -> Result<()> {
//! fn backup_db<P: AsRef<Path>>(
//! src: &Connection,
//! dst: P,
//! progress: fn(backup::Progress),
//! ) -> Result<()> {
//! let mut dst = try!(Connection::open(dst));
//! let backup = try!(backup::Backup::new(src, &mut dst));
//! backup.run_to_completion(5, time::Duration::from_millis(250), Some(progress))
@ -136,7 +139,8 @@ pub enum StepResult {
/// The backup is complete.
Done,
/// The step was successful but there are still more pages that need to be backed up.
/// The step was successful but there are still more pages that need to be
/// backed up.
More,
/// The step failed because appropriate locks could not be aquired. This is

View File

@ -1,14 +1,15 @@
//! Incremental BLOB I/O.
//!
//! Note that SQLite does not provide API-level access to change the size of a BLOB; that must
//! be performed through SQL statements.
//! Note that SQLite does not provide API-level access to change the size of a
//! BLOB; that must be performed through SQL statements.
//!
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`, so it plays
//! nicely with other types that build on these (such as `std::io::BufReader` and
//! `std::io::BufWriter`). However, you must be careful with the size of the blob. For example,
//! when using a `BufWriter`, the `BufWriter` will accept more data than the `Blob` will allow,
//! so make sure to call `flush` and check for errors. (See the unit tests in this module for
//! an example.)
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`,
//! so it plays nicely with other types that build on these (such as
//! `std::io::BufReader` and `std::io::BufWriter`). However, you must be
//! careful with the size of the blob. For example, when using a `BufWriter`,
//! the `BufWriter` will accept more data than the `Blob`
//! will allow, so make sure to call `flush` and check for errors. (See the
//! unit tests in this module for an example.)
//!
//! ## Example
//!
@ -16,17 +17,21 @@
//! extern crate libsqlite3_sys;
//! extern crate rusqlite;
//!
//! use rusqlite::{Connection, DatabaseName};
//! use rusqlite::blob::ZeroBlob;
//! use std::io::{Read, Write, Seek, SeekFrom};
//! use rusqlite::{Connection, DatabaseName};
//! use std::io::{Read, Seek, SeekFrom, Write};
//!
//! fn main() {
//! let db = Connection::open_in_memory().unwrap();
//! db.execute_batch("CREATE TABLE test (content BLOB);").unwrap();
//! db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[]).unwrap();
//! db.execute_batch("CREATE TABLE test (content BLOB);")
//! .unwrap();
//! db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[])
//! .unwrap();
//!
//! let rowid = db.last_insert_rowid();
//! let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
//! let mut blob = db
//! .blob_open(DatabaseName::Main, "test", "content", rowid, false)
//! .unwrap();
//!
//! // Make sure to test that the number of bytes written matches what you expect;
//! // if you try to write too much, the data will be truncated to the size of the BLOB.
@ -39,7 +44,8 @@
//! let bytes_read = blob.read(&mut buf[..]).unwrap();
//! assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//!
//! db.execute("INSERT INTO test (content) VALUES (?)", &[&ZeroBlob(64)]).unwrap();
//! db.execute("INSERT INTO test (content) VALUES (?)", &[&ZeroBlob(64)])
//! .unwrap();
//!
//! // given a new row ID, we can reopen the blob on that row
//! let rowid = db.last_insert_rowid();
@ -64,12 +70,14 @@ pub struct Blob<'conn> {
}
impl Connection {
/// Open a handle to the BLOB located in `row_id`, `column`, `table` in database `db`.
/// Open a handle to the BLOB located in `row_id`, `column`, `table` in
/// database `db`.
///
/// # Failure
///
/// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string
/// or if the underlying SQLite BLOB open call fails.
/// Will return `Err` if `db`/`table`/`column` cannot be converted to a
/// C-compatible string or if the underlying SQLite BLOB open call
/// fails.
pub fn blob_open<'a>(
&'a self,
db: DatabaseName,
@ -124,8 +132,9 @@ impl<'conn> Blob<'conn> {
/// Close a BLOB handle.
///
/// Calling `close` explicitly is not required (the BLOB will be closed when the
/// `Blob` is dropped), but it is available so you can get any errors that occur.
/// Calling `close` explicitly is not required (the BLOB will be closed
/// when the `Blob` is dropped), but it is available so you can get any
/// errors that occur.
///
/// # Failure
///
@ -142,8 +151,8 @@ impl<'conn> Blob<'conn> {
}
impl<'conn> io::Read for Blob<'conn> {
/// Read data from a BLOB incrementally. Will return Ok(0) if the end of the blob
/// has been reached.
/// Read data from a BLOB incrementally. Will return Ok(0) if the end of
/// the blob has been reached.
///
/// # Failure
///
@ -165,12 +174,13 @@ impl<'conn> io::Read for Blob<'conn> {
}
impl<'conn> io::Write for Blob<'conn> {
/// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of the blob
/// has been reached; consider using `Write::write_all(buf)` if you want to get an
/// error if the entirety of the buffer cannot be written.
/// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of
/// the blob has been reached; consider using `Write::write_all(buf)`
/// if you want to get an error if the entirety of the buffer cannot be
/// written.
///
/// This function may only modify the contents of the BLOB; it is not possible to increase
/// the size of a BLOB using this API.
/// This function may only modify the contents of the BLOB; it is not
/// possible to increase the size of a BLOB using this API.
///
/// # Failure
///
@ -230,8 +240,8 @@ impl<'conn> Drop for Blob<'conn> {
/// BLOB of length N that is filled with zeroes.
///
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using
/// incremental BLOB I/O routines.
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is
/// later written using incremental BLOB I/O routines.
///
/// A negative value for the zeroblob results in a zero-length BLOB.
#[derive(Copy, Clone)]

View File

@ -8,13 +8,17 @@ use ffi;
use {Connection, InnerConnection, Result};
impl Connection {
/// Set a busy handler that sleeps for a specified amount of time when a table is locked.
/// The handler will sleep multiple times until at least "ms" milliseconds of sleeping have accumulated.
/// Set a busy handler that sleeps for a specified amount of time when a
/// table is locked. The handler will sleep multiple times until at
/// least "ms" milliseconds of sleeping have accumulated.
///
/// Calling this routine with an argument equal to zero turns off all busy handlers.
/// Calling this routine with an argument equal to zero turns off all busy
/// handlers.
//
/// There can only be a single busy handler for a particular database connection at any given moment.
/// If another busy handler was defined (using `busy_handler`) prior to calling this routine, that other busy handler is cleared.
/// There can only be a single busy handler for a particular database
/// connection at any given moment. If another busy handler was defined
/// (using `busy_handler`) prior to calling this routine, that other
/// busy handler is cleared.
pub fn busy_timeout(&self, timeout: Duration) -> Result<()> {
let ms = timeout
.as_secs()
@ -26,14 +30,21 @@ impl Connection {
/// Register a callback to handle `SQLITE_BUSY` errors.
///
/// If the busy callback is `None`, then `SQLITE_BUSY is returned immediately upon encountering the lock.`
/// The argument to the busy handler callback is the number of times that the busy handler has been invoked previously for the same locking event.
/// If the busy callback returns `false`, then no additional attempts are made to access the database and `SQLITE_BUSY` is returned to the application.
/// If the callback returns `true`, then another attempt is made to access the database and the cycle repeats.
/// If the busy callback is `None`, then `SQLITE_BUSY is returned
/// immediately upon encountering the lock.` The argument to the busy
/// handler callback is the number of times that the
/// busy handler has been invoked previously for the
/// same locking event. If the busy callback returns `false`, then no
/// additional attempts are made to access the
/// database and `SQLITE_BUSY` is returned to the
/// application. If the callback returns `true`, then another attempt
/// is made to access the database and the cycle repeats.
///
/// There can only be a single busy handler defined for each database connection.
/// Setting a new busy handler clears any previously set handler.
/// Note that calling `busy_timeout()` or evaluating `PRAGMA busy_timeout=N` will change the busy handler and thus clear any previously set busy handler.
/// There can only be a single busy handler defined for each database
/// connection. Setting a new busy handler clears any previously set
/// handler. Note that calling `busy_timeout()` or evaluating `PRAGMA
/// busy_timeout=N` will change the busy handler and thus
/// clear any previously set busy handler.
pub fn busy_handler(&self, callback: Option<fn(i32) -> bool>) -> Result<()> {
unsafe extern "C" fn busy_handler_callback(p_arg: *mut c_void, count: c_int) -> c_int {
let handler_fn: fn(i32) -> bool = mem::transmute(p_arg);

View File

@ -7,10 +7,10 @@ use std::ops::{Deref, DerefMut};
use {Connection, Result, Statement};
impl Connection {
/// Prepare a SQL statement for execution, returning a previously prepared (but
/// not currently in-use) statement if one is available. The returned statement
/// will be cached for reuse by future calls to `prepare_cached` once it is
/// dropped.
/// Prepare a SQL statement for execution, returning a previously prepared
/// (but not currently in-use) statement if one is available. The
/// returned statement will be cached for reuse by future calls to
/// `prepare_cached` once it is dropped.
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result};
@ -31,16 +31,17 @@ impl Connection {
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
self.cache.get(self, sql)
}
/// Set the maximum number of cached prepared statements this connection will hold.
/// By default, a connection will hold a relatively small number of cached statements.
/// If you need more, or know that you will not use cached statements, you can set
/// the capacity manually using this method.
/// Set the maximum number of cached prepared statements this connection
/// will hold. By default, a connection will hold a relatively small
/// number of cached statements. If you need more, or know that you
/// will not use cached statements, you
/// can set the capacity manually using this method.
pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
self.cache.set_capacity(capacity)
}
@ -95,8 +96,8 @@ impl<'conn> CachedStatement<'conn> {
}
}
/// Discard the statement, preventing it from being returned to its `Connection`'s collection
/// of cached statements.
/// Discard the statement, preventing it from being returned to its
/// `Connection`'s collection of cached statements.
pub fn discard(mut self) {
self.stmt = None;
}
@ -117,8 +118,8 @@ impl StatementCache {
//
// # Failure
//
// Will return `Err` if no cached statement can be found and the underlying SQLite prepare
// call fails.
// Will return `Err` if no cached statement can be found and the underlying
// SQLite prepare call fails.
fn get<'conn>(
&'conn self,
conn: &'conn Connection,

View File

@ -17,26 +17,29 @@ pub enum Error {
/// An error from an underlying SQLite call.
SqliteFailure(ffi::Error, Option<String>),
/// Error reported when attempting to open a connection when SQLite was configured to
/// allow single-threaded use only.
/// Error reported when attempting to open a connection when SQLite was
/// configured to allow single-threaded use only.
SqliteSingleThreadedMode,
/// Error when the value of a particular column is requested, but it cannot be converted to
/// the requested Rust type.
/// Error when the value of a particular column is requested, but it cannot
/// be converted to the requested Rust type.
FromSqlConversionFailure(usize, Type, Box<error::Error + Send + Sync>),
/// Error when SQLite gives us an integral value outside the range of the requested type (e.g.,
/// trying to get the value 1000 into a `u8`). The associated `usize` is the column index, and
/// the associated `i64` is the value returned by SQLite.
/// Error when SQLite gives us an integral value outside the range of the
/// requested type (e.g., trying to get the value 1000 into a `u8`).
/// The associated `usize` is the column index,
/// and the associated `i64` is the value returned by SQLite.
IntegralValueOutOfRange(usize, i64),
/// Error converting a string to UTF-8.
Utf8Error(str::Utf8Error),
/// Error converting a string to a C-compatible string because it contained an embedded nul.
/// Error converting a string to a C-compatible string because it contained
/// an embedded nul.
NulError(::std::ffi::NulError),
/// Error when using SQL named parameters and passing a parameter name not present in the SQL.
/// Error when using SQL named parameters and passing a parameter name not
/// present in the SQL.
InvalidParameterName(String),
/// Error converting a file path to a string.
@ -45,31 +48,33 @@ pub enum Error {
/// Error returned when an `execute` call returns rows.
ExecuteReturnedResults,
/// Error when a query that was expected to return at least one row (e.g., for `query_row`)
/// did not return any.
/// Error when a query that was expected to return at least one row (e.g.,
/// for `query_row`) did not return any.
QueryReturnedNoRows,
/// Error when the value of a particular column is requested, but the index is out of range
/// for the statement.
/// Error when the value of a particular column is requested, but the index
/// is out of range for the statement.
InvalidColumnIndex(usize),
/// Error when the value of a named column is requested, but no column matches the name
/// for the statement.
/// Error when the value of a named column is requested, but no column
/// matches the name for the statement.
InvalidColumnName(String),
/// Error when the value of a particular column is requested, but the type of the result in
/// that column cannot be converted to the requested Rust type.
/// Error when the value of a particular column is requested, but the type
/// of the result in that column cannot be converted to the requested
/// Rust type.
InvalidColumnType(usize, Type),
/// Error when a query that was expected to insert one row did not insert any or insert many.
/// Error when a query that was expected to insert one row did not insert
/// any or insert many.
StatementChangedRows(usize),
/// Error returned by `functions::Context::get` when the function argument cannot be converted
/// to the requested type.
/// Error returned by `functions::Context::get` when the function argument
/// cannot be converted to the requested type.
#[cfg(feature = "functions")]
InvalidFunctionParameterType(usize, Type),
/// Error returned by `vtab::Values::get` when the filter argument cannot be converted
/// to the requested type.
/// Error returned by `vtab::Values::get` when the filter argument cannot
/// be converted to the requested type.
#[cfg(feature = "vtab")]
InvalidFilterParameterType(usize, Type),

View File

@ -2,19 +2,20 @@
//!
//! # Example
//!
//! Adding a `regexp` function to a connection in which compiled regular expressions
//! are cached in a `HashMap`. For an alternative implementation that uses SQLite's
//! [Function Auxilliary Data](https://www.sqlite.org/c3ref/get_auxdata.html) interface
//! to avoid recompiling regular expressions, see the unit tests for this module.
//! Adding a `regexp` function to a connection in which compiled regular
//! expressions are cached in a `HashMap`. For an alternative implementation
//! that uses SQLite's [Function Auxilliary Data](https://www.sqlite.org/c3ref/get_auxdata.html) interface
//! to avoid recompiling regular expressions, see the unit tests for this
//! module.
//!
//! ```rust
//! extern crate libsqlite3_sys;
//! extern crate rusqlite;
//! extern crate regex;
//!
//! use regex::Regex;
//! use rusqlite::{Connection, Error, Result};
//! use std::collections::HashMap;
//! use regex::Regex;
//!
//! fn add_regexp_function(db: &Connection) -> Result<()> {
//! let mut cached_regexes = HashMap::new();
@ -25,12 +26,10 @@
//! use std::collections::hash_map::Entry::{Occupied, Vacant};
//! match entry {
//! Occupied(occ) => occ.into_mut(),
//! Vacant(vac) => {
//! match Regex::new(&regex_s) {
//! Ok(r) => vac.insert(r),
//! Err(err) => return Err(Error::UserFunctionError(Box::new(err))),
//! }
//! }
//! Vacant(vac) => match Regex::new(&regex_s) {
//! Ok(r) => vac.insert(r),
//! Err(err) => return Err(Error::UserFunctionError(Box::new(err))),
//! },
//! }
//! };
//!
@ -43,8 +42,10 @@
//! let db = Connection::open_in_memory().unwrap();
//! add_regexp_function(&db).unwrap();
//!
//! let is_match: bool = db.query_row("SELECT regexp('[aeiou]*', 'aaaaeeeiii')", &[],
//! |row| row.get(0)).unwrap();
//! let is_match: bool = db
//! .query_row("SELECT regexp('[aeiou]*', 'aaaaeeeiii')", &[], |row| {
//! row.get(0)
//! }).unwrap();
//!
//! assert!(is_match);
//! }
@ -64,10 +65,10 @@ use types::{FromSql, FromSqlError, ToSql, ValueRef};
use {str_to_cstring, Connection, Error, InnerConnection, Result};
unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) {
// Extended constraint error codes were added in SQLite 3.7.16. We don't have an explicit
// feature check for that, and this doesn't really warrant one. We'll use the extended code
// if we're on the bundled version (since it's at least 3.17.0) and the normal constraint
// error code if not.
// Extended constraint error codes were added in SQLite 3.7.16. We don't have
// an explicit feature check for that, and this doesn't really warrant one.
// We'll use the extended code if we're on the bundled version (since it's
// at least 3.17.0) and the normal constraint error code if not.
#[cfg(feature = "bundled")]
fn constraint_error_code() -> i32 {
ffi::SQLITE_CONSTRAINT_FUNCTION
@ -108,6 +109,7 @@ impl<'a> Context<'a> {
pub fn len(&self) -> usize {
self.args.len()
}
/// Returns `true` when there is no argument.
pub fn is_empty(&self) -> bool {
self.args.is_empty()
@ -119,7 +121,8 @@ impl<'a> Context<'a> {
///
/// Will panic if `idx` is greater than or equal to `self.len()`.
///
/// Will return Err if the underlying SQLite type cannot be converted to a `T`.
/// Will return Err if the underlying SQLite type cannot be converted to a
/// `T`.
pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
let arg = self.args[idx];
let value = unsafe { ValueRef::from_value(arg) };
@ -169,26 +172,26 @@ impl<'a> Context<'a> {
/// Aggregate is the callback interface for user-defined aggregate function.
///
/// `A` is the type of the aggregation context and `T` is the type of the final result.
/// Implementations should be stateless.
/// `A` is the type of the aggregation context and `T` is the type of the final
/// result. Implementations should be stateless.
pub trait Aggregate<A, T>
where
T: ToSql,
{
/// Initializes the aggregation context. Will be called prior to the first call
/// to `step()` to set up the context for an invocation of the function. (Note:
/// `init()` will not be called if there are no rows.)
/// Initializes the aggregation context. Will be called prior to the first
/// call to `step()` to set up the context for an invocation of the
/// function. (Note: `init()` will not be called if there are no rows.)
fn init(&self) -> A;
/// "step" function called once for each row in an aggregate group. May be called
/// 0 times if there are no rows.
/// "step" function called once for each row in an aggregate group. May be
/// called 0 times if there are no rows.
fn step(&self, &mut Context, &mut A) -> Result<()>;
/// Computes and returns the final result. Will be called exactly once for each
/// invocation of the function. If `step()` was called at least once, will be given
/// `Some(A)` (the same `A` as was created by `init` and given to `step`); if `step()`
/// was not called (because the function is running against 0 rows), will be given
/// `None`.
/// Computes and returns the final result. Will be called exactly once for
/// each invocation of the function. If `step()` was called at least
/// once, will be given `Some(A)` (the same `A` as was created by
/// `init` and given to `step`); if `step()` was not called (because
/// the function is running against 0 rows), will be given `None`.
fn finalize(&self, Option<A>) -> Result<T>;
}
@ -196,9 +199,9 @@ impl Connection {
/// Attach a user-defined scalar function to this database connection.
///
/// `fn_name` is the name the function will be accessible from SQL.
/// `n_arg` is the number of arguments to the function. Use `-1` for a variable
/// number. If the function always returns the same value given the same
/// input, `deterministic` should be `true`.
/// `n_arg` is the number of arguments to the function. Use `-1` for a
/// variable number. If the function always returns the same value
/// given the same input, `deterministic` should be `true`.
///
/// The function will remain available until the connection is closed or
/// until it is explicitly removed via `remove_function`.

View File

@ -91,7 +91,8 @@ impl From<i32> for Action {
}
impl Connection {
/// Register a callback function to be invoked whenever a transaction is committed.
/// Register a callback function to be invoked whenever a transaction is
/// committed.
///
/// The callback returns `true` to rollback.
pub fn commit_hook<F>(&self, hook: Option<F>)
@ -101,7 +102,8 @@ impl Connection {
self.db.borrow_mut().commit_hook(hook);
}
/// Register a callback function to be invoked whenever a transaction is committed.
/// Register a callback function to be invoked whenever a transaction is
/// committed.
///
/// The callback returns `true` to rollback.
pub fn rollback_hook<F>(&self, hook: Option<F>)
@ -116,10 +118,11 @@ impl Connection {
///
/// The callback parameters are:
///
/// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE),
/// - the name of the database ("main", "temp", ...),
/// - the name of the table that is updated,
/// - the ROWID of the row that is updated.
/// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or
/// SQLITE_DELETE),
/// - the name of the database ("main", "temp", ...),
/// - the name of the table that is updated,
/// - the ROWID of the row that is updated.
pub fn update_hook<F>(&self, hook: Option<F>)
where
F: FnMut(Action, &str, &str, i64) + Send + 'static,
@ -151,8 +154,9 @@ impl InnerConnection {
}
}
// unlike `sqlite3_create_function_v2`, we cannot specify a `xDestroy` with `sqlite3_commit_hook`.
// so we keep the `xDestroy` function in `InnerConnection.free_boxed_hook`.
// unlike `sqlite3_create_function_v2`, we cannot specify a `xDestroy` with
// `sqlite3_commit_hook`. so we keep the `xDestroy` function in
// `InnerConnection.free_boxed_hook`.
let free_commit_hook = if hook.is_some() {
Some(free_boxed_hook::<F> as fn(*mut c_void))
} else {

View File

@ -1,49 +1,55 @@
//! Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
//! an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres).
//! Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to
//! expose an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres).
//!
//! ```rust
//! extern crate rusqlite;
//! extern crate time;
//!
//! use time::Timespec;
//! use rusqlite::Connection;
//! use time::Timespec;
//!
//! #[derive(Debug)]
//! struct Person {
//! id: i32,
//! name: String,
//! time_created: Timespec,
//! data: Option<Vec<u8>>
//! data: Option<Vec<u8>>,
//! }
//!
//! fn main() {
//! let conn = Connection::open_in_memory().unwrap();
//!
//! conn.execute("CREATE TABLE person (
//! conn.execute(
//! "CREATE TABLE person (
//! id INTEGER PRIMARY KEY,
//! name TEXT NOT NULL,
//! time_created TEXT NOT NULL,
//! data BLOB
//! )", &[]).unwrap();
//! )",
//! &[],
//! ).unwrap();
//! let me = Person {
//! id: 0,
//! name: "Steven".to_string(),
//! time_created: time::get_time(),
//! data: None
//! data: None,
//! };
//! conn.execute("INSERT INTO person (name, time_created, data)
//! conn.execute(
//! "INSERT INTO person (name, time_created, data)
//! VALUES (?1, ?2, ?3)",
//! &[&me.name, &me.time_created, &me.data]).unwrap();
//! &[&me.name, &me.time_created, &me.data],
//! ).unwrap();
//!
//! let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap();
//! let person_iter = stmt.query_map(&[], |row| {
//! Person {
//! let mut stmt = conn
//! .prepare("SELECT id, name, time_created, data FROM person")
//! .unwrap();
//! let person_iter = stmt
//! .query_map(&[], |row| Person {
//! id: row.get(0),
//! name: row.get(1),
//! time_created: row.get(2),
//! data: row.get(3)
//! }
//! }).unwrap();
//! data: row.get(3),
//! }).unwrap();
//!
//! for person in person_iter {
//! println!("Found person {:?}", person.unwrap());
@ -168,8 +174,8 @@ pub enum DatabaseName<'a> {
Attached(&'a str),
}
// Currently DatabaseName is only used by the backup and blob mods, so hide this (private)
// impl to avoid dead code warnings.
// Currently DatabaseName is only used by the backup and blob mods, so hide
// this (private) impl to avoid dead code warnings.
#[cfg(any(feature = "backup", feature = "blob"))]
impl<'a> DatabaseName<'a> {
fn to_cstring(&self) -> Result<CString> {
@ -204,13 +210,15 @@ impl Drop for Connection {
impl Connection {
/// Open a new connection to a SQLite database.
///
/// `Connection::open(path)` is equivalent to `Connection::open_with_flags(path,
/// OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE)`.
/// `Connection::open(path)` is equivalent to
/// `Connection::open_with_flags(path,
/// OpenFlags::SQLITE_OPEN_READ_WRITE |
/// OpenFlags::SQLITE_OPEN_CREATE)`.
///
/// # Failure
///
/// Will return `Err` if `path` cannot be converted to a C-compatible string or if the
/// underlying SQLite open call fails.
/// Will return `Err` if `path` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails.
pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
let flags = OpenFlags::default();
Connection::open_with_flags(path, flags)
@ -233,8 +241,8 @@ impl Connection {
///
/// # Failure
///
/// Will return `Err` if `path` cannot be converted to a C-compatible string or if the
/// underlying SQLite open call fails.
/// Will return `Err` if `path` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails.
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 {
@ -261,7 +269,8 @@ impl Connection {
})
}
/// Convenience method to run multiple SQL statements (that cannot take any parameters).
/// 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.
///
@ -270,25 +279,27 @@ impl Connection {
/// ```rust,no_run
/// # use rusqlite::{Connection, Result};
/// fn create_tables(conn: &Connection) -> Result<()> {
/// conn.execute_batch("BEGIN;
/// conn.execute_batch(
/// "BEGIN;
/// CREATE TABLE foo(x INTEGER);
/// CREATE TABLE bar(y TEXT);
/// COMMIT;")
/// COMMIT;",
/// )
/// }
/// ```
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn execute_batch(&self, sql: &str) -> Result<()> {
self.db.borrow_mut().execute_batch(sql)
}
/// 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`).
/// On success, returns the number of rows that were changed or inserted or
/// deleted (via `sqlite3_changes`).
///
/// ## Example
///
@ -304,30 +315,34 @@ impl Connection {
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn execute(&self, sql: &str, params: &[&ToSql]) -> Result<usize> {
self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
}
/// Convenience method to prepare and execute a single SQL statement with named parameter(s).
/// Convenience method to prepare and execute a single SQL statement with
/// named parameter(s).
///
/// On success, returns the number of rows that were changed or inserted or deleted (via
/// `sqlite3_changes`).
/// On success, returns the number of rows that were changed or inserted or
/// deleted (via `sqlite3_changes`).
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result};
/// fn insert(conn: &Connection) -> Result<usize> {
/// conn.execute_named("INSERT INTO test (name) VALUES (:name)", &[(":name", &"one")])
/// conn.execute_named(
/// "INSERT INTO test (name) VALUES (:name)",
/// &[(":name", &"one")],
/// )
/// }
/// ```
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> Result<usize> {
self.prepare(sql)
.and_then(|mut stmt| stmt.execute_named(params))
@ -341,25 +356,29 @@ impl Connection {
self.db.borrow_mut().last_insert_rowid()
}
/// 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.
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{Result,Connection};
/// fn preferred_locale(conn: &Connection) -> Result<String> {
/// conn.query_row("SELECT value FROM preferences WHERE name='locale'", &[], |row| {
/// row.get(0)
/// })
/// conn.query_row(
/// "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.
/// If the query returns more than one row, all rows except the first are
/// ignored.
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
where
F: FnOnce(&Row) -> T,
@ -368,15 +387,16 @@ impl Connection {
stmt.query_row(params, f)
}
/// Convenience method to execute a query with named parameter(s) that is expected to return
/// a single row.
/// Convenience method to execute a query with named parameter(s) that is
/// expected to return a single row.
///
/// If the query returns more than one row, all rows except the first are ignored.
/// If the query returns more than one row, all rows except the first are
/// ignored.
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &ToSql)], f: F) -> Result<T>
where
F: FnOnce(&Row) -> T,
@ -387,29 +407,31 @@ impl Connection {
rows.get_expected_row().map(|r| f(&r))
}
/// 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.
/// The `Result` type of `f` must implement `std::convert::From<Error>`.
/// 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. The `Result` type of `f` must implement
/// `std::convert::From<Error>`.
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{Result,Connection};
/// fn preferred_locale(conn: &Connection) -> Result<String> {
/// conn.query_row_and_then("SELECT value FROM preferences WHERE name='locale'",
/// &[],
/// |row| {
/// row.get_checked(0)
/// })
/// conn.query_row_and_then(
/// "SELECT value FROM preferences WHERE name='locale'",
/// &[],
/// |row| row.get_checked(0),
/// )
/// }
/// ```
///
/// If the query returns more than one row, all rows except the first are ignored.
/// If the query returns more than one row, all rows except the first are
/// ignored.
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn query_row_and_then<T, E, F>(
&self,
sql: &str,
@ -426,25 +448,29 @@ impl Connection {
rows.get_expected_row().map_err(E::from).and_then(|r| f(&r))
}
/// 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.
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{Result,Connection};
/// fn preferred_locale(conn: &Connection) -> Result<String> {
/// conn.query_row_safe("SELECT value FROM preferences WHERE name='locale'", &[], |row| {
/// row.get(0)
/// })
/// 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.
/// If the query returns more than one row, all rows except the first are
/// ignored.
///
/// ## Deprecated
///
/// This method should be considered deprecated. Use `query_row` instead, which now
/// does exactly the same thing.
/// This method should be considered deprecated. Use `query_row` instead,
/// which now does exactly the same thing.
#[deprecated(since = "0.1.0", note = "Use query_row instead")]
pub fn query_row_safe<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
where
@ -469,17 +495,17 @@ impl Connection {
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails.
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>> {
self.db.borrow_mut().prepare(self, sql)
}
/// Close the SQLite connection.
///
/// This is functionally equivalent to the `Drop` implementation for `Connection` except
/// that on failure, it returns an error and the connection itself (presumably so closing
/// can be attempted again).
/// This is functionally equivalent to the `Drop` implementation for
/// `Connection` except that on failure, it returns an error and the
/// connection itself (presumably so closing can be attempted again).
///
/// # Failure
///
@ -490,8 +516,8 @@ impl Connection {
r.map_err(move |err| (self, err))
}
/// Enable loading of SQLite extensions. Strongly consider using `LoadExtensionGuard`
/// instead of this function.
/// Enable loading of SQLite extensions. Strongly consider using
/// `LoadExtensionGuard` instead of this function.
///
/// ## Example
///
@ -525,12 +551,13 @@ impl Connection {
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.
/// 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`.
/// 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`.
///
/// ## Example
///
@ -562,10 +589,11 @@ impl Connection {
///
/// # 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`.
/// 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::sqlite3 {
self.db.borrow().db()
}
@ -644,27 +672,34 @@ static SQLITE_VERSION_CHECK: Once = ONCE_INIT;
static BYPASS_SQLITE_INIT: AtomicBool = ATOMIC_BOOL_INIT;
static BYPASS_VERSION_CHECK: AtomicBool = ATOMIC_BOOL_INIT;
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or later. If you are
/// running against a SQLite older than that, rusqlite attempts to ensure safety by performing
/// configuration and initialization of SQLite itself the first time you attempt to open a
/// connection. By default, rusqlite panics if that initialization fails, since that could mean
/// SQLite has been initialized in single-thread mode.
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or
/// later. If you are running against a SQLite older than that, rusqlite
/// attempts to ensure safety by performing configuration and initialization of
/// SQLite itself the first time you
/// attempt to open a connection. By default, rusqlite panics if that
/// initialization fails, since that could mean SQLite has been initialized in
/// single-thread mode.
///
/// If you are encountering that panic _and_ can ensure that SQLite has been initialized in either
/// multi-thread or serialized mode, call this function prior to attempting to open a connection
/// and rusqlite's initialization process will by skipped. This function is unsafe because if you
/// call it and SQLite has actually been configured to run in single-thread mode, you may enounter
/// memory errors or data corruption or any number of terrible things that should not be possible
/// when you're using Rust.
/// If you are encountering that panic _and_ can ensure that SQLite has been
/// initialized in either multi-thread or serialized mode, call this function
/// prior to attempting to open a connection and rusqlite's initialization
/// process will by skipped. This
/// function is unsafe because if you call it and SQLite has actually been
/// configured to run in single-thread mode,
/// you may enounter memory errors or data corruption or any number of terrible
/// things that should not be possible when you're using Rust.
pub unsafe fn bypass_sqlite_initialization() {
BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
}
/// rusqlite performs a one-time check that the runtime SQLite version is at least as new as
/// the version of SQLite found when rusqlite was built. Bypassing this check may be dangerous;
/// e.g., if you use features of SQLite that are not present in the runtime version. If you are
/// sure the runtime version is compatible with the build-time version for your usage, you can
/// bypass the version check by calling this function before your first connection attempt.
/// rusqlite performs a one-time check that the runtime SQLite version is at
/// least as new as the version of SQLite found when rusqlite was built.
/// Bypassing this check may be dangerous; e.g., if you use features of SQLite
/// that are not present in the runtime
/// version. If you are sure the runtime version is compatible with the
/// build-time version for your usage, you can bypass the version check by
/// calling this function before
/// your first connection attempt.
pub unsafe fn bypass_sqlite_version_check() {
BYPASS_VERSION_CHECK.store(true, Ordering::Relaxed);
}
@ -693,8 +728,8 @@ fn ensure_valid_sqlite_version() {
return;
}
// Check that the runtime version number is compatible with the version number we found at
// build-time.
// Check that the runtime version number is compatible with the version number
// we found at build-time.
if version_number < ffi::SQLITE_VERSION_NUMBER {
panic!(
"\
@ -716,21 +751,23 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> {
return Err(Error::SqliteSingleThreadedMode);
}
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode, but it's
// possible someone configured it to be in Single-thread mode before calling into us. That
// would mean we're exposing an unsafe API via a safe one (in Rust terminology), which is
// no good. We have two options to protect against this, depending on the version of SQLite
// we're linked with:
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode,
// but it's possible someone configured it to be in Single-thread mode
// before calling into us. That would mean we're exposing an unsafe API via
// a safe one (in Rust terminology), which is no good. We have two options
// to protect against this, depending on the version of SQLite we're linked
// with:
//
// 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for the magic value
// 8. This isn't documented, but it's what SQLite returns for its mutex allocation function
// in Single-thread mode.
// 2. If we're prior to SQLite 3.7.0, AFAIK there's no way to check the threading mode. The
// check we perform for >= 3.7.0 will segfault. Instead, we insist on being able to call
// sqlite3_config and sqlite3_initialize ourself, ensuring we know the threading mode. This
// will fail if someone else has already initialized SQLite even if they initialized it
// safely. That's not ideal either, which is why we expose bypass_sqlite_initialization
// above.
// 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for
// the magic value 8. This isn't documented, but it's what SQLite
// returns for its mutex allocation function in Single-thread mode.
// 2. If we're prior to SQLite 3.7.0, AFAIK there's no way to check the
// threading mode. The check we perform for >= 3.7.0 will segfault.
// Instead, we insist on being able to call sqlite3_config and
// sqlite3_initialize ourself, ensuring we know the threading
// mode. This will fail if someone else has already initialized SQLite
// even if they initialized it safely. That's not ideal either, which is
// why we expose bypass_sqlite_initialization above.
if version_number() >= 3_007_000 {
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
let is_singlethreaded = unsafe {
@ -775,6 +812,7 @@ impl InnerConnection {
fn new(db: *mut ffi::sqlite3) -> InnerConnection {
InnerConnection { db }
}
#[cfg(feature = "hooks")]
fn new(db: *mut ffi::sqlite3) -> InnerConnection {
InnerConnection {
@ -789,8 +827,8 @@ impl InnerConnection {
ensure_valid_sqlite_version();
ensure_safe_sqlite_threading_mode()?;
// Replicate the check for sane open flags from SQLite, because the check in SQLite itself
// wasn't added until version 3.7.3.
// Replicate the check for sane open flags from SQLite, because the check in
// SQLite itself wasn't added until version 3.7.3.
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_ONLY.bits, 0x02);
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits, 0x04);
debug_assert_eq!(
@ -1105,8 +1143,9 @@ mod 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.
// 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 super::str_to_cstring;
use std::mem;
@ -1129,7 +1168,8 @@ mod test {
raw_stmt
};
// now that we have an open statement, trying (and retrying) to close should fail.
// 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();
@ -1439,6 +1479,7 @@ mod test {
fn description(&self) -> &str {
"my custom error"
}
fn cause(&self) -> Option<&StdError> {
match *self {
CustomError::SomeError => None,

View File

@ -22,8 +22,9 @@ pub struct LoadExtensionGuard<'conn> {
}
impl<'conn> LoadExtensionGuard<'conn> {
/// Attempt to enable loading extensions. Loading extensions will be disabled when this
/// guard goes out of scope. Cannot be meaningfully nested.
/// Attempt to enable loading extensions. Loading extensions will be
/// disabled when this guard goes out of scope. Cannot be meaningfully
/// nested.
pub fn new(conn: &Connection) -> Result<LoadExtensionGuard> {
conn.load_extension_enable()
.map(|_| LoadExtensionGuard { conn })

View File

@ -16,16 +16,17 @@ impl<'stmt> Rows<'stmt> {
}
}
/// 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.
/// 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`.
/// 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`.
#[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))] // cannot implement Iterator
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
self.stmt.and_then(|stmt| match stmt.step() {
@ -135,11 +136,15 @@ impl<'a, 'stmt> Row<'a, 'stmt> {
///
/// ## Failure
///
/// Panics if calling `row.get_checked(idx)` would return an error, including:
/// Panics if calling `row.get_checked(idx)` would return an error,
/// including:
///
/// * If the underlying SQLite column type is not a valid type as a source for `T`
/// * If the underlying SQLite integral value is outside the range representable by `T`
/// * If `idx` is outside the range of columns in the returned query
/// * If the underlying SQLite column type is not a valid type as a
/// source for `T`
/// * If the underlying SQLite integral value is
/// outside the range representable by `T`
/// * If `idx` is outside the range of columns in the
/// returned query
pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
self.get_checked(idx).unwrap()
}
@ -151,11 +156,11 @@ impl<'a, 'stmt> Row<'a, 'stmt> {
/// Returns an `Error::InvalidColumnType` if the underlying SQLite column
/// type is not a valid type as a source for `T`.
///
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid column range
/// for this row.
/// 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.
/// 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> {
let idx = try!(idx.idx(self.stmt));
let value = self.stmt.value_ref(idx);

View File

@ -33,19 +33,21 @@ impl<'conn> Statement<'conn> {
cols
}
/// Return the number of columns in the result set returned by the prepared statement.
/// Return the number of columns in the result set returned by the prepared
/// statement.
pub fn column_count(&self) -> usize {
self.stmt.column_count()
}
/// Returns the column index in the result set for a given column name.
///
/// 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.
/// 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.
///
/// # Failure
///
/// Will return an `Error::InvalidColumnName` when there is no column with the specified `name`.
/// Will return an `Error::InvalidColumnName` when there is no column with
/// the specified `name`.
pub fn column_index(&self, name: &str) -> Result<usize> {
let bytes = name.as_bytes();
let n = self.column_count();
@ -59,8 +61,8 @@ impl<'conn> Statement<'conn> {
/// Execute the prepared statement.
///
/// On success, returns the number of rows that were changed or inserted or deleted (via
/// `sqlite3_changes`).
/// On success, returns the number of rows that were changed or inserted or
/// deleted (via `sqlite3_changes`).
///
/// ## Example
///
@ -78,20 +80,22 @@ impl<'conn> Statement<'conn> {
///
/// # 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.
/// 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<usize> {
try!(self.bind_parameters(params));
self.execute_with_bound_parameters()
}
/// Execute the prepared statement with named parameter(s). If any parameters
/// that were in the prepared statement are not included in `params`, they
/// will continue to use the most-recently bound value from a previous call
/// to `execute_named`, or `NULL` if they have never been bound.
/// Execute the prepared statement with named parameter(s). If any
/// parameters that were in the prepared statement are not included in
/// `params`, they will continue to use the most-recently bound value
/// from a previous call to `execute_named`, or `NULL` if they have
/// never been bound.
///
/// On success, returns the number of rows that were changed or inserted or deleted (via
/// `sqlite3_changes`).
/// On success, returns the number of rows that were changed or inserted or
/// deleted (via `sqlite3_changes`).
///
/// ## Example
///
@ -105,8 +109,9 @@ impl<'conn> Statement<'conn> {
///
/// # 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.
/// 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_named(&mut self, params: &[(&str, &ToSql)]) -> Result<usize> {
try!(self.bind_parameters_named(params));
self.execute_with_bound_parameters()
@ -116,10 +121,11 @@ impl<'conn> Statement<'conn> {
///
/// # Note
///
/// This function is a convenience wrapper around `execute()` intended for queries that
/// insert a single item. It is possible to misuse this function in a way that it cannot
/// detect, such as by calling it on a statement which _updates_ a single item rather than
/// inserting one. Please don't do that.
/// This function is a convenience wrapper around `execute()` intended for
/// queries that insert a single item. It is possible to misuse this
/// function in a way that it cannot detect, such as by calling it on a
/// statement which _updates_ a single
/// item rather than inserting one. Please don't do that.
///
/// # Failure
///
@ -132,11 +138,12 @@ impl<'conn> Statement<'conn> {
}
}
/// Execute the prepared statement, returning a handle to the resulting rows.
/// 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.
/// implement the `Iterator` trait. Consider using `query_map` or
/// `query_and_then` instead, which do.
///
/// ## Example
///
@ -165,10 +172,11 @@ impl<'conn> Statement<'conn> {
Ok(Rows::new(self))
}
/// Execute the prepared statement with named parameter(s), returning a handle for the
/// resulting rows. If any parameters that were in the prepared statement are not included in
/// `params`, they will continue to use the most-recently bound value from a previous call to
/// `query_named`, or `NULL` if they have never been bound.
/// Execute the prepared statement with named parameter(s), returning a
/// handle for the resulting rows. If any parameters that were in the
/// prepared statement are not included in `params`, they will continue
/// to use the most-recently bound value from a previous
/// call to `query_named`, or `NULL` if they have never been bound.
///
/// ## Example
///
@ -193,8 +201,8 @@ impl<'conn> Statement<'conn> {
Ok(Rows::new(self))
}
/// Executes the prepared statement and maps a function over the resulting rows, returning
/// an iterator over the mapped function results.
/// Executes the prepared statement and maps a function over the resulting
/// rows, returning an iterator over the mapped function results.
///
/// ## Example
///
@ -224,11 +232,12 @@ impl<'conn> Statement<'conn> {
Ok(MappedRows::new(rows, f))
}
/// Execute the prepared statement with named parameter(s), returning an iterator over the
/// result of calling the mapping function over the query's rows. If any parameters that were
/// in the prepared statement are not included in `params`, they will continue to use the
/// most-recently bound value from a previous call to `query_named`, or `NULL` if they have
/// never been bound.
/// Execute the prepared statement with named parameter(s), returning an
/// iterator over the result of calling the mapping function over the
/// query's rows. If any parameters that were in the prepared statement
/// are not included in `params`, they will continue to use the
/// most-recently bound value from a previous call to `query_named`,
/// or `NULL` if they have never been bound.
///
/// ## Example
///
@ -263,8 +272,8 @@ impl<'conn> Statement<'conn> {
}
/// Executes the prepared statement and maps a function over the resulting
/// rows, where the function returns a `Result` with `Error` type implementing
/// `std::convert::From<Error>` (so errors can be unified).
/// rows, where the function returns a `Result` with `Error` type
/// implementing `std::convert::From<Error>` (so errors can be unified).
///
/// # Failure
///
@ -282,28 +291,31 @@ impl<'conn> Statement<'conn> {
Ok(AndThenRows::new(rows, f))
}
/// Execute the prepared statement with named parameter(s), returning an iterator over the
/// result of calling the mapping function over the query's rows. If any parameters that were
/// in the prepared statement are not included in `params`, they will continue to use the
/// most-recently bound value from a previous call to `query_named`, or `NULL` if they have
/// never been bound.
/// Execute the prepared statement with named parameter(s), returning an
/// iterator over the result of calling the mapping function over the
/// query's rows. If any parameters that were in the prepared statement
/// are not included in
/// `params`, they will
/// continue to use the most-recently bound value from a previous call
/// to `query_named`, or `NULL` if they have never been bound.
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result};
/// struct Person { name: String };
/// struct Person {
/// name: String,
/// };
///
/// fn name_to_person(name: String) -> Result<Person> {
/// // ... check for valid name
/// Ok(Person{ name: name })
/// Ok(Person { name: name })
/// }
///
/// fn get_names(conn: &Connection) -> Result<Vec<Person>> {
/// let mut stmt = try!(conn.prepare("SELECT name FROM people WHERE id = :id"));
/// let rows = try!(stmt.query_and_then_named(&[(":id", &"one")], |row| {
/// name_to_person(row.get(0))
/// }));
/// let rows =
/// try!(stmt.query_and_then_named(&[(":id", &"one")], |row| name_to_person(row.get(0))));
///
/// let mut persons = Vec::new();
/// for person_result in rows {
@ -330,8 +342,8 @@ impl<'conn> Statement<'conn> {
Ok(AndThenRows::new(rows, f))
}
/// Return `true` if a query in the SQL statement it executes returns one or more rows
/// and `false` if the SQL returns an empty set.
/// Return `true` if a query in the SQL statement it executes returns one
/// or more rows and `false` if the SQL returns an empty set.
pub fn exists(&mut self, params: &[&ToSql]) -> Result<bool> {
let mut rows = try!(self.query(params));
let exists = {
@ -343,9 +355,11 @@ impl<'conn> Statement<'conn> {
Ok(exists)
}
/// 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.
///
/// If the query returns more than one row, all rows except the first are ignored.
/// If the query returns more than one row, all rows except the first are
/// ignored.
///
/// # Failure
///
@ -361,8 +375,8 @@ impl<'conn> Statement<'conn> {
/// Consumes the statement.
///
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any errors
/// that occur.
/// Functionally equivalent to the `Drop` implementation, but allows
/// callers to see any errors that occur.
///
/// # Failure
///
@ -514,7 +528,8 @@ impl<'conn> Statement<'conn> {
Ok(())
}
/// Returns a string containing the SQL text of prepared statement with bound parameters expanded.
/// Returns a string containing the SQL text of prepared statement with
/// bound parameters expanded.
#[cfg(feature = "bundled")]
pub fn expanded_sql(&self) -> Option<&str> {
unsafe {

View File

@ -61,12 +61,12 @@ pub fn log(err_code: c_int, msg: &str) {
}
impl Connection {
/// Register or clear a callback function that can be used for tracing the execution of SQL
/// statements.
/// Register or clear a callback function that can be used for tracing the
/// execution of SQL statements.
///
/// Prepared statement placeholders are replaced/logged with their assigned values.
/// There can only be a single tracer defined for each database connection.
/// Setting a new tracer clears the old one.
/// Prepared statement placeholders are replaced/logged with their assigned
/// values. There can only be a single tracer defined for each database
/// connection. Setting a new tracer clears the old one.
pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) {
let trace_fn: fn(&str) = mem::transmute(p_arg);
@ -86,11 +86,11 @@ impl Connection {
}
}
/// Register or clear a callback function that can be used for profiling the execution of SQL
/// statements.
/// Register or clear a callback function that can be used for profiling
/// the execution of SQL statements.
///
/// There can only be a single profiler defined for each database connection.
/// Setting a new profiler clears the old one.
/// There can only be a single profiler defined for each database
/// connection. Setting a new profiler clears the old one.
pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
unsafe extern "C" fn profile_callback(
p_arg: *mut c_void,

View File

@ -1,7 +1,8 @@
use std::ops::Deref;
use {Connection, Result};
/// Old name for `TransactionBehavior`. `SqliteTransactionBehavior` is deprecated.
/// Old name for `TransactionBehavior`. `SqliteTransactionBehavior` is
/// deprecated.
#[deprecated(since = "0.6.0", note = "Use TransactionBehavior instead")]
pub type SqliteTransactionBehavior = TransactionBehavior;
@ -23,8 +24,8 @@ pub enum DropBehavior {
/// Commit the changes.
Commit,
/// Do not commit or roll back changes - this will leave the transaction or savepoint
/// open, so should be used with care.
/// Do not commit or roll back changes - this will leave the transaction or
/// savepoint open, so should be used with care.
Ignore,
/// Panic. Used to enforce intentional behavior during development.
@ -39,9 +40,9 @@ pub type SqliteTransaction<'conn> = Transaction<'conn>;
///
/// ## Note
///
/// Transactions will roll back by default. Use `commit` method to explicitly commit the
/// transaction, or use `set_drop_behavior` to change what happens when the transaction
/// is dropped.
/// Transactions will roll back by default. Use `commit` method to explicitly
/// commit the transaction, or use `set_drop_behavior` to change what happens
/// when the transaction is dropped.
///
/// ## Example
///
@ -67,9 +68,9 @@ pub struct Transaction<'conn> {
///
/// ## Note
///
/// Savepoints will roll back by default. Use `commit` method to explicitly commit the
/// savepoint, or use `set_drop_behavior` to change what happens when the savepoint
/// is dropped.
/// Savepoints will roll back by default. Use `commit` method to explicitly
/// commit the savepoint, or use `set_drop_behavior` to change what happens
/// when the savepoint is dropped.
///
/// ## Example
///
@ -95,7 +96,8 @@ pub struct Savepoint<'conn> {
}
impl<'conn> Transaction<'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.
// Even though we don't mutate the connection, we take a `&mut Connection`
// so as to prevent nested or concurrent transactions on the same
// connection.
@ -116,7 +118,8 @@ impl<'conn> Transaction<'conn> {
///
/// ## Note
///
/// Just like outer level transactions, savepoint transactions rollback by default.
/// Just like outer level transactions, savepoint transactions rollback by
/// default.
///
/// ## Example
///
@ -146,12 +149,14 @@ impl<'conn> Transaction<'conn> {
Savepoint::with_depth_and_name(self.conn, 1, name)
}
/// Get the current setting for what happens to the transaction when it is dropped.
/// Get the current setting for what happens to the transaction when it is
/// dropped.
pub fn drop_behavior(&self) -> DropBehavior {
self.drop_behavior
}
/// Configure the transaction to perform the specified action when it is dropped.
/// Configure the transaction to perform the specified action when it is
/// dropped.
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
self.drop_behavior = drop_behavior
}
@ -176,11 +181,11 @@ impl<'conn> Transaction<'conn> {
Ok(())
}
/// Consumes the transaction, committing or rolling back according to the current setting
/// (see `drop_behavior`).
/// Consumes the transaction, committing or rolling back according to the
/// current setting (see `drop_behavior`).
///
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any
/// errors that occur.
/// Functionally equivalent to the `Drop` implementation, but allows
/// callers to see any errors that occur.
pub fn finish(mut self) -> Result<()> {
self.finish_()
}
@ -255,12 +260,14 @@ impl<'conn> Savepoint<'conn> {
Savepoint::with_depth_and_name(self.conn, self.depth + 1, name)
}
/// Get the current setting for what happens to the savepoint when it is dropped.
/// Get the current setting for what happens to the savepoint when it is
/// dropped.
pub fn drop_behavior(&self) -> DropBehavior {
self.drop_behavior
}
/// Configure the savepoint to perform the specified action when it is dropped.
/// Configure the savepoint to perform the specified action when it is
/// dropped.
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
self.drop_behavior = drop_behavior
}
@ -280,18 +287,18 @@ impl<'conn> Savepoint<'conn> {
///
/// ## Note
///
/// Unlike `Transaction`s, savepoints remain active after they have been rolled back,
/// and can be rolled back again or committed.
/// Unlike `Transaction`s, savepoints remain active after they have been
/// rolled back, and can be rolled back again or committed.
pub fn rollback(&mut self) -> Result<()> {
self.conn
.execute_batch(&format!("ROLLBACK TO {}", self.name))
}
/// Consumes the savepoint, committing or rolling back according to the current setting
/// (see `drop_behavior`).
/// Consumes the savepoint, committing or rolling back according to the
/// current setting (see `drop_behavior`).
///
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any
/// errors that occur.
/// Functionally equivalent to the `Drop` implementation, but allows
/// callers to see any errors that occur.
pub fn finish(mut self) -> Result<()> {
self.finish_()
}
@ -327,8 +334,9 @@ impl<'conn> Drop for Savepoint<'conn> {
impl Connection {
/// 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_drop_behavior(DropBehavior::Commit)`.
/// The transaction defaults to rolling back when it is dropped. If you
/// want the transaction to commit, you must call `commit` or
/// `set_drop_behavior(DropBehavior::Commit)`.
///
/// ## Example
///
@ -369,8 +377,9 @@ impl Connection {
/// Begin a new savepoint with the default behavior (DEFERRED).
///
/// The savepoint defaults to rolling back when it is dropped. If you want the savepoint to
/// commit, you must call `commit` or `set_drop_behavior(DropBehavior::Commit)`.
/// The savepoint defaults to rolling back when it is dropped. If you want
/// the savepoint to commit, you must call `commit` or
/// `set_drop_behavior(DropBehavior::Commit)`.
///
/// ## Example
///

View File

@ -53,7 +53,8 @@ impl FromSql for NaiveTime {
}
}
/// ISO 8601 combined date and time without timezone => "YYYY-MM-DD HH:MM:SS.SSS"
/// ISO 8601 combined date and time without timezone =>
/// "YYYY-MM-DD HH:MM:SS.SSS"
impl ToSql for NaiveDateTime {
fn to_sql(&self) -> Result<ToSqlOutput> {
let date_str = self.format("%Y-%m-%dT%H:%M:%S%.f").to_string();
@ -61,8 +62,9 @@ impl ToSql for NaiveDateTime {
}
}
/// "YYYY-MM-DD HH:MM:SS"/"YYYY-MM-DD HH:MM:SS.SSS" => ISO 8601 combined date and time
/// without timezone. ("YYYY-MM-DDTHH:MM:SS"/"YYYY-MM-DDTHH:MM:SS.SSS" also supported)
/// "YYYY-MM-DD HH:MM:SS"/"YYYY-MM-DD HH:MM:SS.SSS" => ISO 8601 combined date
/// and time without timezone. ("YYYY-MM-DDTHH:MM:SS"/"YYYY-MM-DDTHH:MM:SS.SSS"
/// also supported)
impl FromSql for NaiveDateTime {
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
value.as_str().and_then(|s| {
@ -80,7 +82,8 @@ impl FromSql for NaiveDateTime {
}
}
/// Date and time with time zone => UTC RFC3339 timestamp ("YYYY-MM-DDTHH:MM:SS.SSS+00:00").
/// Date and time with time zone => UTC RFC3339 timestamp
/// ("YYYY-MM-DDTHH:MM:SS.SSS+00:00").
impl<Tz: TimeZone> ToSql for DateTime<Tz> {
fn to_sql(&self) -> Result<ToSqlOutput> {
Ok(ToSqlOutput::from(self.with_timezone(&Utc).to_rfc3339()))

View File

@ -5,11 +5,12 @@ use std::fmt;
/// Enum listing possible errors from `FromSql` trait.
#[derive(Debug)]
pub enum FromSqlError {
/// Error when an SQLite value is requested, but the type of the result cannot be converted to
/// the requested Rust type.
/// Error when an SQLite value is requested, but the type of the result
/// cannot be converted to the requested Rust type.
InvalidType,
/// Error when the i64 value returned by SQLite cannot be stored into the requested type.
/// Error when the i64 value returned by SQLite cannot be stored into the
/// requested type.
OutOfRange(i64),
/// An error case available for implementors of the `FromSql` trait.
@ -49,13 +50,15 @@ pub type FromSqlResult<T> = Result<T, FromSqlError>;
/// A trait for types that can be created from a SQLite value.
///
/// Note that `FromSql` and `ToSql` are defined for most integral types, but not `u64` or `usize`.
/// This is intentional; SQLite returns integers as signed 64-bit values, which cannot fully
/// represent the range of these types. Rusqlite would have to decide how to handle negative
/// values: return an error or reinterpret as a very large postive numbers, neither of which is
/// guaranteed to be correct for everyone. Callers can work around this by fetching values as i64
/// and then doing the interpretation themselves or by defining a newtype and implementing
/// `FromSql`/`ToSql` for it.
/// Note that `FromSql` and `ToSql` are defined for most integral types, but
/// not `u64` or `usize`. This is intentional; SQLite returns integers as
/// signed 64-bit values, which cannot fully represent the range of these
/// types. Rusqlite would have to
/// decide how to handle negative values: return an error or reinterpret as a
/// very large postive numbers, neither of which
/// is guaranteed to be correct for everyone. Callers can work around this by
/// fetching values as i64 and then doing the interpretation themselves or by
/// defining a newtype and implementing `FromSql`/`ToSql` for it.
pub trait FromSql: Sized {
fn column_result(value: ValueRef) -> FromSqlResult<Self>;
}

View File

@ -1,11 +1,11 @@
//! Traits dealing with SQLite data types.
//!
//! SQLite uses a [dynamic type system](https://www.sqlite.org/datatype3.html). Implementations of
//! the `ToSql` and `FromSql` traits are provided for the basic types that SQLite provides methods
//! for:
//! the `ToSql` and `FromSql` traits are provided for the basic types that
//! SQLite provides methods for:
//!
//! * Integers (`i32` and `i64`; SQLite uses `i64` internally, so getting an `i32` will truncate
//! if the value is too large or too small).
//! * Integers (`i32` and `i64`; SQLite uses `i64` internally, so getting an
//! `i32` will truncate if the value is too large or too small).
//! * Reals (`f64`)
//! * Strings (`String` and `&str`)
//! * Blobs (`Vec<u8>` and `&[u8]`)
@ -22,16 +22,18 @@
//! extern crate rusqlite;
//! extern crate time;
//!
//! use rusqlite::types::{FromSql, FromSqlResult, ValueRef, ToSql, ToSqlOutput};
//! use rusqlite::{Result};
//! use rusqlite::types::{FromSql, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
//! use rusqlite::Result;
//!
//! pub struct TimespecSql(pub time::Timespec);
//!
//! impl FromSql for TimespecSql {
//! fn column_result(value: ValueRef) -> FromSqlResult<Self> {
//! f64::column_result(value).map(|as_f64| {
//! TimespecSql(time::Timespec{ sec: as_f64.trunc() as i64,
//! nsec: (as_f64.fract() * 1.0e9) as i32 })
//! TimespecSql(time::Timespec {
//! sec: as_f64.trunc() as i64,
//! nsec: (as_f64.fract() * 1.0e9) as i32,
//! })
//! })
//! }
//! }
@ -48,9 +50,9 @@
//! # fn main() {}
//! ```
//!
//! `ToSql` and `FromSql` are also implemented for `Option<T>` where `T` implements `ToSql` or
//! `FromSql` for the cases where you want to know if a value was NULL (which gets translated to
//! `None`).
//! `ToSql` and `FromSql` are also implemented for `Option<T>` where `T`
//! implements `ToSql` or `FromSql` for the cases where you want to know if a
//! value was NULL (which gets translated to `None`).
pub use self::from_sql::{FromSql, FromSqlError, FromSqlResult};
pub use self::to_sql::{ToSql, ToSqlOutput};
@ -77,8 +79,7 @@ mod value_ref;
/// # extern crate rusqlite;
/// # use rusqlite::{Connection, Result};
/// # use rusqlite::types::{Null};
/// fn main() {
/// }
/// fn main() {}
/// fn insert_null(conn: &Connection) -> Result<usize> {
/// conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null])
/// }

View File

@ -4,7 +4,8 @@ use std::borrow::Cow;
use vtab::array::Array;
use Result;
/// `ToSqlOutput` represents the possible output types for implementors of the `ToSql` trait.
/// `ToSqlOutput` represents the possible output types for implementors of the
/// `ToSql` trait.
#[derive(Clone, Debug, PartialEq)]
pub enum ToSqlOutput<'a> {
/// A borrowed SQLite-representable value.

View File

@ -32,8 +32,8 @@ impl<'a> ValueRef<'a> {
}
impl<'a> ValueRef<'a> {
/// If `self` is case `Integer`, returns the integral value. Otherwise, returns
/// `Err(Error::InvalidColumnType)`.
/// If `self` is case `Integer`, returns the integral value. Otherwise,
/// returns `Err(Error::InvalidColumnType)`.
pub fn as_i64(&self) -> FromSqlResult<i64> {
match *self {
ValueRef::Integer(i) => Ok(i),
@ -41,8 +41,8 @@ impl<'a> ValueRef<'a> {
}
}
/// If `self` is case `Real`, returns the floating point value. Otherwise, returns
/// `Err(Error::InvalidColumnType)`.
/// If `self` is case `Real`, returns the floating point value. Otherwise,
/// returns `Err(Error::InvalidColumnType)`.
pub fn as_f64(&self) -> FromSqlResult<f64> {
match *self {
ValueRef::Real(f) => Ok(f),

View File

@ -1,7 +1,8 @@
use ffi;
use std::ffi::CStr;
/// Returns the SQLite version as an integer; e.g., `3016002` for version 3.16.2.
/// Returns the SQLite version as an integer; e.g., `3016002` for version
/// 3.16.2.
///
/// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html).
pub fn version_number() -> i32 {

View File

@ -120,6 +120,7 @@ impl ArrayTabCursor {
ptr: None,
}
}
fn len(&self) -> i64 {
match self.ptr {
Some(ref a) => a.len() as i64,
@ -137,13 +138,16 @@ impl VTabCursor for ArrayTabCursor {
self.row_id = 1;
Ok(())
}
fn next(&mut self) -> Result<()> {
self.row_id += 1;
Ok(())
}
fn eof(&self) -> bool {
self.row_id > self.len()
}
fn column(&self, ctx: &mut Context, i: c_int) -> Result<()> {
match i {
CARRAY_COLUMN_POINTER => Ok(()),
@ -157,6 +161,7 @@ impl VTabCursor for ArrayTabCursor {
}
}
}
fn rowid(&self) -> Result<i64> {
Ok(self.row_id)
}

View File

@ -293,6 +293,7 @@ impl VTabCursor for CSVTabCursor {
self.row_number = 0;
self.next()
}
fn next(&mut self) -> Result<()> {
{
self.eof = self.reader.is_done();
@ -306,9 +307,11 @@ impl VTabCursor for CSVTabCursor {
self.row_number += 1;
Ok(())
}
fn eof(&self) -> bool {
self.eof
}
fn column(&self, ctx: &mut Context, col: c_int) -> Result<()> {
if col < 0 || col as usize >= self.cols.len() {
return Err(Error::ModuleError(format!(
@ -322,6 +325,7 @@ impl VTabCursor for CSVTabCursor {
// TODO Affinity
ctx.set_result(&self.cols[col as usize].to_owned())
}
fn rowid(&self) -> Result<i64> {
Ok(self.row_number as i64)
}

View File

@ -278,12 +278,14 @@ impl IndexInfo {
(*self.0).idxNum = idx_num;
}
}
/// True if output is already ordered
pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
unsafe {
(*self.0).orderByConsumed = if order_by_consumed { 1 } else { 0 };
}
}
/// Estimated cost of using this index
pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
unsafe {
@ -329,10 +331,12 @@ impl<'a> IndexConstraint<'a> {
pub fn column(&self) -> c_int {
self.0.iColumn
}
/// Constraint operator
pub fn operator(&self) -> IndexConstraintOp {
IndexConstraintOp::from_bits_truncate(self.0.op)
}
/// True if this constraint is usable
pub fn is_usable(&self) -> bool {
self.0.usable != 0
@ -347,6 +351,7 @@ impl<'a> IndexConstraintUsage<'a> {
pub fn set_argv_index(&mut self, argv_index: c_int) {
self.0.argvIndex = argv_index;
}
/// if `omit`, do not code a test for this constraint
pub fn set_omit(&mut self, omit: bool) {
self.0.omit = if omit { 1 } else { 0 };
@ -377,6 +382,7 @@ impl<'a> OrderBy<'a> {
pub fn column(&self) -> c_int {
self.0.iColumn
}
/// True for DESC. False for ASC.
pub fn is_order_by_desc(&self) -> bool {
self.0.desc != 0
@ -483,8 +489,8 @@ impl<'a> Values<'a> {
}
impl<'a> IntoIterator for &'a Values<'a> {
type Item = ValueRef<'a>;
type IntoIter = ValueIter<'a>;
type Item = ValueRef<'a>;
fn into_iter(self) -> ValueIter<'a> {
self.iter()

View File

@ -227,6 +227,7 @@ impl VTabCursor for SeriesTabCursor {
self.row_id = 1;
Ok(())
}
fn next(&mut self) -> Result<()> {
if self.is_desc {
self.value -= self.step;
@ -236,6 +237,7 @@ impl VTabCursor for SeriesTabCursor {
self.row_id += 1;
Ok(())
}
fn eof(&self) -> bool {
if self.is_desc {
self.value < self.min_value
@ -243,6 +245,7 @@ impl VTabCursor for SeriesTabCursor {
self.value > self.max_value
}
}
fn column(&self, ctx: &mut Context, i: c_int) -> Result<()> {
let x = match i {
SERIES_COLUMN_START => self.min_value,
@ -252,6 +255,7 @@ impl VTabCursor for SeriesTabCursor {
};
ctx.set_result(&x)
}
fn rowid(&self) -> Result<i64> {
Ok(self.row_id)
}

View File

@ -1,5 +1,6 @@
//! This file contains unit tests for `rusqlite::trace::config_log`. This function affects
//! SQLite process-wide and so is not safe to run as a normal #[test] in the library.
//! This file contains unit tests for `rusqlite::trace::config_log`. This
//! function affects SQLite process-wide and so is not safe to run as a normal
//! #[test] in the library.
#[cfg(feature = "trace")]
#[macro_use]

View File

@ -65,16 +65,20 @@ fn test_dummy_module() {
self.row_id = 1;
Ok(())
}
fn next(&mut self) -> Result<()> {
self.row_id += 1;
Ok(())
}
fn eof(&self) -> bool {
self.row_id > 1
}
fn column(&self, ctx: &mut Context, _: c_int) -> Result<()> {
ctx.set_result(&self.row_id)
}
fn rowid(&self) -> Result<i64> {
Ok(self.row_id)
}