mirror of
https://github.com/isar/rusqlite.git
synced 2025-01-20 00:00:52 +08:00
Rustfmt
This commit is contained in:
parent
33271764b1
commit
5e9c7bac4e
@ -18,8 +18,11 @@
|
|||||||
//! # use std::path::Path;
|
//! # use std::path::Path;
|
||||||
//! # use std::time;
|
//! # use std::time;
|
||||||
//!
|
//!
|
||||||
//! fn backup_db<P: AsRef<Path>>(src: &Connection, dst: P, progress: fn(backup::Progress))
|
//! fn backup_db<P: AsRef<Path>>(
|
||||||
//! -> Result<()> {
|
//! src: &Connection,
|
||||||
|
//! dst: P,
|
||||||
|
//! progress: fn(backup::Progress),
|
||||||
|
//! ) -> Result<()> {
|
||||||
//! let mut dst = try!(Connection::open(dst));
|
//! let mut dst = try!(Connection::open(dst));
|
||||||
//! let backup = try!(backup::Backup::new(src, &mut dst));
|
//! let backup = try!(backup::Backup::new(src, &mut dst));
|
||||||
//! backup.run_to_completion(5, time::Duration::from_millis(250), Some(progress))
|
//! backup.run_to_completion(5, time::Duration::from_millis(250), Some(progress))
|
||||||
@ -136,7 +139,8 @@ pub enum StepResult {
|
|||||||
/// The backup is complete.
|
/// The backup is complete.
|
||||||
Done,
|
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,
|
More,
|
||||||
|
|
||||||
/// The step failed because appropriate locks could not be aquired. This is
|
/// 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.
|
//! Incremental BLOB I/O.
|
||||||
//!
|
//!
|
||||||
//! Note that SQLite does not provide API-level access to change the size of a BLOB; that must
|
//! Note that SQLite does not provide API-level access to change the size of a
|
||||||
//! be performed through SQL statements.
|
//! BLOB; that must be performed through SQL statements.
|
||||||
//!
|
//!
|
||||||
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`, so it plays
|
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`,
|
||||||
//! nicely with other types that build on these (such as `std::io::BufReader` and
|
//! so it plays nicely with other types that build on these (such as
|
||||||
//! `std::io::BufWriter`). However, you must be careful with the size of the blob. For example,
|
//! `std::io::BufReader` and `std::io::BufWriter`). However, you must be
|
||||||
//! when using a `BufWriter`, the `BufWriter` will accept more data than the `Blob` will allow,
|
//! careful with the size of the blob. For example, when using a `BufWriter`,
|
||||||
//! so make sure to call `flush` and check for errors. (See the unit tests in this module for
|
//! the `BufWriter` will accept more data than the `Blob`
|
||||||
//! an example.)
|
//! will allow, so make sure to call `flush` and check for errors. (See the
|
||||||
|
//! unit tests in this module for an example.)
|
||||||
//!
|
//!
|
||||||
//! ## Example
|
//! ## Example
|
||||||
//!
|
//!
|
||||||
@ -16,17 +17,21 @@
|
|||||||
//! extern crate libsqlite3_sys;
|
//! extern crate libsqlite3_sys;
|
||||||
//! extern crate rusqlite;
|
//! extern crate rusqlite;
|
||||||
//!
|
//!
|
||||||
//! use rusqlite::{Connection, DatabaseName};
|
|
||||||
//! use rusqlite::blob::ZeroBlob;
|
//! use rusqlite::blob::ZeroBlob;
|
||||||
//! use std::io::{Read, Write, Seek, SeekFrom};
|
//! use rusqlite::{Connection, DatabaseName};
|
||||||
|
//! use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let db = Connection::open_in_memory().unwrap();
|
//! let db = Connection::open_in_memory().unwrap();
|
||||||
//! db.execute_batch("CREATE TABLE test (content BLOB);").unwrap();
|
//! db.execute_batch("CREATE TABLE test (content BLOB);")
|
||||||
//! db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[]).unwrap();
|
//! .unwrap();
|
||||||
|
//! db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[])
|
||||||
|
//! .unwrap();
|
||||||
//!
|
//!
|
||||||
//! let rowid = db.last_insert_rowid();
|
//! 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;
|
//! // 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.
|
//! // 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();
|
//! let bytes_read = blob.read(&mut buf[..]).unwrap();
|
||||||
//! assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
|
//! 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
|
//! // given a new row ID, we can reopen the blob on that row
|
||||||
//! let rowid = db.last_insert_rowid();
|
//! let rowid = db.last_insert_rowid();
|
||||||
@ -64,12 +70,14 @@ pub struct Blob<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
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
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string
|
/// Will return `Err` if `db`/`table`/`column` cannot be converted to a
|
||||||
/// or if the underlying SQLite BLOB open call fails.
|
/// C-compatible string or if the underlying SQLite BLOB open call
|
||||||
|
/// fails.
|
||||||
pub fn blob_open<'a>(
|
pub fn blob_open<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
db: DatabaseName,
|
db: DatabaseName,
|
||||||
@ -124,8 +132,9 @@ impl<'conn> Blob<'conn> {
|
|||||||
|
|
||||||
/// Close a BLOB handle.
|
/// Close a BLOB handle.
|
||||||
///
|
///
|
||||||
/// Calling `close` explicitly is not required (the BLOB will be closed when the
|
/// Calling `close` explicitly is not required (the BLOB will be closed
|
||||||
/// `Blob` is dropped), but it is available so you can get any errors that occur.
|
/// when the `Blob` is dropped), but it is available so you can get any
|
||||||
|
/// errors that occur.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -142,8 +151,8 @@ impl<'conn> Blob<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn> io::Read for 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
|
/// Read data from a BLOB incrementally. Will return Ok(0) if the end of
|
||||||
/// has been reached.
|
/// the blob has been reached.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -165,12 +174,13 @@ impl<'conn> io::Read for Blob<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn> io::Write 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
|
/// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of
|
||||||
/// has been reached; consider using `Write::write_all(buf)` if you want to get an
|
/// the blob has been reached; consider using `Write::write_all(buf)`
|
||||||
/// error if the entirety of the buffer cannot be written.
|
/// 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
|
/// This function may only modify the contents of the BLOB; it is not
|
||||||
/// the size of a BLOB using this API.
|
/// possible to increase the size of a BLOB using this API.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -230,8 +240,8 @@ impl<'conn> Drop for Blob<'conn> {
|
|||||||
|
|
||||||
/// BLOB of length N that is filled with zeroes.
|
/// BLOB of length N that is filled with zeroes.
|
||||||
///
|
///
|
||||||
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using
|
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is
|
||||||
/// incremental BLOB I/O routines.
|
/// later written using incremental BLOB I/O routines.
|
||||||
///
|
///
|
||||||
/// A negative value for the zeroblob results in a zero-length BLOB.
|
/// A negative value for the zeroblob results in a zero-length BLOB.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
35
src/busy.rs
35
src/busy.rs
@ -8,13 +8,17 @@ use ffi;
|
|||||||
use {Connection, InnerConnection, Result};
|
use {Connection, InnerConnection, Result};
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
/// Set a busy handler that sleeps for a specified amount of time when a table is locked.
|
/// Set a busy handler that sleeps for a specified amount of time when a
|
||||||
/// The handler will sleep multiple times until at least "ms" milliseconds of sleeping have accumulated.
|
/// 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.
|
/// There can only be a single busy handler for a particular database
|
||||||
/// If another busy handler was defined (using `busy_handler`) prior to calling this routine, that other busy handler is cleared.
|
/// 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<()> {
|
pub fn busy_timeout(&self, timeout: Duration) -> Result<()> {
|
||||||
let ms = timeout
|
let ms = timeout
|
||||||
.as_secs()
|
.as_secs()
|
||||||
@ -26,14 +30,21 @@ impl Connection {
|
|||||||
|
|
||||||
/// Register a callback to handle `SQLITE_BUSY` errors.
|
/// Register a callback to handle `SQLITE_BUSY` errors.
|
||||||
///
|
///
|
||||||
/// If the busy callback is `None`, then `SQLITE_BUSY is returned immediately upon encountering the lock.`
|
/// If the busy callback is `None`, then `SQLITE_BUSY is returned
|
||||||
/// 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.
|
/// immediately upon encountering the lock.` The argument to the busy
|
||||||
/// If the busy callback returns `false`, then no additional attempts are made to access the database and `SQLITE_BUSY` is returned to the application.
|
/// handler callback is the number of times that the
|
||||||
/// If the callback returns `true`, then another attempt is made to access the database and the cycle repeats.
|
/// 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.
|
/// There can only be a single busy handler defined for each database
|
||||||
/// Setting a new busy handler clears any previously set handler.
|
/// connection. Setting a new busy handler clears any previously set
|
||||||
/// Note that calling `busy_timeout()` or evaluating `PRAGMA busy_timeout=N` will change the busy handler and thus clear any previously set busy handler.
|
/// 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<()> {
|
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 {
|
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);
|
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};
|
use {Connection, Result, Statement};
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
/// Prepare a SQL statement for execution, returning a previously prepared (but
|
/// Prepare a SQL statement for execution, returning a previously prepared
|
||||||
/// not currently in-use) statement if one is available. The returned statement
|
/// (but not currently in-use) statement if one is available. The
|
||||||
/// will be cached for reuse by future calls to `prepare_cached` once it is
|
/// returned statement will be cached for reuse by future calls to
|
||||||
/// dropped.
|
/// `prepare_cached` once it is dropped.
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{Connection, Result};
|
/// # use rusqlite::{Connection, Result};
|
||||||
@ -31,16 +31,17 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
|
pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
|
||||||
self.cache.get(self, sql)
|
self.cache.get(self, sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of cached prepared statements this connection will hold.
|
/// Set the maximum number of cached prepared statements this connection
|
||||||
/// By default, a connection will hold a relatively small number of cached statements.
|
/// will hold. By default, a connection will hold a relatively small
|
||||||
/// If you need more, or know that you will not use cached statements, you can set
|
/// number of cached statements. If you need more, or know that you
|
||||||
/// the capacity manually using this method.
|
/// will not use cached statements, you
|
||||||
|
/// can set the capacity manually using this method.
|
||||||
pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
|
pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
|
||||||
self.cache.set_capacity(capacity)
|
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
|
/// Discard the statement, preventing it from being returned to its
|
||||||
/// of cached statements.
|
/// `Connection`'s collection of cached statements.
|
||||||
pub fn discard(mut self) {
|
pub fn discard(mut self) {
|
||||||
self.stmt = None;
|
self.stmt = None;
|
||||||
}
|
}
|
||||||
@ -117,8 +118,8 @@ impl StatementCache {
|
|||||||
//
|
//
|
||||||
// # Failure
|
// # Failure
|
||||||
//
|
//
|
||||||
// Will return `Err` if no cached statement can be found and the underlying SQLite prepare
|
// Will return `Err` if no cached statement can be found and the underlying
|
||||||
// call fails.
|
// SQLite prepare call fails.
|
||||||
fn get<'conn>(
|
fn get<'conn>(
|
||||||
&'conn self,
|
&'conn self,
|
||||||
conn: &'conn Connection,
|
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.
|
/// An error from an underlying SQLite call.
|
||||||
SqliteFailure(ffi::Error, Option<String>),
|
SqliteFailure(ffi::Error, Option<String>),
|
||||||
|
|
||||||
/// Error reported when attempting to open a connection when SQLite was configured to
|
/// Error reported when attempting to open a connection when SQLite was
|
||||||
/// allow single-threaded use only.
|
/// configured to allow single-threaded use only.
|
||||||
SqliteSingleThreadedMode,
|
SqliteSingleThreadedMode,
|
||||||
|
|
||||||
/// Error when the value of a particular column is requested, but it cannot be converted to
|
/// Error when the value of a particular column is requested, but it cannot
|
||||||
/// the requested Rust type.
|
/// be converted to the requested Rust type.
|
||||||
FromSqlConversionFailure(usize, Type, Box<error::Error + Send + Sync>),
|
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.,
|
/// Error when SQLite gives us an integral value outside the range of the
|
||||||
/// trying to get the value 1000 into a `u8`). The associated `usize` is the column index, and
|
/// requested type (e.g., trying to get the value 1000 into a `u8`).
|
||||||
/// the associated `i64` is the value returned by SQLite.
|
/// The associated `usize` is the column index,
|
||||||
|
/// and the associated `i64` is the value returned by SQLite.
|
||||||
IntegralValueOutOfRange(usize, i64),
|
IntegralValueOutOfRange(usize, i64),
|
||||||
|
|
||||||
/// Error converting a string to UTF-8.
|
/// Error converting a string to UTF-8.
|
||||||
Utf8Error(str::Utf8Error),
|
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),
|
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),
|
InvalidParameterName(String),
|
||||||
|
|
||||||
/// Error converting a file path to a string.
|
/// Error converting a file path to a string.
|
||||||
@ -45,31 +48,33 @@ pub enum Error {
|
|||||||
/// Error returned when an `execute` call returns rows.
|
/// Error returned when an `execute` call returns rows.
|
||||||
ExecuteReturnedResults,
|
ExecuteReturnedResults,
|
||||||
|
|
||||||
/// Error when a query that was expected to return at least one row (e.g., for `query_row`)
|
/// Error when a query that was expected to return at least one row (e.g.,
|
||||||
/// did not return any.
|
/// for `query_row`) did not return any.
|
||||||
QueryReturnedNoRows,
|
QueryReturnedNoRows,
|
||||||
|
|
||||||
/// Error when the value of a particular column is requested, but the index is out of range
|
/// Error when the value of a particular column is requested, but the index
|
||||||
/// for the statement.
|
/// is out of range for the statement.
|
||||||
InvalidColumnIndex(usize),
|
InvalidColumnIndex(usize),
|
||||||
|
|
||||||
/// Error when the value of a named column is requested, but no column matches the name
|
/// Error when the value of a named column is requested, but no column
|
||||||
/// for the statement.
|
/// matches the name for the statement.
|
||||||
InvalidColumnName(String),
|
InvalidColumnName(String),
|
||||||
|
|
||||||
/// Error when the value of a particular column is requested, but the type of the result in
|
/// Error when the value of a particular column is requested, but the type
|
||||||
/// that column cannot be converted to the requested Rust type.
|
/// of the result in that column cannot be converted to the requested
|
||||||
|
/// Rust type.
|
||||||
InvalidColumnType(usize, 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),
|
StatementChangedRows(usize),
|
||||||
|
|
||||||
/// Error returned by `functions::Context::get` when the function argument cannot be converted
|
/// Error returned by `functions::Context::get` when the function argument
|
||||||
/// to the requested type.
|
/// cannot be converted to the requested type.
|
||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
InvalidFunctionParameterType(usize, Type),
|
InvalidFunctionParameterType(usize, Type),
|
||||||
/// Error returned by `vtab::Values::get` when the filter argument cannot be converted
|
/// Error returned by `vtab::Values::get` when the filter argument cannot
|
||||||
/// to the requested type.
|
/// be converted to the requested type.
|
||||||
#[cfg(feature = "vtab")]
|
#[cfg(feature = "vtab")]
|
||||||
InvalidFilterParameterType(usize, Type),
|
InvalidFilterParameterType(usize, Type),
|
||||||
|
|
||||||
|
@ -2,19 +2,20 @@
|
|||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
//! Adding a `regexp` function to a connection in which compiled regular expressions
|
//! Adding a `regexp` function to a connection in which compiled regular
|
||||||
//! are cached in a `HashMap`. For an alternative implementation that uses SQLite's
|
//! expressions are cached in a `HashMap`. For an alternative implementation
|
||||||
//! [Function Auxilliary Data](https://www.sqlite.org/c3ref/get_auxdata.html) interface
|
//! 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.
|
//! to avoid recompiling regular expressions, see the unit tests for this
|
||||||
|
//! module.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! extern crate libsqlite3_sys;
|
//! extern crate libsqlite3_sys;
|
||||||
//! extern crate rusqlite;
|
//! extern crate rusqlite;
|
||||||
//! extern crate regex;
|
//! extern crate regex;
|
||||||
//!
|
//!
|
||||||
|
//! use regex::Regex;
|
||||||
//! use rusqlite::{Connection, Error, Result};
|
//! use rusqlite::{Connection, Error, Result};
|
||||||
//! use std::collections::HashMap;
|
//! use std::collections::HashMap;
|
||||||
//! use regex::Regex;
|
|
||||||
//!
|
//!
|
||||||
//! fn add_regexp_function(db: &Connection) -> Result<()> {
|
//! fn add_regexp_function(db: &Connection) -> Result<()> {
|
||||||
//! let mut cached_regexes = HashMap::new();
|
//! let mut cached_regexes = HashMap::new();
|
||||||
@ -25,12 +26,10 @@
|
|||||||
//! use std::collections::hash_map::Entry::{Occupied, Vacant};
|
//! use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
//! match entry {
|
//! match entry {
|
||||||
//! Occupied(occ) => occ.into_mut(),
|
//! Occupied(occ) => occ.into_mut(),
|
||||||
//! Vacant(vac) => {
|
//! Vacant(vac) => match Regex::new(®ex_s) {
|
||||||
//! match Regex::new(®ex_s) {
|
|
||||||
//! Ok(r) => vac.insert(r),
|
//! Ok(r) => vac.insert(r),
|
||||||
//! Err(err) => return Err(Error::UserFunctionError(Box::new(err))),
|
//! Err(err) => return Err(Error::UserFunctionError(Box::new(err))),
|
||||||
//! }
|
//! },
|
||||||
//! }
|
|
||||||
//! }
|
//! }
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
@ -43,8 +42,10 @@
|
|||||||
//! let db = Connection::open_in_memory().unwrap();
|
//! let db = Connection::open_in_memory().unwrap();
|
||||||
//! add_regexp_function(&db).unwrap();
|
//! add_regexp_function(&db).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let is_match: bool = db.query_row("SELECT regexp('[aeiou]*', 'aaaaeeeiii')", &[],
|
//! let is_match: bool = db
|
||||||
//! |row| row.get(0)).unwrap();
|
//! .query_row("SELECT regexp('[aeiou]*', 'aaaaeeeiii')", &[], |row| {
|
||||||
|
//! row.get(0)
|
||||||
|
//! }).unwrap();
|
||||||
//!
|
//!
|
||||||
//! assert!(is_match);
|
//! assert!(is_match);
|
||||||
//! }
|
//! }
|
||||||
@ -64,10 +65,10 @@ use types::{FromSql, FromSqlError, ToSql, ValueRef};
|
|||||||
use {str_to_cstring, Connection, Error, InnerConnection, Result};
|
use {str_to_cstring, Connection, Error, InnerConnection, Result};
|
||||||
|
|
||||||
unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) {
|
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
|
// Extended constraint error codes were added in SQLite 3.7.16. We don't have
|
||||||
// feature check for that, and this doesn't really warrant one. We'll use the extended code
|
// an explicit feature check for that, and this doesn't really warrant one.
|
||||||
// if we're on the bundled version (since it's at least 3.17.0) and the normal constraint
|
// We'll use the extended code if we're on the bundled version (since it's
|
||||||
// error code if not.
|
// at least 3.17.0) and the normal constraint error code if not.
|
||||||
#[cfg(feature = "bundled")]
|
#[cfg(feature = "bundled")]
|
||||||
fn constraint_error_code() -> i32 {
|
fn constraint_error_code() -> i32 {
|
||||||
ffi::SQLITE_CONSTRAINT_FUNCTION
|
ffi::SQLITE_CONSTRAINT_FUNCTION
|
||||||
@ -108,6 +109,7 @@ impl<'a> Context<'a> {
|
|||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.args.len()
|
self.args.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` when there is no argument.
|
/// Returns `true` when there is no argument.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.args.is_empty()
|
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 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> {
|
pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
|
||||||
let arg = self.args[idx];
|
let arg = self.args[idx];
|
||||||
let value = unsafe { ValueRef::from_value(arg) };
|
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.
|
/// 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.
|
/// `A` is the type of the aggregation context and `T` is the type of the final
|
||||||
/// Implementations should be stateless.
|
/// result. Implementations should be stateless.
|
||||||
pub trait Aggregate<A, T>
|
pub trait Aggregate<A, T>
|
||||||
where
|
where
|
||||||
T: ToSql,
|
T: ToSql,
|
||||||
{
|
{
|
||||||
/// Initializes the aggregation context. Will be called prior to the first call
|
/// Initializes the aggregation context. Will be called prior to the first
|
||||||
/// to `step()` to set up the context for an invocation of the function. (Note:
|
/// call to `step()` to set up the context for an invocation of the
|
||||||
/// `init()` will not be called if there are no rows.)
|
/// function. (Note: `init()` will not be called if there are no rows.)
|
||||||
fn init(&self) -> A;
|
fn init(&self) -> A;
|
||||||
|
|
||||||
/// "step" function called once for each row in an aggregate group. May be called
|
/// "step" function called once for each row in an aggregate group. May be
|
||||||
/// 0 times if there are no rows.
|
/// called 0 times if there are no rows.
|
||||||
fn step(&self, &mut Context, &mut A) -> Result<()>;
|
fn step(&self, &mut Context, &mut A) -> Result<()>;
|
||||||
|
|
||||||
/// Computes and returns the final result. Will be called exactly once for each
|
/// Computes and returns the final result. Will be called exactly once for
|
||||||
/// invocation of the function. If `step()` was called at least once, will be given
|
/// each invocation of the function. If `step()` was called at least
|
||||||
/// `Some(A)` (the same `A` as was created by `init` and given to `step`); if `step()`
|
/// once, will be given `Some(A)` (the same `A` as was created by
|
||||||
/// was not called (because the function is running against 0 rows), will be given
|
/// `init` and given to `step`); if `step()` was not called (because
|
||||||
/// `None`.
|
/// the function is running against 0 rows), will be given `None`.
|
||||||
fn finalize(&self, Option<A>) -> Result<T>;
|
fn finalize(&self, Option<A>) -> Result<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,9 +199,9 @@ impl Connection {
|
|||||||
/// Attach a user-defined scalar function to this database connection.
|
/// Attach a user-defined scalar function to this database connection.
|
||||||
///
|
///
|
||||||
/// `fn_name` is the name the function will be accessible from SQL.
|
/// `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
|
/// `n_arg` is the number of arguments to the function. Use `-1` for a
|
||||||
/// number. If the function always returns the same value given the same
|
/// variable number. If the function always returns the same value
|
||||||
/// input, `deterministic` should be `true`.
|
/// given the same input, `deterministic` should be `true`.
|
||||||
///
|
///
|
||||||
/// The function will remain available until the connection is closed or
|
/// The function will remain available until the connection is closed or
|
||||||
/// until it is explicitly removed via `remove_function`.
|
/// until it is explicitly removed via `remove_function`.
|
||||||
|
14
src/hooks.rs
14
src/hooks.rs
@ -91,7 +91,8 @@ impl From<i32> for Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
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.
|
/// The callback returns `true` to rollback.
|
||||||
pub fn commit_hook<F>(&self, hook: Option<F>)
|
pub fn commit_hook<F>(&self, hook: Option<F>)
|
||||||
@ -101,7 +102,8 @@ impl Connection {
|
|||||||
self.db.borrow_mut().commit_hook(hook);
|
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.
|
/// The callback returns `true` to rollback.
|
||||||
pub fn rollback_hook<F>(&self, hook: Option<F>)
|
pub fn rollback_hook<F>(&self, hook: Option<F>)
|
||||||
@ -116,7 +118,8 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// The callback parameters are:
|
/// The callback parameters are:
|
||||||
///
|
///
|
||||||
/// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE),
|
/// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or
|
||||||
|
/// SQLITE_DELETE),
|
||||||
/// - the name of the database ("main", "temp", ...),
|
/// - the name of the database ("main", "temp", ...),
|
||||||
/// - the name of the table that is updated,
|
/// - the name of the table that is updated,
|
||||||
/// - the ROWID of the row that is updated.
|
/// - the ROWID of the row that is updated.
|
||||||
@ -151,8 +154,9 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unlike `sqlite3_create_function_v2`, we cannot specify a `xDestroy` with `sqlite3_commit_hook`.
|
// unlike `sqlite3_create_function_v2`, we cannot specify a `xDestroy` with
|
||||||
// so we keep the `xDestroy` function in `InnerConnection.free_boxed_hook`.
|
// `sqlite3_commit_hook`. so we keep the `xDestroy` function in
|
||||||
|
// `InnerConnection.free_boxed_hook`.
|
||||||
let free_commit_hook = if hook.is_some() {
|
let free_commit_hook = if hook.is_some() {
|
||||||
Some(free_boxed_hook::<F> as fn(*mut c_void))
|
Some(free_boxed_hook::<F> as fn(*mut c_void))
|
||||||
} else {
|
} else {
|
||||||
|
279
src/lib.rs
279
src/lib.rs
@ -1,48 +1,54 @@
|
|||||||
//! Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
|
//! Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to
|
||||||
//! an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres).
|
//! expose an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres).
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! extern crate rusqlite;
|
//! extern crate rusqlite;
|
||||||
//! extern crate time;
|
//! extern crate time;
|
||||||
//!
|
//!
|
||||||
//! use time::Timespec;
|
|
||||||
//! use rusqlite::Connection;
|
//! use rusqlite::Connection;
|
||||||
|
//! use time::Timespec;
|
||||||
//!
|
//!
|
||||||
//! #[derive(Debug)]
|
//! #[derive(Debug)]
|
||||||
//! struct Person {
|
//! struct Person {
|
||||||
//! id: i32,
|
//! id: i32,
|
||||||
//! name: String,
|
//! name: String,
|
||||||
//! time_created: Timespec,
|
//! time_created: Timespec,
|
||||||
//! data: Option<Vec<u8>>
|
//! data: Option<Vec<u8>>,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let conn = Connection::open_in_memory().unwrap();
|
//! let conn = Connection::open_in_memory().unwrap();
|
||||||
//!
|
//!
|
||||||
//! conn.execute("CREATE TABLE person (
|
//! conn.execute(
|
||||||
|
//! "CREATE TABLE person (
|
||||||
//! id INTEGER PRIMARY KEY,
|
//! id INTEGER PRIMARY KEY,
|
||||||
//! name TEXT NOT NULL,
|
//! name TEXT NOT NULL,
|
||||||
//! time_created TEXT NOT NULL,
|
//! time_created TEXT NOT NULL,
|
||||||
//! data BLOB
|
//! data BLOB
|
||||||
//! )", &[]).unwrap();
|
//! )",
|
||||||
|
//! &[],
|
||||||
|
//! ).unwrap();
|
||||||
//! let me = Person {
|
//! let me = Person {
|
||||||
//! id: 0,
|
//! id: 0,
|
||||||
//! name: "Steven".to_string(),
|
//! name: "Steven".to_string(),
|
||||||
//! time_created: time::get_time(),
|
//! 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)",
|
//! 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 mut stmt = conn
|
||||||
//! let person_iter = stmt.query_map(&[], |row| {
|
//! .prepare("SELECT id, name, time_created, data FROM person")
|
||||||
//! Person {
|
//! .unwrap();
|
||||||
|
//! let person_iter = stmt
|
||||||
|
//! .query_map(&[], |row| Person {
|
||||||
//! id: row.get(0),
|
//! id: row.get(0),
|
||||||
//! name: row.get(1),
|
//! name: row.get(1),
|
||||||
//! time_created: row.get(2),
|
//! time_created: row.get(2),
|
||||||
//! data: row.get(3)
|
//! data: row.get(3),
|
||||||
//! }
|
|
||||||
//! }).unwrap();
|
//! }).unwrap();
|
||||||
//!
|
//!
|
||||||
//! for person in person_iter {
|
//! for person in person_iter {
|
||||||
@ -168,8 +174,8 @@ pub enum DatabaseName<'a> {
|
|||||||
Attached(&'a str),
|
Attached(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently DatabaseName is only used by the backup and blob mods, so hide this (private)
|
// Currently DatabaseName is only used by the backup and blob mods, so hide
|
||||||
// impl to avoid dead code warnings.
|
// this (private) impl to avoid dead code warnings.
|
||||||
#[cfg(any(feature = "backup", feature = "blob"))]
|
#[cfg(any(feature = "backup", feature = "blob"))]
|
||||||
impl<'a> DatabaseName<'a> {
|
impl<'a> DatabaseName<'a> {
|
||||||
fn to_cstring(&self) -> Result<CString> {
|
fn to_cstring(&self) -> Result<CString> {
|
||||||
@ -204,13 +210,15 @@ impl Drop for Connection {
|
|||||||
impl Connection {
|
impl Connection {
|
||||||
/// Open a new connection to a SQLite database.
|
/// Open a new connection to a SQLite database.
|
||||||
///
|
///
|
||||||
/// `Connection::open(path)` is equivalent to `Connection::open_with_flags(path,
|
/// `Connection::open(path)` is equivalent to
|
||||||
/// OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE)`.
|
/// `Connection::open_with_flags(path,
|
||||||
|
/// OpenFlags::SQLITE_OPEN_READ_WRITE |
|
||||||
|
/// OpenFlags::SQLITE_OPEN_CREATE)`.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `path` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `path` cannot be converted to a C-compatible
|
||||||
/// underlying SQLite open call fails.
|
/// string or if the underlying SQLite open call fails.
|
||||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
|
||||||
let flags = OpenFlags::default();
|
let flags = OpenFlags::default();
|
||||||
Connection::open_with_flags(path, flags)
|
Connection::open_with_flags(path, flags)
|
||||||
@ -233,8 +241,8 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `path` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `path` cannot be converted to a C-compatible
|
||||||
/// underlying SQLite open call fails.
|
/// string or if the underlying SQLite open call fails.
|
||||||
pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
|
pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
|
||||||
let c_path = try!(path_to_cstring(path.as_ref()));
|
let c_path = try!(path_to_cstring(path.as_ref()));
|
||||||
InnerConnection::open_with_flags(&c_path, flags).map(|db| Connection {
|
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.
|
/// Uses [sqlite3_exec](http://www.sqlite.org/c3ref/exec.html) under the hood.
|
||||||
///
|
///
|
||||||
@ -270,25 +279,27 @@ impl Connection {
|
|||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{Connection, Result};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// fn create_tables(conn: &Connection) -> Result<()> {
|
/// fn create_tables(conn: &Connection) -> Result<()> {
|
||||||
/// conn.execute_batch("BEGIN;
|
/// conn.execute_batch(
|
||||||
|
/// "BEGIN;
|
||||||
/// CREATE TABLE foo(x INTEGER);
|
/// CREATE TABLE foo(x INTEGER);
|
||||||
/// CREATE TABLE bar(y TEXT);
|
/// CREATE TABLE bar(y TEXT);
|
||||||
/// COMMIT;")
|
/// COMMIT;",
|
||||||
|
/// )
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn execute_batch(&self, sql: &str) -> Result<()> {
|
pub fn execute_batch(&self, sql: &str) -> Result<()> {
|
||||||
self.db.borrow_mut().execute_batch(sql)
|
self.db.borrow_mut().execute_batch(sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method to prepare and execute a single SQL statement.
|
/// 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
|
/// On success, returns the number of rows that were changed or inserted or
|
||||||
/// `sqlite3_changes`).
|
/// deleted (via `sqlite3_changes`).
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -304,30 +315,34 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn execute(&self, sql: &str, params: &[&ToSql]) -> Result<usize> {
|
pub fn execute(&self, sql: &str, params: &[&ToSql]) -> Result<usize> {
|
||||||
self.prepare(sql).and_then(|mut stmt| stmt.execute(params))
|
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
|
/// On success, returns the number of rows that were changed or inserted or
|
||||||
/// `sqlite3_changes`).
|
/// deleted (via `sqlite3_changes`).
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{Connection, Result};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// fn insert(conn: &Connection) -> Result<usize> {
|
/// 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
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> Result<usize> {
|
pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> Result<usize> {
|
||||||
self.prepare(sql)
|
self.prepare(sql)
|
||||||
.and_then(|mut stmt| stmt.execute_named(params))
|
.and_then(|mut stmt| stmt.execute_named(params))
|
||||||
@ -341,25 +356,29 @@ impl Connection {
|
|||||||
self.db.borrow_mut().last_insert_rowid()
|
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
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{Result,Connection};
|
/// # use rusqlite::{Result,Connection};
|
||||||
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
||||||
/// conn.query_row("SELECT value FROM preferences WHERE name='locale'", &[], |row| {
|
/// conn.query_row(
|
||||||
/// row.get(0)
|
/// "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
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
|
pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
|
||||||
where
|
where
|
||||||
F: FnOnce(&Row) -> T,
|
F: FnOnce(&Row) -> T,
|
||||||
@ -368,15 +387,16 @@ impl Connection {
|
|||||||
stmt.query_row(params, f)
|
stmt.query_row(params, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method to execute a query with named parameter(s) that is expected to return
|
/// Convenience method to execute a query with named parameter(s) that is
|
||||||
/// a single row.
|
/// 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
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &ToSql)], f: F) -> Result<T>
|
pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &ToSql)], f: F) -> Result<T>
|
||||||
where
|
where
|
||||||
F: FnOnce(&Row) -> T,
|
F: FnOnce(&Row) -> T,
|
||||||
@ -387,29 +407,31 @@ impl Connection {
|
|||||||
rows.get_expected_row().map(|r| f(&r))
|
rows.get_expected_row().map(|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
|
||||||
/// and execute a mapping via `f` on that returned row with the possibility of failure.
|
/// single row, and execute a mapping via `f` on that returned row with
|
||||||
/// The `Result` type of `f` must implement `std::convert::From<Error>`.
|
/// the possibility of failure. The `Result` type of `f` must implement
|
||||||
|
/// `std::convert::From<Error>`.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{Result,Connection};
|
/// # use rusqlite::{Result,Connection};
|
||||||
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
||||||
/// conn.query_row_and_then("SELECT value FROM preferences WHERE name='locale'",
|
/// conn.query_row_and_then(
|
||||||
|
/// "SELECT value FROM preferences WHERE name='locale'",
|
||||||
/// &[],
|
/// &[],
|
||||||
/// |row| {
|
/// |row| row.get_checked(0),
|
||||||
/// 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
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn query_row_and_then<T, E, F>(
|
pub fn query_row_and_then<T, E, F>(
|
||||||
&self,
|
&self,
|
||||||
sql: &str,
|
sql: &str,
|
||||||
@ -426,25 +448,29 @@ impl Connection {
|
|||||||
rows.get_expected_row().map_err(E::from).and_then(|r| f(&r))
|
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
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{Result,Connection};
|
/// # use rusqlite::{Result,Connection};
|
||||||
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
/// fn preferred_locale(conn: &Connection) -> Result<String> {
|
||||||
/// conn.query_row_safe("SELECT value FROM preferences WHERE name='locale'", &[], |row| {
|
/// conn.query_row_safe(
|
||||||
/// row.get(0)
|
/// "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
|
/// ## Deprecated
|
||||||
///
|
///
|
||||||
/// This method should be considered deprecated. Use `query_row` instead, which now
|
/// This method should be considered deprecated. Use `query_row` instead,
|
||||||
/// does exactly the same thing.
|
/// which now does exactly the same thing.
|
||||||
#[deprecated(since = "0.1.0", note = "Use query_row instead")]
|
#[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>
|
pub fn query_row_safe<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
|
||||||
where
|
where
|
||||||
@ -469,17 +495,17 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>> {
|
pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>> {
|
||||||
self.db.borrow_mut().prepare(self, sql)
|
self.db.borrow_mut().prepare(self, sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Close the SQLite connection.
|
/// Close the SQLite connection.
|
||||||
///
|
///
|
||||||
/// This is functionally equivalent to the `Drop` implementation for `Connection` except
|
/// This is functionally equivalent to the `Drop` implementation for
|
||||||
/// that on failure, it returns an error and the connection itself (presumably so closing
|
/// `Connection` except that on failure, it returns an error and the
|
||||||
/// can be attempted again).
|
/// connection itself (presumably so closing can be attempted again).
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -490,8 +516,8 @@ impl Connection {
|
|||||||
r.map_err(move |err| (self, err))
|
r.map_err(move |err| (self, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable loading of SQLite extensions. Strongly consider using `LoadExtensionGuard`
|
/// Enable loading of SQLite extensions. Strongly consider using
|
||||||
/// instead of this function.
|
/// `LoadExtensionGuard` instead of this function.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -525,12 +551,13 @@ impl Connection {
|
|||||||
self.db.borrow_mut().enable_load_extension(0)
|
self.db.borrow_mut().enable_load_extension(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load the SQLite extension at `dylib_path`. `dylib_path` is passed through to
|
/// Load the SQLite extension at `dylib_path`. `dylib_path` is passed
|
||||||
/// `sqlite3_load_extension`, which may attempt OS-specific modifications if the file
|
/// through to `sqlite3_load_extension`, which may attempt OS-specific
|
||||||
/// cannot be loaded directly.
|
/// 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
|
/// If `entry_point` is `None`, SQLite will attempt to find the entry
|
||||||
/// `None`, the entry point will be passed through to `sqlite3_load_extension`.
|
/// point. If it is not `None`, the entry point will be passed through
|
||||||
|
/// to `sqlite3_load_extension`.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -562,10 +589,11 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// # Warning
|
/// # Warning
|
||||||
///
|
///
|
||||||
/// You should not need to use this function. If you do need to, please [open an issue
|
/// You should not need to use this function. If you do need to, please
|
||||||
/// on the rusqlite repository](https://github.com/jgallagher/rusqlite/issues) and describe
|
/// [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
|
/// your use case. This function is unsafe because it gives you raw access
|
||||||
/// connection, and what you do with it could impact the safety of this `Connection`.
|
/// 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 {
|
pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
|
||||||
self.db.borrow().db()
|
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_SQLITE_INIT: AtomicBool = ATOMIC_BOOL_INIT;
|
||||||
static BYPASS_VERSION_CHECK: 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
|
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or
|
||||||
/// running against a SQLite older than that, rusqlite attempts to ensure safety by performing
|
/// later. If you are running against a SQLite older than that, rusqlite
|
||||||
/// configuration and initialization of SQLite itself the first time you attempt to open a
|
/// attempts to ensure safety by performing configuration and initialization of
|
||||||
/// connection. By default, rusqlite panics if that initialization fails, since that could mean
|
/// SQLite itself the first time you
|
||||||
/// SQLite has been initialized in single-thread mode.
|
/// 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
|
/// If you are encountering that panic _and_ can ensure that SQLite has been
|
||||||
/// multi-thread or serialized mode, call this function prior to attempting to open a connection
|
/// initialized in either multi-thread or serialized mode, call this function
|
||||||
/// and rusqlite's initialization process will by skipped. This function is unsafe because if you
|
/// prior to attempting to open a connection and rusqlite's initialization
|
||||||
/// call it and SQLite has actually been configured to run in single-thread mode, you may enounter
|
/// process will by skipped. This
|
||||||
/// memory errors or data corruption or any number of terrible things that should not be possible
|
/// function is unsafe because if you call it and SQLite has actually been
|
||||||
/// when you're using Rust.
|
/// 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() {
|
pub unsafe fn bypass_sqlite_initialization() {
|
||||||
BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
|
BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// rusqlite performs a one-time check that the runtime SQLite version is at least as new as
|
/// rusqlite performs a one-time check that the runtime SQLite version is at
|
||||||
/// the version of SQLite found when rusqlite was built. Bypassing this check may be dangerous;
|
/// least as new as the version of SQLite found when rusqlite was built.
|
||||||
/// e.g., if you use features of SQLite that are not present in the runtime version. If you are
|
/// Bypassing this check may be dangerous; e.g., if you use features of SQLite
|
||||||
/// sure the runtime version is compatible with the build-time version for your usage, you can
|
/// that are not present in the runtime
|
||||||
/// bypass the version check by calling this function before your first connection attempt.
|
/// 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() {
|
pub unsafe fn bypass_sqlite_version_check() {
|
||||||
BYPASS_VERSION_CHECK.store(true, Ordering::Relaxed);
|
BYPASS_VERSION_CHECK.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
@ -693,8 +728,8 @@ fn ensure_valid_sqlite_version() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the runtime version number is compatible with the version number we found at
|
// Check that the runtime version number is compatible with the version number
|
||||||
// build-time.
|
// we found at build-time.
|
||||||
if version_number < ffi::SQLITE_VERSION_NUMBER {
|
if version_number < ffi::SQLITE_VERSION_NUMBER {
|
||||||
panic!(
|
panic!(
|
||||||
"\
|
"\
|
||||||
@ -716,21 +751,23 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> {
|
|||||||
return Err(Error::SqliteSingleThreadedMode);
|
return Err(Error::SqliteSingleThreadedMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode, but it's
|
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode,
|
||||||
// possible someone configured it to be in Single-thread mode before calling into us. That
|
// but it's possible someone configured it to be in Single-thread mode
|
||||||
// would mean we're exposing an unsafe API via a safe one (in Rust terminology), which is
|
// before calling into us. That would mean we're exposing an unsafe API via
|
||||||
// no good. We have two options to protect against this, depending on the version of SQLite
|
// a safe one (in Rust terminology), which is no good. We have two options
|
||||||
// we're linked with:
|
// 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
|
// 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for
|
||||||
// 8. This isn't documented, but it's what SQLite returns for its mutex allocation function
|
// the magic value 8. This isn't documented, but it's what SQLite
|
||||||
// in Single-thread mode.
|
// 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
|
// 2. If we're prior to SQLite 3.7.0, AFAIK there's no way to check the
|
||||||
// check we perform for >= 3.7.0 will segfault. Instead, we insist on being able to call
|
// threading mode. The check we perform for >= 3.7.0 will segfault.
|
||||||
// sqlite3_config and sqlite3_initialize ourself, ensuring we know the threading mode. This
|
// Instead, we insist on being able to call sqlite3_config and
|
||||||
// will fail if someone else has already initialized SQLite even if they initialized it
|
// sqlite3_initialize ourself, ensuring we know the threading
|
||||||
// safely. That's not ideal either, which is why we expose bypass_sqlite_initialization
|
// mode. This will fail if someone else has already initialized SQLite
|
||||||
// above.
|
// 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 {
|
if version_number() >= 3_007_000 {
|
||||||
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
||||||
let is_singlethreaded = unsafe {
|
let is_singlethreaded = unsafe {
|
||||||
@ -775,6 +812,7 @@ impl InnerConnection {
|
|||||||
fn new(db: *mut ffi::sqlite3) -> InnerConnection {
|
fn new(db: *mut ffi::sqlite3) -> InnerConnection {
|
||||||
InnerConnection { db }
|
InnerConnection { db }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "hooks")]
|
#[cfg(feature = "hooks")]
|
||||||
fn new(db: *mut ffi::sqlite3) -> InnerConnection {
|
fn new(db: *mut ffi::sqlite3) -> InnerConnection {
|
||||||
InnerConnection {
|
InnerConnection {
|
||||||
@ -789,8 +827,8 @@ impl InnerConnection {
|
|||||||
ensure_valid_sqlite_version();
|
ensure_valid_sqlite_version();
|
||||||
ensure_safe_sqlite_threading_mode()?;
|
ensure_safe_sqlite_threading_mode()?;
|
||||||
|
|
||||||
// Replicate the check for sane open flags from SQLite, because the check in SQLite itself
|
// Replicate the check for sane open flags from SQLite, because the check in
|
||||||
// wasn't added until version 3.7.3.
|
// 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_ONLY.bits, 0x02);
|
||||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits, 0x04);
|
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits, 0x04);
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
@ -1105,8 +1143,9 @@ mod test {
|
|||||||
fn test_close_retry() {
|
fn test_close_retry() {
|
||||||
let db = checked_memory_handle();
|
let db = checked_memory_handle();
|
||||||
|
|
||||||
// force the DB to be busy by preparing a statement; this must be done at the FFI
|
// force the DB to be busy by preparing a statement; this must be done at the
|
||||||
// level to allow us to call .close() without dropping the prepared statement first.
|
// FFI level to allow us to call .close() without dropping the prepared
|
||||||
|
// statement first.
|
||||||
let raw_stmt = {
|
let raw_stmt = {
|
||||||
use super::str_to_cstring;
|
use super::str_to_cstring;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@ -1129,7 +1168,8 @@ mod test {
|
|||||||
raw_stmt
|
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();
|
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 {
|
fn description(&self) -> &str {
|
||||||
"my custom error"
|
"my custom error"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self) -> Option<&StdError> {
|
fn cause(&self) -> Option<&StdError> {
|
||||||
match *self {
|
match *self {
|
||||||
CustomError::SomeError => None,
|
CustomError::SomeError => None,
|
||||||
|
@ -22,8 +22,9 @@ pub struct LoadExtensionGuard<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn> LoadExtensionGuard<'conn> {
|
impl<'conn> LoadExtensionGuard<'conn> {
|
||||||
/// Attempt to enable loading extensions. Loading extensions will be disabled when this
|
/// Attempt to enable loading extensions. Loading extensions will be
|
||||||
/// guard goes out of scope. Cannot be meaningfully nested.
|
/// disabled when this guard goes out of scope. Cannot be meaningfully
|
||||||
|
/// nested.
|
||||||
pub fn new(conn: &Connection) -> Result<LoadExtensionGuard> {
|
pub fn new(conn: &Connection) -> Result<LoadExtensionGuard> {
|
||||||
conn.load_extension_enable()
|
conn.load_extension_enable()
|
||||||
.map(|_| LoadExtensionGuard { conn })
|
.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
|
/// Attempt to get the next row from the query. Returns `Some(Ok(Row))` if
|
||||||
/// is another row, `Some(Err(...))` if there was an error getting the next
|
/// there is another row, `Some(Err(...))` if there was an error
|
||||||
/// row, and `None` if all rows have been retrieved.
|
/// getting the next row, and `None` if all rows have been retrieved.
|
||||||
///
|
///
|
||||||
/// ## Note
|
/// ## Note
|
||||||
///
|
///
|
||||||
/// This interface is not compatible with Rust's `Iterator` trait, because the
|
/// This interface is not compatible with Rust's `Iterator` trait, because
|
||||||
/// lifetime of the returned row is tied to the lifetime of `self`. This is a
|
/// the lifetime of the returned row is tied to the lifetime of `self`.
|
||||||
/// "streaming iterator". For a more natural interface, consider using `query_map`
|
/// This is a "streaming iterator". For a more natural interface,
|
||||||
/// or `query_and_then` instead, which return types that implement `Iterator`.
|
/// 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
|
#[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))] // cannot implement Iterator
|
||||||
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
|
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
|
||||||
self.stmt.and_then(|stmt| match stmt.step() {
|
self.stmt.and_then(|stmt| match stmt.step() {
|
||||||
@ -135,11 +136,15 @@ impl<'a, 'stmt> Row<'a, 'stmt> {
|
|||||||
///
|
///
|
||||||
/// ## Failure
|
/// ## 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 column type is not a valid type as a
|
||||||
/// * If the underlying SQLite integral value is outside the range representable by `T`
|
/// source for `T`
|
||||||
/// * If `idx` is outside the range of columns in the returned query
|
/// * 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 {
|
pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
|
||||||
self.get_checked(idx).unwrap()
|
self.get_checked(idx).unwrap()
|
||||||
}
|
}
|
||||||
@ -151,11 +156,11 @@ impl<'a, 'stmt> Row<'a, 'stmt> {
|
|||||||
/// Returns an `Error::InvalidColumnType` if the underlying SQLite column
|
/// Returns an `Error::InvalidColumnType` if the underlying SQLite column
|
||||||
/// type is not a valid type as a source for `T`.
|
/// type is not a valid type as a source for `T`.
|
||||||
///
|
///
|
||||||
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid column range
|
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid
|
||||||
/// for this row.
|
/// column range for this row.
|
||||||
///
|
///
|
||||||
/// Returns an `Error::InvalidColumnName` if `idx` is not a valid column name
|
/// Returns an `Error::InvalidColumnName` if `idx` is not a valid column
|
||||||
/// for this row.
|
/// name for this row.
|
||||||
pub fn get_checked<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
|
pub fn get_checked<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
|
||||||
let idx = try!(idx.idx(self.stmt));
|
let idx = try!(idx.idx(self.stmt));
|
||||||
let value = self.stmt.value_ref(idx);
|
let value = self.stmt.value_ref(idx);
|
||||||
|
121
src/statement.rs
121
src/statement.rs
@ -33,19 +33,21 @@ impl<'conn> Statement<'conn> {
|
|||||||
cols
|
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 {
|
pub fn column_count(&self) -> usize {
|
||||||
self.stmt.column_count()
|
self.stmt.column_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the column index in the result set for a given column name.
|
/// 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
|
/// If there is no AS clause then the name of the column is unspecified and
|
||||||
/// release of SQLite to the next.
|
/// may change from one release of SQLite to the next.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # 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> {
|
pub fn column_index(&self, name: &str) -> Result<usize> {
|
||||||
let bytes = name.as_bytes();
|
let bytes = name.as_bytes();
|
||||||
let n = self.column_count();
|
let n = self.column_count();
|
||||||
@ -59,8 +61,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
|
|
||||||
/// Execute the prepared statement.
|
/// Execute the prepared statement.
|
||||||
///
|
///
|
||||||
/// On success, returns the number of rows that were changed or inserted or deleted (via
|
/// On success, returns the number of rows that were changed or inserted or
|
||||||
/// `sqlite3_changes`).
|
/// deleted (via `sqlite3_changes`).
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -78,20 +80,22 @@ impl<'conn> Statement<'conn> {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if binding parameters fails, the executed statement returns rows (in
|
/// Will return `Err` if binding parameters fails, the executed statement
|
||||||
/// which case `query` should be used instead), or the underling SQLite call fails.
|
/// 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> {
|
pub fn execute(&mut self, params: &[&ToSql]) -> Result<usize> {
|
||||||
try!(self.bind_parameters(params));
|
try!(self.bind_parameters(params));
|
||||||
self.execute_with_bound_parameters()
|
self.execute_with_bound_parameters()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the prepared statement with named parameter(s). If any parameters
|
/// Execute the prepared statement with named parameter(s). If any
|
||||||
/// that were in the prepared statement are not included in `params`, they
|
/// parameters that were in the prepared statement are not included in
|
||||||
/// will continue to use the most-recently bound value from a previous call
|
/// `params`, they will continue to use the most-recently bound value
|
||||||
/// to `execute_named`, or `NULL` if they have never been bound.
|
/// 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
|
/// On success, returns the number of rows that were changed or inserted or
|
||||||
/// `sqlite3_changes`).
|
/// deleted (via `sqlite3_changes`).
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -105,8 +109,9 @@ impl<'conn> Statement<'conn> {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if binding parameters fails, the executed statement returns rows (in
|
/// Will return `Err` if binding parameters fails, the executed statement
|
||||||
/// which case `query` should be used instead), or the underling SQLite call fails.
|
/// 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> {
|
pub fn execute_named(&mut self, params: &[(&str, &ToSql)]) -> Result<usize> {
|
||||||
try!(self.bind_parameters_named(params));
|
try!(self.bind_parameters_named(params));
|
||||||
self.execute_with_bound_parameters()
|
self.execute_with_bound_parameters()
|
||||||
@ -116,10 +121,11 @@ impl<'conn> Statement<'conn> {
|
|||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// This function is a convenience wrapper around `execute()` intended for queries that
|
/// This function is a convenience wrapper around `execute()` intended for
|
||||||
/// insert a single item. It is possible to misuse this function in a way that it cannot
|
/// queries that insert a single item. It is possible to misuse this
|
||||||
/// detect, such as by calling it on a statement which _updates_ a single item rather than
|
/// function in a way that it cannot detect, such as by calling it on a
|
||||||
/// inserting one. Please don't do that.
|
/// statement which _updates_ a single
|
||||||
|
/// item rather than inserting one. Please don't do that.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # 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
|
/// Due to lifetime restricts, the rows handle returned by `query` does not
|
||||||
/// implement the `Iterator` trait. Consider using `query_map` or `query_and_then`
|
/// implement the `Iterator` trait. Consider using `query_map` or
|
||||||
/// instead, which do.
|
/// `query_and_then` instead, which do.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -165,10 +172,11 @@ impl<'conn> Statement<'conn> {
|
|||||||
Ok(Rows::new(self))
|
Ok(Rows::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the prepared statement with named parameter(s), returning a handle for the
|
/// Execute the prepared statement with named parameter(s), returning a
|
||||||
/// resulting rows. If any parameters that were in the prepared statement are not included in
|
/// handle for the resulting rows. If any parameters that were in the
|
||||||
/// `params`, they will continue to use the most-recently bound value from a previous call to
|
/// prepared statement are not included in `params`, they will continue
|
||||||
/// `query_named`, or `NULL` if they have never been bound.
|
/// to use the most-recently bound value from a previous
|
||||||
|
/// call to `query_named`, or `NULL` if they have never been bound.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -193,8 +201,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
Ok(Rows::new(self))
|
Ok(Rows::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the prepared statement and maps a function over the resulting rows, returning
|
/// Executes the prepared statement and maps a function over the resulting
|
||||||
/// an iterator over the mapped function results.
|
/// rows, returning an iterator over the mapped function results.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -224,11 +232,12 @@ impl<'conn> Statement<'conn> {
|
|||||||
Ok(MappedRows::new(rows, f))
|
Ok(MappedRows::new(rows, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the prepared statement with named parameter(s), returning an iterator over the
|
/// Execute the prepared statement with named parameter(s), returning an
|
||||||
/// result of calling the mapping function over the query's rows. If any parameters that were
|
/// iterator over the result of calling the mapping function over the
|
||||||
/// in the prepared statement are not included in `params`, they will continue to use the
|
/// query's rows. If any parameters that were in the prepared statement
|
||||||
/// most-recently bound value from a previous call to `query_named`, or `NULL` if they have
|
/// are not included in `params`, they will continue to use the
|
||||||
/// never been bound.
|
/// most-recently bound value from a previous call to `query_named`,
|
||||||
|
/// or `NULL` if they have never been bound.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -263,8 +272,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the prepared statement and maps a function over the resulting
|
/// Executes the prepared statement and maps a function over the resulting
|
||||||
/// rows, where the function returns a `Result` with `Error` type implementing
|
/// rows, where the function returns a `Result` with `Error` type
|
||||||
/// `std::convert::From<Error>` (so errors can be unified).
|
/// implementing `std::convert::From<Error>` (so errors can be unified).
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -282,28 +291,31 @@ impl<'conn> Statement<'conn> {
|
|||||||
Ok(AndThenRows::new(rows, f))
|
Ok(AndThenRows::new(rows, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the prepared statement with named parameter(s), returning an iterator over the
|
/// Execute the prepared statement with named parameter(s), returning an
|
||||||
/// result of calling the mapping function over the query's rows. If any parameters that were
|
/// iterator over the result of calling the mapping function over the
|
||||||
/// in the prepared statement are not included in `params`, they will continue to use the
|
/// query's rows. If any parameters that were in the prepared statement
|
||||||
/// most-recently bound value from a previous call to `query_named`, or `NULL` if they have
|
/// are not included in
|
||||||
/// never been bound.
|
/// `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
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{Connection, Result};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// struct Person { name: String };
|
/// struct Person {
|
||||||
|
/// name: String,
|
||||||
|
/// };
|
||||||
///
|
///
|
||||||
/// fn name_to_person(name: String) -> Result<Person> {
|
/// fn name_to_person(name: String) -> Result<Person> {
|
||||||
/// // ... check for valid name
|
/// // ... check for valid name
|
||||||
/// Ok(Person{ name: name })
|
/// Ok(Person { name: name })
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn get_names(conn: &Connection) -> Result<Vec<Person>> {
|
/// fn get_names(conn: &Connection) -> Result<Vec<Person>> {
|
||||||
/// let mut stmt = try!(conn.prepare("SELECT name FROM people WHERE id = :id"));
|
/// let mut stmt = try!(conn.prepare("SELECT name FROM people WHERE id = :id"));
|
||||||
/// let rows = try!(stmt.query_and_then_named(&[(":id", &"one")], |row| {
|
/// let rows =
|
||||||
/// name_to_person(row.get(0))
|
/// try!(stmt.query_and_then_named(&[(":id", &"one")], |row| name_to_person(row.get(0))));
|
||||||
/// }));
|
|
||||||
///
|
///
|
||||||
/// let mut persons = Vec::new();
|
/// let mut persons = Vec::new();
|
||||||
/// for person_result in rows {
|
/// for person_result in rows {
|
||||||
@ -330,8 +342,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
Ok(AndThenRows::new(rows, f))
|
Ok(AndThenRows::new(rows, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if a query in the SQL statement it executes returns one or more rows
|
/// Return `true` if a query in the SQL statement it executes returns one
|
||||||
/// and `false` if the SQL returns an empty set.
|
/// or more rows and `false` if the SQL returns an empty set.
|
||||||
pub fn exists(&mut self, params: &[&ToSql]) -> Result<bool> {
|
pub fn exists(&mut self, params: &[&ToSql]) -> Result<bool> {
|
||||||
let mut rows = try!(self.query(params));
|
let mut rows = try!(self.query(params));
|
||||||
let exists = {
|
let exists = {
|
||||||
@ -343,9 +355,11 @@ impl<'conn> Statement<'conn> {
|
|||||||
Ok(exists)
|
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
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -361,8 +375,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
|
|
||||||
/// Consumes the statement.
|
/// Consumes the statement.
|
||||||
///
|
///
|
||||||
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any errors
|
/// Functionally equivalent to the `Drop` implementation, but allows
|
||||||
/// that occur.
|
/// callers to see any errors that occur.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -514,7 +528,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
Ok(())
|
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")]
|
#[cfg(feature = "bundled")]
|
||||||
pub fn expanded_sql(&self) -> Option<&str> {
|
pub fn expanded_sql(&self) -> Option<&str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
18
src/trace.rs
18
src/trace.rs
@ -61,12 +61,12 @@ pub fn log(err_code: c_int, msg: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
/// Register or clear a callback function that can be used for tracing the execution of SQL
|
/// Register or clear a callback function that can be used for tracing the
|
||||||
/// statements.
|
/// execution of SQL statements.
|
||||||
///
|
///
|
||||||
/// Prepared statement placeholders are replaced/logged with their assigned values.
|
/// Prepared statement placeholders are replaced/logged with their assigned
|
||||||
/// There can only be a single tracer defined for each database connection.
|
/// values. There can only be a single tracer defined for each database
|
||||||
/// Setting a new tracer clears the old one.
|
/// connection. Setting a new tracer clears the old one.
|
||||||
pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
|
pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
|
||||||
unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) {
|
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);
|
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
|
/// Register or clear a callback function that can be used for profiling
|
||||||
/// statements.
|
/// the execution of SQL statements.
|
||||||
///
|
///
|
||||||
/// There can only be a single profiler defined for each database connection.
|
/// There can only be a single profiler defined for each database
|
||||||
/// Setting a new profiler clears the old one.
|
/// connection. Setting a new profiler clears the old one.
|
||||||
pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
|
pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
|
||||||
unsafe extern "C" fn profile_callback(
|
unsafe extern "C" fn profile_callback(
|
||||||
p_arg: *mut c_void,
|
p_arg: *mut c_void,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use {Connection, Result};
|
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")]
|
#[deprecated(since = "0.6.0", note = "Use TransactionBehavior instead")]
|
||||||
pub type SqliteTransactionBehavior = TransactionBehavior;
|
pub type SqliteTransactionBehavior = TransactionBehavior;
|
||||||
|
|
||||||
@ -23,8 +24,8 @@ pub enum DropBehavior {
|
|||||||
/// Commit the changes.
|
/// Commit the changes.
|
||||||
Commit,
|
Commit,
|
||||||
|
|
||||||
/// Do not commit or roll back changes - this will leave the transaction or savepoint
|
/// Do not commit or roll back changes - this will leave the transaction or
|
||||||
/// open, so should be used with care.
|
/// savepoint open, so should be used with care.
|
||||||
Ignore,
|
Ignore,
|
||||||
|
|
||||||
/// Panic. Used to enforce intentional behavior during development.
|
/// Panic. Used to enforce intentional behavior during development.
|
||||||
@ -39,9 +40,9 @@ pub type SqliteTransaction<'conn> = Transaction<'conn>;
|
|||||||
///
|
///
|
||||||
/// ## Note
|
/// ## Note
|
||||||
///
|
///
|
||||||
/// Transactions will roll back by default. Use `commit` method to explicitly commit the
|
/// Transactions will roll back by default. Use `commit` method to explicitly
|
||||||
/// transaction, or use `set_drop_behavior` to change what happens when the transaction
|
/// commit the transaction, or use `set_drop_behavior` to change what happens
|
||||||
/// is dropped.
|
/// when the transaction is dropped.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -67,9 +68,9 @@ pub struct Transaction<'conn> {
|
|||||||
///
|
///
|
||||||
/// ## Note
|
/// ## Note
|
||||||
///
|
///
|
||||||
/// Savepoints will roll back by default. Use `commit` method to explicitly commit the
|
/// Savepoints will roll back by default. Use `commit` method to explicitly
|
||||||
/// savepoint, or use `set_drop_behavior` to change what happens when the savepoint
|
/// commit the savepoint, or use `set_drop_behavior` to change what happens
|
||||||
/// is dropped.
|
/// when the savepoint is dropped.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -95,7 +96,8 @@ pub struct Savepoint<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn> Transaction<'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`
|
// Even though we don't mutate the connection, we take a `&mut Connection`
|
||||||
// so as to prevent nested or concurrent transactions on the same
|
// so as to prevent nested or concurrent transactions on the same
|
||||||
// connection.
|
// connection.
|
||||||
@ -116,7 +118,8 @@ impl<'conn> Transaction<'conn> {
|
|||||||
///
|
///
|
||||||
/// ## Note
|
/// ## Note
|
||||||
///
|
///
|
||||||
/// Just like outer level transactions, savepoint transactions rollback by default.
|
/// Just like outer level transactions, savepoint transactions rollback by
|
||||||
|
/// default.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -146,12 +149,14 @@ impl<'conn> Transaction<'conn> {
|
|||||||
Savepoint::with_depth_and_name(self.conn, 1, name)
|
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 {
|
pub fn drop_behavior(&self) -> DropBehavior {
|
||||||
self.drop_behavior
|
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) {
|
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
|
||||||
self.drop_behavior = drop_behavior
|
self.drop_behavior = drop_behavior
|
||||||
}
|
}
|
||||||
@ -176,11 +181,11 @@ impl<'conn> Transaction<'conn> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the transaction, committing or rolling back according to the current setting
|
/// Consumes the transaction, committing or rolling back according to the
|
||||||
/// (see `drop_behavior`).
|
/// current setting (see `drop_behavior`).
|
||||||
///
|
///
|
||||||
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any
|
/// Functionally equivalent to the `Drop` implementation, but allows
|
||||||
/// errors that occur.
|
/// callers to see any errors that occur.
|
||||||
pub fn finish(mut self) -> Result<()> {
|
pub fn finish(mut self) -> Result<()> {
|
||||||
self.finish_()
|
self.finish_()
|
||||||
}
|
}
|
||||||
@ -255,12 +260,14 @@ impl<'conn> Savepoint<'conn> {
|
|||||||
Savepoint::with_depth_and_name(self.conn, self.depth + 1, name)
|
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 {
|
pub fn drop_behavior(&self) -> DropBehavior {
|
||||||
self.drop_behavior
|
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) {
|
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
|
||||||
self.drop_behavior = drop_behavior
|
self.drop_behavior = drop_behavior
|
||||||
}
|
}
|
||||||
@ -280,18 +287,18 @@ impl<'conn> Savepoint<'conn> {
|
|||||||
///
|
///
|
||||||
/// ## Note
|
/// ## Note
|
||||||
///
|
///
|
||||||
/// Unlike `Transaction`s, savepoints remain active after they have been rolled back,
|
/// Unlike `Transaction`s, savepoints remain active after they have been
|
||||||
/// and can be rolled back again or committed.
|
/// rolled back, and can be rolled back again or committed.
|
||||||
pub fn rollback(&mut self) -> Result<()> {
|
pub fn rollback(&mut self) -> Result<()> {
|
||||||
self.conn
|
self.conn
|
||||||
.execute_batch(&format!("ROLLBACK TO {}", self.name))
|
.execute_batch(&format!("ROLLBACK TO {}", self.name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the savepoint, committing or rolling back according to the current setting
|
/// Consumes the savepoint, committing or rolling back according to the
|
||||||
/// (see `drop_behavior`).
|
/// current setting (see `drop_behavior`).
|
||||||
///
|
///
|
||||||
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any
|
/// Functionally equivalent to the `Drop` implementation, but allows
|
||||||
/// errors that occur.
|
/// callers to see any errors that occur.
|
||||||
pub fn finish(mut self) -> Result<()> {
|
pub fn finish(mut self) -> Result<()> {
|
||||||
self.finish_()
|
self.finish_()
|
||||||
}
|
}
|
||||||
@ -327,8 +334,9 @@ impl<'conn> Drop for Savepoint<'conn> {
|
|||||||
impl Connection {
|
impl Connection {
|
||||||
/// Begin a new transaction with the default behavior (DEFERRED).
|
/// 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
|
/// The transaction defaults to rolling back when it is dropped. If you
|
||||||
/// commit, you must call `commit` or `set_drop_behavior(DropBehavior::Commit)`.
|
/// want the transaction to commit, you must call `commit` or
|
||||||
|
/// `set_drop_behavior(DropBehavior::Commit)`.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -369,8 +377,9 @@ impl Connection {
|
|||||||
|
|
||||||
/// Begin a new savepoint with the default behavior (DEFERRED).
|
/// 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
|
/// The savepoint defaults to rolling back when it is dropped. If you want
|
||||||
/// commit, you must call `commit` or `set_drop_behavior(DropBehavior::Commit)`.
|
/// the savepoint to commit, you must call `commit` or
|
||||||
|
/// `set_drop_behavior(DropBehavior::Commit)`.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## 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 {
|
impl ToSql for NaiveDateTime {
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||||
let date_str = self.format("%Y-%m-%dT%H:%M:%S%.f").to_string();
|
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
|
/// "YYYY-MM-DD HH:MM:SS"/"YYYY-MM-DD HH:MM:SS.SSS" => ISO 8601 combined date
|
||||||
/// without timezone. ("YYYY-MM-DDTHH:MM:SS"/"YYYY-MM-DDTHH:MM:SS.SSS" also supported)
|
/// and time without timezone. ("YYYY-MM-DDTHH:MM:SS"/"YYYY-MM-DDTHH:MM:SS.SSS"
|
||||||
|
/// also supported)
|
||||||
impl FromSql for NaiveDateTime {
|
impl FromSql for NaiveDateTime {
|
||||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||||
value.as_str().and_then(|s| {
|
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> {
|
impl<Tz: TimeZone> ToSql for DateTime<Tz> {
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||||
Ok(ToSqlOutput::from(self.with_timezone(&Utc).to_rfc3339()))
|
Ok(ToSqlOutput::from(self.with_timezone(&Utc).to_rfc3339()))
|
||||||
|
@ -5,11 +5,12 @@ use std::fmt;
|
|||||||
/// Enum listing possible errors from `FromSql` trait.
|
/// Enum listing possible errors from `FromSql` trait.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FromSqlError {
|
pub enum FromSqlError {
|
||||||
/// Error when an SQLite value is requested, but the type of the result cannot be converted to
|
/// Error when an SQLite value is requested, but the type of the result
|
||||||
/// the requested Rust type.
|
/// cannot be converted to the requested Rust type.
|
||||||
InvalidType,
|
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),
|
OutOfRange(i64),
|
||||||
|
|
||||||
/// An error case available for implementors of the `FromSql` trait.
|
/// 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.
|
/// 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`.
|
/// Note that `FromSql` and `ToSql` are defined for most integral types, but
|
||||||
/// This is intentional; SQLite returns integers as signed 64-bit values, which cannot fully
|
/// not `u64` or `usize`. This is intentional; SQLite returns integers as
|
||||||
/// represent the range of these types. Rusqlite would have to decide how to handle negative
|
/// signed 64-bit values, which cannot fully represent the range of these
|
||||||
/// values: return an error or reinterpret as a very large postive numbers, neither of which is
|
/// types. Rusqlite would have to
|
||||||
/// guaranteed to be correct for everyone. Callers can work around this by fetching values as i64
|
/// decide how to handle negative values: return an error or reinterpret as a
|
||||||
/// and then doing the interpretation themselves or by defining a newtype and implementing
|
/// very large postive numbers, neither of which
|
||||||
/// `FromSql`/`ToSql` for it.
|
/// 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 {
|
pub trait FromSql: Sized {
|
||||||
fn column_result(value: ValueRef) -> FromSqlResult<Self>;
|
fn column_result(value: ValueRef) -> FromSqlResult<Self>;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
//! Traits dealing with SQLite data types.
|
//! Traits dealing with SQLite data types.
|
||||||
//!
|
//!
|
||||||
//! SQLite uses a [dynamic type system](https://www.sqlite.org/datatype3.html). Implementations of
|
//! 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
|
//! the `ToSql` and `FromSql` traits are provided for the basic types that
|
||||||
//! for:
|
//! SQLite provides methods for:
|
||||||
//!
|
//!
|
||||||
//! * Integers (`i32` and `i64`; SQLite uses `i64` internally, so getting an `i32` will truncate
|
//! * Integers (`i32` and `i64`; SQLite uses `i64` internally, so getting an
|
||||||
//! if the value is too large or too small).
|
//! `i32` will truncate if the value is too large or too small).
|
||||||
//! * Reals (`f64`)
|
//! * Reals (`f64`)
|
||||||
//! * Strings (`String` and `&str`)
|
//! * Strings (`String` and `&str`)
|
||||||
//! * Blobs (`Vec<u8>` and `&[u8]`)
|
//! * Blobs (`Vec<u8>` and `&[u8]`)
|
||||||
@ -22,16 +22,18 @@
|
|||||||
//! extern crate rusqlite;
|
//! extern crate rusqlite;
|
||||||
//! extern crate time;
|
//! extern crate time;
|
||||||
//!
|
//!
|
||||||
//! use rusqlite::types::{FromSql, FromSqlResult, ValueRef, ToSql, ToSqlOutput};
|
//! use rusqlite::types::{FromSql, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||||
//! use rusqlite::{Result};
|
//! use rusqlite::Result;
|
||||||
//!
|
//!
|
||||||
//! pub struct TimespecSql(pub time::Timespec);
|
//! pub struct TimespecSql(pub time::Timespec);
|
||||||
//!
|
//!
|
||||||
//! impl FromSql for TimespecSql {
|
//! impl FromSql for TimespecSql {
|
||||||
//! fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
//! fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||||
//! f64::column_result(value).map(|as_f64| {
|
//! f64::column_result(value).map(|as_f64| {
|
||||||
//! TimespecSql(time::Timespec{ sec: as_f64.trunc() as i64,
|
//! TimespecSql(time::Timespec {
|
||||||
//! nsec: (as_f64.fract() * 1.0e9) as i32 })
|
//! sec: as_f64.trunc() as i64,
|
||||||
|
//! nsec: (as_f64.fract() * 1.0e9) as i32,
|
||||||
|
//! })
|
||||||
//! })
|
//! })
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
@ -48,9 +50,9 @@
|
|||||||
//! # fn main() {}
|
//! # fn main() {}
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! `ToSql` and `FromSql` are also implemented for `Option<T>` where `T` implements `ToSql` or
|
//! `ToSql` and `FromSql` are also implemented for `Option<T>` where `T`
|
||||||
//! `FromSql` for the cases where you want to know if a value was NULL (which gets translated to
|
//! implements `ToSql` or `FromSql` for the cases where you want to know if a
|
||||||
//! `None`).
|
//! value was NULL (which gets translated to `None`).
|
||||||
|
|
||||||
pub use self::from_sql::{FromSql, FromSqlError, FromSqlResult};
|
pub use self::from_sql::{FromSql, FromSqlError, FromSqlResult};
|
||||||
pub use self::to_sql::{ToSql, ToSqlOutput};
|
pub use self::to_sql::{ToSql, ToSqlOutput};
|
||||||
@ -77,8 +79,7 @@ mod value_ref;
|
|||||||
/// # extern crate rusqlite;
|
/// # extern crate rusqlite;
|
||||||
/// # use rusqlite::{Connection, Result};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// # use rusqlite::types::{Null};
|
/// # use rusqlite::types::{Null};
|
||||||
/// fn main() {
|
/// fn main() {}
|
||||||
/// }
|
|
||||||
/// fn insert_null(conn: &Connection) -> Result<usize> {
|
/// fn insert_null(conn: &Connection) -> Result<usize> {
|
||||||
/// conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null])
|
/// conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null])
|
||||||
/// }
|
/// }
|
||||||
|
@ -4,7 +4,8 @@ use std::borrow::Cow;
|
|||||||
use vtab::array::Array;
|
use vtab::array::Array;
|
||||||
use Result;
|
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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ToSqlOutput<'a> {
|
pub enum ToSqlOutput<'a> {
|
||||||
/// A borrowed SQLite-representable value.
|
/// A borrowed SQLite-representable value.
|
||||||
|
@ -32,8 +32,8 @@ impl<'a> ValueRef<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ValueRef<'a> {
|
impl<'a> ValueRef<'a> {
|
||||||
/// If `self` is case `Integer`, returns the integral value. Otherwise, returns
|
/// If `self` is case `Integer`, returns the integral value. Otherwise,
|
||||||
/// `Err(Error::InvalidColumnType)`.
|
/// returns `Err(Error::InvalidColumnType)`.
|
||||||
pub fn as_i64(&self) -> FromSqlResult<i64> {
|
pub fn as_i64(&self) -> FromSqlResult<i64> {
|
||||||
match *self {
|
match *self {
|
||||||
ValueRef::Integer(i) => Ok(i),
|
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
|
/// If `self` is case `Real`, returns the floating point value. Otherwise,
|
||||||
/// `Err(Error::InvalidColumnType)`.
|
/// returns `Err(Error::InvalidColumnType)`.
|
||||||
pub fn as_f64(&self) -> FromSqlResult<f64> {
|
pub fn as_f64(&self) -> FromSqlResult<f64> {
|
||||||
match *self {
|
match *self {
|
||||||
ValueRef::Real(f) => Ok(f),
|
ValueRef::Real(f) => Ok(f),
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use ffi;
|
use ffi;
|
||||||
use std::ffi::CStr;
|
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).
|
/// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html).
|
||||||
pub fn version_number() -> i32 {
|
pub fn version_number() -> i32 {
|
||||||
|
@ -120,6 +120,7 @@ impl ArrayTabCursor {
|
|||||||
ptr: None,
|
ptr: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len(&self) -> i64 {
|
fn len(&self) -> i64 {
|
||||||
match self.ptr {
|
match self.ptr {
|
||||||
Some(ref a) => a.len() as i64,
|
Some(ref a) => a.len() as i64,
|
||||||
@ -137,13 +138,16 @@ impl VTabCursor for ArrayTabCursor {
|
|||||||
self.row_id = 1;
|
self.row_id = 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self) -> Result<()> {
|
fn next(&mut self) -> Result<()> {
|
||||||
self.row_id += 1;
|
self.row_id += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eof(&self) -> bool {
|
fn eof(&self) -> bool {
|
||||||
self.row_id > self.len()
|
self.row_id > self.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column(&self, ctx: &mut Context, i: c_int) -> Result<()> {
|
fn column(&self, ctx: &mut Context, i: c_int) -> Result<()> {
|
||||||
match i {
|
match i {
|
||||||
CARRAY_COLUMN_POINTER => Ok(()),
|
CARRAY_COLUMN_POINTER => Ok(()),
|
||||||
@ -157,6 +161,7 @@ impl VTabCursor for ArrayTabCursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rowid(&self) -> Result<i64> {
|
fn rowid(&self) -> Result<i64> {
|
||||||
Ok(self.row_id)
|
Ok(self.row_id)
|
||||||
}
|
}
|
||||||
|
@ -293,6 +293,7 @@ impl VTabCursor for CSVTabCursor {
|
|||||||
self.row_number = 0;
|
self.row_number = 0;
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self) -> Result<()> {
|
fn next(&mut self) -> Result<()> {
|
||||||
{
|
{
|
||||||
self.eof = self.reader.is_done();
|
self.eof = self.reader.is_done();
|
||||||
@ -306,9 +307,11 @@ impl VTabCursor for CSVTabCursor {
|
|||||||
self.row_number += 1;
|
self.row_number += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eof(&self) -> bool {
|
fn eof(&self) -> bool {
|
||||||
self.eof
|
self.eof
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column(&self, ctx: &mut Context, col: c_int) -> Result<()> {
|
fn column(&self, ctx: &mut Context, col: c_int) -> Result<()> {
|
||||||
if col < 0 || col as usize >= self.cols.len() {
|
if col < 0 || col as usize >= self.cols.len() {
|
||||||
return Err(Error::ModuleError(format!(
|
return Err(Error::ModuleError(format!(
|
||||||
@ -322,6 +325,7 @@ impl VTabCursor for CSVTabCursor {
|
|||||||
// TODO Affinity
|
// TODO Affinity
|
||||||
ctx.set_result(&self.cols[col as usize].to_owned())
|
ctx.set_result(&self.cols[col as usize].to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rowid(&self) -> Result<i64> {
|
fn rowid(&self) -> Result<i64> {
|
||||||
Ok(self.row_number as i64)
|
Ok(self.row_number as i64)
|
||||||
}
|
}
|
||||||
|
@ -278,12 +278,14 @@ impl IndexInfo {
|
|||||||
(*self.0).idxNum = idx_num;
|
(*self.0).idxNum = idx_num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if output is already ordered
|
/// True if output is already ordered
|
||||||
pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
|
pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.0).orderByConsumed = if order_by_consumed { 1 } else { 0 };
|
(*self.0).orderByConsumed = if order_by_consumed { 1 } else { 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Estimated cost of using this index
|
/// Estimated cost of using this index
|
||||||
pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
|
pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -329,10 +331,12 @@ impl<'a> IndexConstraint<'a> {
|
|||||||
pub fn column(&self) -> c_int {
|
pub fn column(&self) -> c_int {
|
||||||
self.0.iColumn
|
self.0.iColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constraint operator
|
/// Constraint operator
|
||||||
pub fn operator(&self) -> IndexConstraintOp {
|
pub fn operator(&self) -> IndexConstraintOp {
|
||||||
IndexConstraintOp::from_bits_truncate(self.0.op)
|
IndexConstraintOp::from_bits_truncate(self.0.op)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if this constraint is usable
|
/// True if this constraint is usable
|
||||||
pub fn is_usable(&self) -> bool {
|
pub fn is_usable(&self) -> bool {
|
||||||
self.0.usable != 0
|
self.0.usable != 0
|
||||||
@ -347,6 +351,7 @@ impl<'a> IndexConstraintUsage<'a> {
|
|||||||
pub fn set_argv_index(&mut self, argv_index: c_int) {
|
pub fn set_argv_index(&mut self, argv_index: c_int) {
|
||||||
self.0.argvIndex = argv_index;
|
self.0.argvIndex = argv_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// if `omit`, do not code a test for this constraint
|
/// if `omit`, do not code a test for this constraint
|
||||||
pub fn set_omit(&mut self, omit: bool) {
|
pub fn set_omit(&mut self, omit: bool) {
|
||||||
self.0.omit = if omit { 1 } else { 0 };
|
self.0.omit = if omit { 1 } else { 0 };
|
||||||
@ -377,6 +382,7 @@ impl<'a> OrderBy<'a> {
|
|||||||
pub fn column(&self) -> c_int {
|
pub fn column(&self) -> c_int {
|
||||||
self.0.iColumn
|
self.0.iColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True for DESC. False for ASC.
|
/// True for DESC. False for ASC.
|
||||||
pub fn is_order_by_desc(&self) -> bool {
|
pub fn is_order_by_desc(&self) -> bool {
|
||||||
self.0.desc != 0
|
self.0.desc != 0
|
||||||
@ -483,8 +489,8 @@ impl<'a> Values<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a Values<'a> {
|
impl<'a> IntoIterator for &'a Values<'a> {
|
||||||
type Item = ValueRef<'a>;
|
|
||||||
type IntoIter = ValueIter<'a>;
|
type IntoIter = ValueIter<'a>;
|
||||||
|
type Item = ValueRef<'a>;
|
||||||
|
|
||||||
fn into_iter(self) -> ValueIter<'a> {
|
fn into_iter(self) -> ValueIter<'a> {
|
||||||
self.iter()
|
self.iter()
|
||||||
|
@ -227,6 +227,7 @@ impl VTabCursor for SeriesTabCursor {
|
|||||||
self.row_id = 1;
|
self.row_id = 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self) -> Result<()> {
|
fn next(&mut self) -> Result<()> {
|
||||||
if self.is_desc {
|
if self.is_desc {
|
||||||
self.value -= self.step;
|
self.value -= self.step;
|
||||||
@ -236,6 +237,7 @@ impl VTabCursor for SeriesTabCursor {
|
|||||||
self.row_id += 1;
|
self.row_id += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eof(&self) -> bool {
|
fn eof(&self) -> bool {
|
||||||
if self.is_desc {
|
if self.is_desc {
|
||||||
self.value < self.min_value
|
self.value < self.min_value
|
||||||
@ -243,6 +245,7 @@ impl VTabCursor for SeriesTabCursor {
|
|||||||
self.value > self.max_value
|
self.value > self.max_value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column(&self, ctx: &mut Context, i: c_int) -> Result<()> {
|
fn column(&self, ctx: &mut Context, i: c_int) -> Result<()> {
|
||||||
let x = match i {
|
let x = match i {
|
||||||
SERIES_COLUMN_START => self.min_value,
|
SERIES_COLUMN_START => self.min_value,
|
||||||
@ -252,6 +255,7 @@ impl VTabCursor for SeriesTabCursor {
|
|||||||
};
|
};
|
||||||
ctx.set_result(&x)
|
ctx.set_result(&x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rowid(&self) -> Result<i64> {
|
fn rowid(&self) -> Result<i64> {
|
||||||
Ok(self.row_id)
|
Ok(self.row_id)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! This file contains unit tests for `rusqlite::trace::config_log`. This function affects
|
//! This file contains unit tests for `rusqlite::trace::config_log`. This
|
||||||
//! SQLite process-wide and so is not safe to run as a normal #[test] in the library.
|
//! function affects SQLite process-wide and so is not safe to run as a normal
|
||||||
|
//! #[test] in the library.
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -65,16 +65,20 @@ fn test_dummy_module() {
|
|||||||
self.row_id = 1;
|
self.row_id = 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self) -> Result<()> {
|
fn next(&mut self) -> Result<()> {
|
||||||
self.row_id += 1;
|
self.row_id += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eof(&self) -> bool {
|
fn eof(&self) -> bool {
|
||||||
self.row_id > 1
|
self.row_id > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column(&self, ctx: &mut Context, _: c_int) -> Result<()> {
|
fn column(&self, ctx: &mut Context, _: c_int) -> Result<()> {
|
||||||
ctx.set_result(&self.row_id)
|
ctx.set_result(&self.row_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rowid(&self) -> Result<i64> {
|
fn rowid(&self) -> Result<i64> {
|
||||||
Ok(self.row_id)
|
Ok(self.row_id)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user