mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
commit
d1b2104b89
@ -1,34 +0,0 @@
|
||||
rusqlite contributors
|
||||
=====================
|
||||
|
||||
* [John Gallagher](https://github.com/jgallagher)
|
||||
* [Marcus Klaas de Vries](https://github.com/marcusklaas)
|
||||
* [gwenn](https://github.com/gwenn)
|
||||
* [Jimmy Lu](https://github.com/Yuhta)
|
||||
* [Huon Wilson](https://github.com/huonw)
|
||||
* [Patrick Fernie](https://github.com/pfernie)
|
||||
* [Steve Klabnik](https://github.com/steveklabnik)
|
||||
* [krdln](https://github.com/krdln)
|
||||
* [Ben Striegel](https://github.com/bstrie)
|
||||
* [Andrew Straw](https://github.com/astraw)
|
||||
* [Ronald Kinard](https://github.com/Furyhunter)
|
||||
* [maciejkula](https://github.com/maciejkula)
|
||||
* [Xidorn Quan](https://github.com/upsuper)
|
||||
* [Chip Collier](https://github.com/photex)
|
||||
* [Omar Ferrer](https://github.com/chamakits)
|
||||
* [Lee Jenkins](https://github.com/reddraggone9)
|
||||
* [miedzinski](https://github.com/miedzinski)
|
||||
* [aidanhs](https://github.com/aidanhs)
|
||||
* [Steven Fackler](https://github.com/sfackler)
|
||||
* [Davide Aversa](https://github.com/THeK3nger)
|
||||
* [mcgoo](https://github.com/mcgoo)
|
||||
* [Kelvin Ly](https://github.com/cactorium)
|
||||
* [king6cong](https://github.com/king6cong)
|
||||
* [Andy Russell](https://github.com/euclio)
|
||||
* [Tristan Lostroh](https://github.com/tl8roy)
|
||||
* [Ossi Herrala](https://github.com/oherrala)
|
||||
* [Vojtech Cima](https://github.com/vojtechcima)
|
||||
* [Louis Garczynski](https://github.com/lgarczyn)
|
||||
* [twistedfall](https://github.com/twistedfall)
|
||||
* [Nick Fitzgerald](https://github.com/fitzgen)
|
||||
* [Lorenzo Villani](https://github.com/lvillani)
|
26
Changelog.md
26
Changelog.md
@ -1,3 +1,29 @@
|
||||
# Version 0.14.0 (2018-08-1?)
|
||||
|
||||
* BREAKING CHANGE: `ToSql` implementation for `time::Timespec` uses RFC 3339 (%Y-%m-%dT%H:%M:%S.%fZ).
|
||||
Previous format was %Y-%m-%d %H:%M:%S:%f %Z.
|
||||
* BREAKING CHANGE: Remove potentially conflicting impl of ToSqlOutput (#313).
|
||||
* BREAKING CHANGE: Replace column index/count type (i32) with usize.
|
||||
* BREAKING CHANGE: Replace parameter index/count type (i32) with usize.
|
||||
* BREAKING CHANGE: Replace row changes/count type (i32) with usize.
|
||||
* BREAKING CHANGE: Scalar functions must be `Send`able and `'static`.
|
||||
* Bugfix: Commit failure unhandled, database left in unusable state (#366).
|
||||
* Bugfix: `free_boxed_hook` does not work for `fn`.
|
||||
* Update the bundled SQLite version to 3.24.0 (#326).
|
||||
* Add DropBehavior::Panic to enforce intentional commit or rollback.
|
||||
* Implement `sqlite3_update_hook` (#260, #328), `sqlite3_commit_hook` and `sqlite3_rollback_hook`.
|
||||
* Add support to unlock notification behind `unlock_notify` feature (#294, #331).
|
||||
* Make `Statement::column_index` case insensitive (#330).
|
||||
* Add comment to justify `&mut Connection` in `Transaction`.
|
||||
* Fix `tyvar_behind_raw_pointer` warnings.
|
||||
* Fix handful of clippy warnings.
|
||||
* Fix `Connection::open` documentation (#332)
|
||||
* Add binding to `sqlite3_get_autocommit` and `sqlite3_stmt_busy`.
|
||||
* Add binding to `sqlite3_busy_timeout` and `sqlite3_busy_handler`.
|
||||
* Add binding to `sqlite3_expanded_sql`.
|
||||
* Use `rerun-if-env-changed` in libsqlite3-sys (#329).
|
||||
* Return an `InvalidQuery` error when SQL is not read only.
|
||||
|
||||
# Version 0.13.0 (2017-11-13)
|
||||
|
||||
* Added ToSqlConversionFailure case to Error enum.
|
||||
|
@ -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
|
||||
|
66
src/blob.rs
66
src/blob.rs
@ -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)]
|
||||
|
35
src/busy.rs
35
src/busy.rs
@ -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);
|
||||
|
29
src/cache.rs
29
src/cache.rs
@ -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,
|
||||
|
49
src/error.rs
49
src/error.rs
@ -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),
|
||||
|
||||
|
@ -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(®ex_s) {
|
||||
//! Ok(r) => vac.insert(r),
|
||||
//! Err(err) => return Err(Error::UserFunctionError(Box::new(err))),
|
||||
//! }
|
||||
//! }
|
||||
//! Vacant(vac) => match Regex::new(®ex_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`.
|
||||
|
20
src/hooks.rs
20
src/hooks.rs
@ -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 {
|
||||
|
283
src/lib.rs
283
src/lib.rs
@ -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,
|
||||
|
@ -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 })
|
||||
|
35
src/row.rs
35
src/row.rs
@ -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);
|
||||
|
121
src/statement.rs
121
src/statement.rs
@ -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 {
|
||||
|
18
src/trace.rs
18
src/trace.rs
@ -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,
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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()))
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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])
|
||||
/// }
|
||||
|
@ -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.
|
||||
|
@ -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),
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user