mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Doctest column name reference (#918)
* Doctest column name reference * Document rusqlite assumption on column name reference And move doctest as a test. * Document when columns metadata should be extracted. * Rustfmt doc (wrap_comments)
This commit is contained in:
parent
ecbc0aa767
commit
c4b398f468
@ -3,9 +3,10 @@
|
|||||||
//! To create a [`Backup`], you must have two distinct [`Connection`]s - one
|
//! To create a [`Backup`], you must have two distinct [`Connection`]s - one
|
||||||
//! for the source (which can be used while the backup is running) and one for
|
//! for the source (which can be used while the backup is running) and one for
|
||||||
//! the destination (which cannot). A [`Backup`] handle exposes three methods:
|
//! the destination (which cannot). A [`Backup`] handle exposes three methods:
|
||||||
//! [`step`](Backup::step) will attempt to back up a specified number of pages, [`progress`](Backup::progress) gets
|
//! [`step`](Backup::step) will attempt to back up a specified number of pages,
|
||||||
//! the current progress of the backup as of the last call to [`step`](Backup::step), and
|
//! [`progress`](Backup::progress) gets the current progress of the backup as of
|
||||||
//! [`run_to_completion`](Backup::run_to_completion) will attempt to back up the entire source database,
|
//! the last call to [`step`](Backup::step), and [`run_to_completion`](Backup::run_to_completion)
|
||||||
|
//! will attempt to back up the entire source database,
|
||||||
//! allowing you to specify how many pages are backed up at a time and how long
|
//! allowing you to specify how many pages are backed up at a time and how long
|
||||||
//! the thread should sleep between chunks of pages.
|
//! the thread should sleep between chunks of pages.
|
||||||
//!
|
//!
|
||||||
@ -130,7 +131,8 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `feature = "backup"` Possible successful results of calling [`Backup::step`].
|
/// `feature = "backup"` Possible successful results of calling
|
||||||
|
/// [`Backup::step`].
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum StepResult {
|
pub enum StepResult {
|
||||||
@ -152,9 +154,10 @@ pub enum StepResult {
|
|||||||
|
|
||||||
/// `feature = "backup"` Struct specifying the progress of a backup. The
|
/// `feature = "backup"` Struct specifying the progress of a backup. The
|
||||||
/// percentage completion can be calculated as `(pagecount - remaining) /
|
/// percentage completion can be calculated as `(pagecount - remaining) /
|
||||||
/// pagecount`. The progress of a backup is as of the last call to [`step`](Backup::step) - if
|
/// pagecount`. The progress of a backup is as of the last call to
|
||||||
/// the source database is modified after a call to [`step`](Backup::step), the progress value
|
/// [`step`](Backup::step) - if the source database is modified after a call to
|
||||||
/// will become outdated and potentially incorrect.
|
/// [`step`](Backup::step), the progress value will become outdated and
|
||||||
|
/// potentially incorrect.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Progress {
|
pub struct Progress {
|
||||||
/// Number of pages in the source database that still need to be backed up.
|
/// Number of pages in the source database that still need to be backed up.
|
||||||
@ -225,7 +228,8 @@ impl Backup<'_, '_> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the progress of the backup as of the last call to [`step`](Backup::step).
|
/// Gets the progress of the backup as of the last call to
|
||||||
|
/// [`step`](Backup::step).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn progress(&self) -> Progress {
|
pub fn progress(&self) -> Progress {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -240,7 +244,8 @@ impl Backup<'_, '_> {
|
|||||||
/// negative, will attempt to back up all remaining pages. This will hold a
|
/// negative, will attempt to back up all remaining pages. This will hold a
|
||||||
/// lock on the source database for the duration, so it is probably not
|
/// lock on the source database for the duration, so it is probably not
|
||||||
/// what you want for databases that are currently active (see
|
/// what you want for databases that are currently active (see
|
||||||
/// [`run_to_completion`](Backup::run_to_completion) for a better alternative).
|
/// [`run_to_completion`](Backup::run_to_completion) for a better
|
||||||
|
/// alternative).
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -262,12 +267,12 @@ impl Backup<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to run the entire backup. Will call [`step(pages_per_step)`](Backup::step) as
|
/// Attempts to run the entire backup. Will call
|
||||||
/// many times as necessary, sleeping for `pause_between_pages` between
|
/// [`step(pages_per_step)`](Backup::step) as many times as necessary,
|
||||||
/// each call to give the source database time to process any pending
|
/// sleeping for `pause_between_pages` between each call to give the
|
||||||
/// queries. This is a direct implementation of "Example 2: Online Backup
|
/// source database time to process any pending queries. This is a
|
||||||
/// of a Running Database" from [SQLite's Online Backup API
|
/// direct implementation of "Example 2: Online Backup of a Running
|
||||||
/// documentation](https://www.sqlite.org/backup.html).
|
/// Database" from [SQLite's Online Backup API documentation](https://www.sqlite.org/backup.html).
|
||||||
///
|
///
|
||||||
/// If `progress` is not `None`, it will be called after each step with the
|
/// If `progress` is not `None`, it will be called after each step with the
|
||||||
/// current progress of the backup. Note that is possible the progress may
|
/// current progress of the backup. Note that is possible the progress may
|
||||||
@ -276,7 +281,8 @@ impl Backup<'_, '_> {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return `Err` if any of the calls to [`step`](Backup::step) return `Err`.
|
/// Will return `Err` if any of the calls to [`step`](Backup::step) return
|
||||||
|
/// `Err`.
|
||||||
pub fn run_to_completion(
|
pub fn run_to_completion(
|
||||||
&self,
|
&self,
|
||||||
pages_per_step: c_int,
|
pages_per_step: c_int,
|
||||||
|
19
src/busy.rs
19
src/busy.rs
@ -19,11 +19,11 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// There can only be a single busy handler for a particular database
|
/// There can only be a single busy handler for a particular database
|
||||||
/// connection at any given moment. If another busy handler was defined
|
/// connection at any given moment. If another busy handler was defined
|
||||||
/// (using [`busy_handler`](Connection::busy_handler)) prior to calling this routine, that other
|
/// (using [`busy_handler`](Connection::busy_handler)) prior to calling this
|
||||||
/// busy handler is cleared.
|
/// routine, that other busy handler is cleared.
|
||||||
///
|
///
|
||||||
/// Newly created connections currently have a default busy timeout of 5000ms, but this may be
|
/// Newly created connections currently have a default busy timeout of
|
||||||
/// subject to change.
|
/// 5000ms, but this may be subject to change.
|
||||||
pub fn busy_timeout(&self, timeout: Duration) -> Result<()> {
|
pub fn busy_timeout(&self, timeout: Duration) -> Result<()> {
|
||||||
let ms: i32 = timeout
|
let ms: i32 = timeout
|
||||||
.as_secs()
|
.as_secs()
|
||||||
@ -48,12 +48,13 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// There can only be a single busy handler defined for each database
|
/// There can only be a single busy handler defined for each database
|
||||||
/// connection. Setting a new busy handler clears any previously set
|
/// connection. Setting a new busy handler clears any previously set
|
||||||
/// handler. Note that calling [`busy_timeout()`](Connection::busy_timeout) or evaluating `PRAGMA
|
/// handler. Note that calling [`busy_timeout()`](Connection::busy_timeout)
|
||||||
/// busy_timeout=N` will change the busy handler and thus
|
/// or evaluating `PRAGMA busy_timeout=N` will change the busy handler
|
||||||
/// clear any previously set busy handler.
|
/// and thus clear any previously set busy handler.
|
||||||
///
|
///
|
||||||
/// Newly created connections default to a [`busy_timeout()`](Connection::busy_timeout) handler
|
/// Newly created connections default to a
|
||||||
/// with a timeout of 5000ms, although this is subject to change.
|
/// [`busy_timeout()`](Connection::busy_timeout) handler with a timeout
|
||||||
|
/// of 5000ms, although this is subject to change.
|
||||||
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);
|
||||||
|
@ -63,7 +63,8 @@ pub struct StatementCache(RefCell<LruCache<Arc<str>, RawStatement>>);
|
|||||||
/// Cacheable statement.
|
/// Cacheable statement.
|
||||||
///
|
///
|
||||||
/// Statement will return automatically to the cache by default.
|
/// Statement will return automatically to the cache by default.
|
||||||
/// If you want the statement to be discarded, call [`discard()`](CachedStatement::discard) on it.
|
/// If you want the statement to be discarded, call
|
||||||
|
/// [`discard()`](CachedStatement::discard) on it.
|
||||||
pub struct CachedStatement<'conn> {
|
pub struct CachedStatement<'conn> {
|
||||||
stmt: Option<Statement<'conn>>,
|
stmt: Option<Statement<'conn>>,
|
||||||
cache: &'conn StatementCache,
|
cache: &'conn StatementCache,
|
||||||
|
@ -97,7 +97,8 @@ impl InnerConnection {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
let res = self.decode_result(r);
|
let res = self.decode_result(r);
|
||||||
// The xDestroy callback is not called if the sqlite3_create_collation_v2() function fails.
|
// The xDestroy callback is not called if the sqlite3_create_collation_v2()
|
||||||
|
// function fails.
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
drop(unsafe { Box::from_raw(boxed_f) });
|
drop(unsafe { Box::from_raw(boxed_f) });
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,10 @@ impl Column<'_> {
|
|||||||
|
|
||||||
impl Statement<'_> {
|
impl Statement<'_> {
|
||||||
/// Get all the column names in the result set of the prepared statement.
|
/// Get all the column names in the result set of the prepared statement.
|
||||||
|
///
|
||||||
|
/// If associated DB schema can be altered concurrently, you should make
|
||||||
|
/// sure that current statement has already been stepped once before
|
||||||
|
/// calling this method.
|
||||||
pub fn column_names(&self) -> Vec<&str> {
|
pub fn column_names(&self) -> Vec<&str> {
|
||||||
let n = self.column_count();
|
let n = self.column_count();
|
||||||
let mut cols = Vec::with_capacity(n as usize);
|
let mut cols = Vec::with_capacity(n as usize);
|
||||||
@ -37,11 +41,34 @@ impl Statement<'_> {
|
|||||||
|
|
||||||
/// Return the number of columns in the result set returned by the prepared
|
/// Return the number of columns in the result set returned by the prepared
|
||||||
/// statement.
|
/// statement.
|
||||||
|
///
|
||||||
|
/// If associated DB schema can be altered concurrently, you should make
|
||||||
|
/// sure that current statement has already been stepped once before
|
||||||
|
/// calling this method.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn column_count(&self) -> usize {
|
pub fn column_count(&self) -> usize {
|
||||||
self.stmt.column_count()
|
self.stmt.column_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that column name reference lifetime is limited:
|
||||||
|
/// https://www.sqlite.org/c3ref/column_name.html
|
||||||
|
/// > The returned string pointer is valid...
|
||||||
|
///
|
||||||
|
/// `column_name` reference can become invalid if `stmt` is reprepared
|
||||||
|
/// (because of schema change) when `query_row` is called. So we assert
|
||||||
|
/// that a compilation error happens if this reference is kept alive:
|
||||||
|
/// ```compile_fail
|
||||||
|
/// use rusqlite::{Connection, Result};
|
||||||
|
/// fn main() -> Result<()> {
|
||||||
|
/// let db = Connection::open_in_memory()?;
|
||||||
|
/// let mut stmt = db.prepare("SELECT 1 as x")?;
|
||||||
|
/// let column_name = stmt.column_name(0)?;
|
||||||
|
/// let x = stmt.query_row([], |r| r.get::<_, i64>(0))?; // E0502
|
||||||
|
/// assert_eq!(1, x);
|
||||||
|
/// assert_eq!("x", column_name);
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn column_name_unwrap(&self, col: usize) -> &str {
|
pub(super) fn column_name_unwrap(&self, col: usize) -> &str {
|
||||||
// Just panic if the bounds are wrong for now, we never call this
|
// Just panic if the bounds are wrong for now, we never call this
|
||||||
@ -52,6 +79,10 @@ impl Statement<'_> {
|
|||||||
/// Returns the name assigned to a particular column in the result set
|
/// Returns the name assigned to a particular column in the result set
|
||||||
/// returned by the prepared statement.
|
/// returned by the prepared statement.
|
||||||
///
|
///
|
||||||
|
/// If associated DB schema can be altered concurrently, you should make
|
||||||
|
/// sure that current statement has already been stepped once before
|
||||||
|
/// calling this method.
|
||||||
|
///
|
||||||
/// ## Failure
|
/// ## Failure
|
||||||
///
|
///
|
||||||
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid
|
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid
|
||||||
@ -73,6 +104,10 @@ impl Statement<'_> {
|
|||||||
/// If there is no AS clause then the name of the column is unspecified and
|
/// If there is no AS clause then the name of the column is unspecified and
|
||||||
/// may change from one release of SQLite to the next.
|
/// may change from one release of SQLite to the next.
|
||||||
///
|
///
|
||||||
|
/// If associated DB schema can be altered concurrently, you should make
|
||||||
|
/// sure that current statement has already been stepped once before
|
||||||
|
/// calling this method.
|
||||||
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return an `Error::InvalidColumnName` when there is no column with
|
/// Will return an `Error::InvalidColumnName` when there is no column with
|
||||||
@ -92,6 +127,10 @@ impl Statement<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a slice describing the columns of the result of the query.
|
/// Returns a slice describing the columns of the result of the query.
|
||||||
|
///
|
||||||
|
/// If associated DB schema can be altered concurrently, you should make
|
||||||
|
/// sure that current statement has already been stepped once before
|
||||||
|
/// calling this method.
|
||||||
#[cfg(feature = "column_decltype")]
|
#[cfg(feature = "column_decltype")]
|
||||||
pub fn columns(&self) -> Vec<Column> {
|
pub fn columns(&self) -> Vec<Column> {
|
||||||
let n = self.column_count();
|
let n = self.column_count();
|
||||||
@ -234,4 +273,24 @@ mod test {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `column_name` reference should stay valid until `stmt` is reprepared (or
|
||||||
|
/// reset) even if DB schema is altered (SQLite documentation is
|
||||||
|
/// ambiguous here because it says reference "is valid until (...) the next
|
||||||
|
/// call to sqlite3_column_name() or sqlite3_column_name16() on the same
|
||||||
|
/// column.". We assume that reference is valid if only `sqlite3_column_name()` is used):
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "modern_sqlite")]
|
||||||
|
fn test_column_name_reference() -> Result<()> {
|
||||||
|
let db = Connection::open_in_memory()?;
|
||||||
|
db.execute_batch("CREATE TABLE y (x);")?;
|
||||||
|
let stmt = db.prepare("SELECT x FROM y;")?;
|
||||||
|
let column_name = stmt.column_name(0)?;
|
||||||
|
assert_eq!("x", column_name);
|
||||||
|
db.execute_batch("ALTER TABLE y RENAME COLUMN x TO z;")?;
|
||||||
|
// column name is not refreshed until statement is re-prepared
|
||||||
|
let same_column_name = stmt.column_name(0)?;
|
||||||
|
assert_eq!(same_column_name, column_name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
21
src/error.rs
21
src/error.rs
@ -43,7 +43,8 @@ pub enum Error {
|
|||||||
/// Error converting a file path to a string.
|
/// Error converting a file path to a string.
|
||||||
InvalidPath(PathBuf),
|
InvalidPath(PathBuf),
|
||||||
|
|
||||||
/// Error returned when an [`execute`](crate::Connection::execute) call returns rows.
|
/// Error returned when an [`execute`](crate::Connection::execute) call
|
||||||
|
/// returns rows.
|
||||||
ExecuteReturnedResults,
|
ExecuteReturnedResults,
|
||||||
|
|
||||||
/// Error when a query that was expected to return at least one row (e.g.,
|
/// Error when a query that was expected to return at least one row (e.g.,
|
||||||
@ -67,12 +68,13 @@ pub enum Error {
|
|||||||
/// any or insert many.
|
/// any or insert many.
|
||||||
StatementChangedRows(usize),
|
StatementChangedRows(usize),
|
||||||
|
|
||||||
/// Error returned by [`functions::Context::get`](crate::functions::Context::get) when the function argument
|
/// Error returned by
|
||||||
/// cannot be converted to the requested type.
|
/// [`functions::Context::get`](crate::functions::Context::get) when the
|
||||||
|
/// function argument 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`](crate::vtab::Values::get) when the filter argument cannot
|
/// Error returned by [`vtab::Values::get`](crate::vtab::Values::get) when
|
||||||
/// be converted to the requested type.
|
/// the filter argument cannot be converted to the requested type.
|
||||||
#[cfg(feature = "vtab")]
|
#[cfg(feature = "vtab")]
|
||||||
InvalidFilterParameterType(usize, Type),
|
InvalidFilterParameterType(usize, Type),
|
||||||
|
|
||||||
@ -82,7 +84,8 @@ pub enum Error {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
|
UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
|
||||||
|
|
||||||
/// Error available for the implementors of the [`ToSql`](crate::types::ToSql) trait.
|
/// Error available for the implementors of the
|
||||||
|
/// [`ToSql`](crate::types::ToSql) trait.
|
||||||
ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
|
ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
|
||||||
|
|
||||||
/// Error when the SQL is not a `SELECT`, is not read-only.
|
/// Error when the SQL is not a `SELECT`, is not read-only.
|
||||||
@ -98,8 +101,10 @@ pub enum Error {
|
|||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
UnwindingPanic,
|
UnwindingPanic,
|
||||||
|
|
||||||
/// An error returned when [`Context::get_aux`](crate::functions::Context::get_aux) attempts to retrieve data
|
/// An error returned when
|
||||||
/// of a different type than what had been stored using [`Context::set_aux`](crate::functions::Context::set_aux).
|
/// [`Context::get_aux`](crate::functions::Context::get_aux) attempts to
|
||||||
|
/// retrieve data of a different type than what had been stored using
|
||||||
|
/// [`Context::set_aux`](crate::functions::Context::set_aux).
|
||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
GetAuxWrongType,
|
GetAuxWrongType,
|
||||||
|
|
||||||
|
@ -128,7 +128,8 @@ impl Context<'_> {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will panic if `idx` is greater than or equal to [`self.len()`](Context::len).
|
/// Will panic if `idx` is greater than or equal to
|
||||||
|
/// [`self.len()`](Context::len).
|
||||||
///
|
///
|
||||||
/// Will return Err if the underlying SQLite type cannot be converted to a
|
/// Will return Err if the underlying SQLite type cannot be converted to a
|
||||||
/// `T`.
|
/// `T`.
|
||||||
@ -158,7 +159,8 @@ impl Context<'_> {
|
|||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will panic if `idx` is greater than or equal to [`self.len()`](Context::len).
|
/// Will panic if `idx` is greater than or equal to
|
||||||
|
/// [`self.len()`](Context::len).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_raw(&self, idx: usize) -> ValueRef<'_> {
|
pub fn get_raw(&self, idx: usize) -> ValueRef<'_> {
|
||||||
let arg = self.args[idx];
|
let arg = self.args[idx];
|
||||||
@ -167,7 +169,8 @@ impl Context<'_> {
|
|||||||
|
|
||||||
/// Fetch or insert the auxilliary data associated with a particular
|
/// Fetch or insert the auxilliary data associated with a particular
|
||||||
/// parameter. This is intended to be an easier-to-use way of fetching it
|
/// parameter. This is intended to be an easier-to-use way of fetching it
|
||||||
/// compared to calling [`get_aux`](Context::get_aux) and [`set_aux`](Context::set_aux) separately.
|
/// compared to calling [`get_aux`](Context::get_aux) and
|
||||||
|
/// [`set_aux`](Context::set_aux) separately.
|
||||||
///
|
///
|
||||||
/// See `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of
|
/// See `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of
|
||||||
/// this feature, or the unit tests of this module for an example.
|
/// this feature, or the unit tests of this module for an example.
|
||||||
@ -208,9 +211,9 @@ impl Context<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the auxilliary data that was associated with a given parameter via
|
/// Gets the auxilliary data that was associated with a given parameter via
|
||||||
/// [`set_aux`](Context::set_aux). Returns `Ok(None)` if no data has been associated, and
|
/// [`set_aux`](Context::set_aux). Returns `Ok(None)` if no data has been
|
||||||
/// Ok(Some(v)) if it has. Returns an error if the requested type does not
|
/// associated, and Ok(Some(v)) if it has. Returns an error if the
|
||||||
/// match.
|
/// requested type does not match.
|
||||||
pub fn get_aux<T: Send + Sync + 'static>(&self, arg: c_int) -> Result<Option<Arc<T>>> {
|
pub fn get_aux<T: Send + Sync + 'static>(&self, arg: c_int) -> Result<Option<Arc<T>>> {
|
||||||
let p = unsafe { ffi::sqlite3_get_auxdata(self.ctx, arg) as *const AuxInner };
|
let p = unsafe { ffi::sqlite3_get_auxdata(self.ctx, arg) as *const AuxInner };
|
||||||
if p.is_null() {
|
if p.is_null() {
|
||||||
@ -268,8 +271,9 @@ where
|
|||||||
T: ToSql,
|
T: ToSql,
|
||||||
{
|
{
|
||||||
/// Initializes the aggregation context. Will be called prior to the first
|
/// Initializes the aggregation context. Will be called prior to the first
|
||||||
/// call to [`step()`](Aggregate::step) to set up the context for an invocation of the
|
/// call to [`step()`](Aggregate::step) to set up the context for an
|
||||||
/// function. (Note: `init()` will not be called if there are no rows.)
|
/// invocation of the function. (Note: `init()` will not be called if
|
||||||
|
/// there are no rows.)
|
||||||
fn init(&self, _: &mut Context<'_>) -> Result<A>;
|
fn init(&self, _: &mut Context<'_>) -> Result<A>;
|
||||||
|
|
||||||
/// "step" function called once for each row in an aggregate group. May be
|
/// "step" function called once for each row in an aggregate group. May be
|
||||||
@ -277,10 +281,12 @@ where
|
|||||||
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
|
/// Computes and returns the final result. Will be called exactly once for
|
||||||
/// each invocation of the function. If [`step()`](Aggregate::step) was called at least
|
/// each invocation of the function. If [`step()`](Aggregate::step) was
|
||||||
/// once, will be given `Some(A)` (the same `A` as was created by
|
/// called at least once, will be given `Some(A)` (the same `A` as was
|
||||||
/// [`init`](Aggregate::init) and given to [`step`](Aggregate::step)); if [`step()`](Aggregate::step) was not called (because
|
/// created by [`init`](Aggregate::init) and given to
|
||||||
/// the function is running against 0 rows), will be given `None`.
|
/// [`step`](Aggregate::step)); if [`step()`](Aggregate::step) was not
|
||||||
|
/// called (because the function is running against 0 rows), will be
|
||||||
|
/// given `None`.
|
||||||
///
|
///
|
||||||
/// The passed context will have no arguments.
|
/// The passed context will have no arguments.
|
||||||
fn finalize(&self, _: &mut Context<'_>, _: Option<A>) -> Result<T>;
|
fn finalize(&self, _: &mut Context<'_>, _: Option<A>) -> Result<T>;
|
||||||
@ -344,7 +350,8 @@ impl Connection {
|
|||||||
/// given the same 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`](Connection::remove_function).
|
/// until it is explicitly removed via
|
||||||
|
/// [`remove_function`](Connection::remove_function).
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
@ -440,7 +447,8 @@ impl Connection {
|
|||||||
/// database connection.
|
/// database connection.
|
||||||
///
|
///
|
||||||
/// `fn_name` and `n_arg` should match the name and number of arguments
|
/// `fn_name` and `n_arg` should match the name and number of arguments
|
||||||
/// given to [`create_scalar_function`](Connection::create_scalar_function) or [`create_aggregate_function`](Connection::create_aggregate_function).
|
/// given to [`create_scalar_function`](Connection::create_scalar_function)
|
||||||
|
/// or [`create_aggregate_function`](Connection::create_aggregate_function).
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
|
@ -29,7 +29,8 @@ impl<'stmt> Rows<'stmt> {
|
|||||||
/// This interface is not compatible with Rust's `Iterator` trait, because
|
/// This interface is not compatible with Rust's `Iterator` trait, because
|
||||||
/// the lifetime of the returned row is tied to the lifetime of `self`.
|
/// the lifetime of the returned row is tied to the lifetime of `self`.
|
||||||
/// This is a fallible "streaming iterator". For a more natural interface,
|
/// This is a fallible "streaming iterator". For a more natural interface,
|
||||||
/// consider using [`query_map`](crate::Statement::query_map) or [`query_and_then`](crate::Statement::query_and_then) instead, which
|
/// consider using [`query_map`](crate::Statement::query_map) or
|
||||||
|
/// [`query_and_then`](crate::Statement::query_and_then) instead, which
|
||||||
/// return types that implement `Iterator`.
|
/// return types that implement `Iterator`.
|
||||||
#[allow(clippy::should_implement_trait)] // cannot implement Iterator
|
#[allow(clippy::should_implement_trait)] // cannot implement Iterator
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -331,8 +332,8 @@ impl<'stmt> Row<'stmt> {
|
|||||||
///
|
///
|
||||||
/// ## Failure
|
/// ## Failure
|
||||||
///
|
///
|
||||||
/// Panics if calling [`row.get_ref(idx)`](Row::get_ref) would return an error,
|
/// Panics if calling [`row.get_ref(idx)`](Row::get_ref) would return an
|
||||||
/// including:
|
/// error, including:
|
||||||
///
|
///
|
||||||
/// * If `idx` is outside the range of columns in the returned query.
|
/// * If `idx` is outside the range of columns in the returned query.
|
||||||
/// * If `idx` is not a valid column name for this row.
|
/// * If `idx` is not a valid column name for this row.
|
||||||
|
@ -411,7 +411,8 @@ impl Drop for ChangesetIter<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `feature = "session"` An item passed to a conflict-handler by
|
/// `feature = "session"` An item passed to a conflict-handler by
|
||||||
/// [`Connection::apply`](crate::Connection::apply), or an item generated by [`ChangesetIter::next`](ChangesetIter::next).
|
/// [`Connection::apply`](crate::Connection::apply), or an item generated by
|
||||||
|
/// [`ChangesetIter::next`](ChangesetIter::next).
|
||||||
// TODO enum ? Delete, Insert, Update, ...
|
// TODO enum ? Delete, Insert, Update, ...
|
||||||
pub struct ChangesetItem {
|
pub struct ChangesetItem {
|
||||||
it: *mut ffi::sqlite3_changeset_iter,
|
it: *mut ffi::sqlite3_changeset_iter,
|
||||||
|
@ -114,11 +114,11 @@ impl Statement<'_> {
|
|||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// This function is a convenience wrapper around [`execute()`](Statement::execute) intended for
|
/// This function is a convenience wrapper around
|
||||||
/// queries that insert a single item. It is possible to misuse this
|
/// [`execute()`](Statement::execute) intended for queries that insert a
|
||||||
/// function in a way that it cannot detect, such as by calling it on a
|
/// single item. It is possible to misuse this function in a way that it
|
||||||
/// statement which _updates_ a single
|
/// cannot detect, such as by calling it on a statement which _updates_
|
||||||
/// item rather than inserting one. Please don't do that.
|
/// a single item rather than inserting one. Please don't do that.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -136,8 +136,9 @@ impl Statement<'_> {
|
|||||||
/// rows.
|
/// 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`](Statement::query_map) or
|
/// implement the `Iterator` trait. Consider using
|
||||||
/// [`query_and_then`](Statement::query_and_then) instead, which do.
|
/// [`query_map`](Statement::query_map) or [`query_and_then`](Statement::query_and_then)
|
||||||
|
/// instead, which do.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -396,8 +397,9 @@ impl Statement<'_> {
|
|||||||
/// iterator over the result of calling the mapping function over the
|
/// iterator over the result of calling the mapping function over the
|
||||||
/// query's rows.
|
/// query's rows.
|
||||||
///
|
///
|
||||||
/// Note: This function is deprecated in favor of [`Statement::query_and_then`],
|
/// Note: This function is deprecated in favor of
|
||||||
/// which can now take named parameters directly.
|
/// [`Statement::query_and_then`], which can now take named parameters
|
||||||
|
/// directly.
|
||||||
///
|
///
|
||||||
/// If any parameters that were in the prepared statement are not included
|
/// If any parameters that were in the prepared statement are not included
|
||||||
/// in `params`, they will continue to use the most-recently bound value
|
/// in `params`, they will continue to use the most-recently bound value
|
||||||
@ -436,9 +438,10 @@ impl Statement<'_> {
|
|||||||
/// ignored.
|
/// ignored.
|
||||||
///
|
///
|
||||||
/// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
|
/// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
|
||||||
/// query truly is optional, you can call [`.optional()`](crate::OptionalExtension::optional) on the result of
|
/// query truly is optional, you can call
|
||||||
/// this to get a `Result<Option<T>>` (requires that the trait `rusqlite::OptionalExtension`
|
/// [`.optional()`](crate::OptionalExtension::optional) on the result of
|
||||||
/// is imported).
|
/// this to get a `Result<Option<T>>` (requires that the trait
|
||||||
|
/// `rusqlite::OptionalExtension` is imported).
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
@ -456,16 +459,18 @@ impl Statement<'_> {
|
|||||||
/// Convenience method to execute a query with named parameter(s) that is
|
/// Convenience method to execute a query with named parameter(s) that is
|
||||||
/// expected to return a single row.
|
/// expected to return a single row.
|
||||||
///
|
///
|
||||||
/// Note: This function is deprecated in favor of [`Statement::query_and_then`],
|
/// Note: This function is deprecated in favor of
|
||||||
/// which can now take named parameters directly.
|
/// [`Statement::query_and_then`], which can now take named parameters
|
||||||
|
/// directly.
|
||||||
///
|
///
|
||||||
/// If the query returns more than one row, all rows except the first are
|
/// If the query returns more than one row, all rows except the first are
|
||||||
/// ignored.
|
/// ignored.
|
||||||
///
|
///
|
||||||
/// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
|
/// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
|
||||||
/// query truly is optional, you can call [`.optional()`](crate::OptionalExtension::optional) on the result of
|
/// query truly is optional, you can call
|
||||||
/// this to get a `Result<Option<T>>` (requires that the trait `rusqlite::OptionalExtension`
|
/// [`.optional()`](crate::OptionalExtension::optional) on the result of
|
||||||
/// is imported).
|
/// this to get a `Result<Option<T>>` (requires that the trait
|
||||||
|
/// `rusqlite::OptionalExtension` is imported).
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
|
@ -377,8 +377,9 @@ 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
|
/// The transaction defaults to rolling back when it is dropped. If you
|
||||||
/// want the transaction to commit, you must call [`commit`](Transaction::commit) or
|
/// want the transaction to commit, you must call
|
||||||
/// [`set_drop_behavior(DropBehavior::Commit)`](Transaction::set_drop_behavior).
|
/// [`commit`](Transaction::commit) or [`set_drop_behavior(DropBehavior:
|
||||||
|
/// :Commit)`](Transaction::set_drop_behavior).
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -458,7 +459,8 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// The savepoint defaults to rolling back when it is dropped. If you want
|
/// The savepoint defaults to rolling back when it is dropped. If you want
|
||||||
/// the savepoint to commit, you must call [`commit`](Savepoint::commit) or
|
/// the savepoint to commit, you must call [`commit`](Savepoint::commit) or
|
||||||
/// [`set_drop_behavior(DropBehavior::Commit)`](Savepoint::set_drop_behavior).
|
/// [`set_drop_behavior(DropBehavior::Commit)`](Savepoint::
|
||||||
|
/// set_drop_behavior).
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
//! [`FromSql`] has different behaviour depending on the SQL and Rust types, and
|
//! [`FromSql`] has different behaviour depending on the SQL and Rust types, and
|
||||||
//! the value.
|
//! the value.
|
||||||
//!
|
//!
|
||||||
//! * `INTEGER` to integer: returns an [`Error::IntegralValueOutOfRange`](crate::Error::IntegralValueOutOfRange) error if
|
//! * `INTEGER` to integer: returns an
|
||||||
//! the value does not fit in the Rust type.
|
//! [`Error::IntegralValueOutOfRange`](crate::Error::IntegralValueOutOfRange)
|
||||||
//! * `REAL` to integer: always returns an [`Error::InvalidColumnType`](crate::Error::InvalidColumnType) error.
|
//! error if the value does not fit in the Rust type.
|
||||||
|
//! * `REAL` to integer: always returns an
|
||||||
|
//! [`Error::InvalidColumnType`](crate::Error::InvalidColumnType) error.
|
||||||
//! * `INTEGER` to float: casts using `as` operator. Never fails.
|
//! * `INTEGER` to float: casts using `as` operator. Never fails.
|
||||||
//! * `REAL` to float: casts using `as` operator. Never fails.
|
//! * `REAL` to float: casts using `as` operator. Never fails.
|
||||||
//!
|
//!
|
||||||
@ -62,8 +64,8 @@ impl ToSql for DateTimeSql {
|
|||||||
"##
|
"##
|
||||||
)]
|
)]
|
||||||
//! [`ToSql`] and [`FromSql`] are also implemented for `Option<T>` where `T`
|
//! [`ToSql`] and [`FromSql`] are also implemented for `Option<T>` where `T`
|
||||||
//! implements [`ToSql`] or [`FromSql`] for the cases where you want to know if a
|
//! implements [`ToSql`] or [`FromSql`] for the cases where you want to know if
|
||||||
//! value was NULL (which gets translated to `None`).
|
//! a 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};
|
||||||
|
@ -3,7 +3,8 @@ use super::{Null, Type};
|
|||||||
/// Owning [dynamic type value](http://sqlite.org/datatype3.html). Value's type is typically
|
/// Owning [dynamic type value](http://sqlite.org/datatype3.html). Value's type is typically
|
||||||
/// dictated by SQLite (not by the caller).
|
/// dictated by SQLite (not by the caller).
|
||||||
///
|
///
|
||||||
/// See [`ValueRef`](crate::types::ValueRef) for a non-owning dynamic type value.
|
/// See [`ValueRef`](crate::types::ValueRef) for a non-owning dynamic type
|
||||||
|
/// value.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
/// The value is a `NULL` value.
|
/// The value is a `NULL` value.
|
||||||
|
@ -35,7 +35,8 @@ impl ValueRef<'_> {
|
|||||||
|
|
||||||
impl<'a> ValueRef<'a> {
|
impl<'a> ValueRef<'a> {
|
||||||
/// If `self` is case `Integer`, returns the integral value. Otherwise,
|
/// If `self` is case `Integer`, returns the integral value. Otherwise,
|
||||||
/// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
|
/// returns [`Err(Error::InvalidColumnType)`](crate::Error::
|
||||||
|
/// InvalidColumnType).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_i64(&self) -> FromSqlResult<i64> {
|
pub fn as_i64(&self) -> FromSqlResult<i64> {
|
||||||
match *self {
|
match *self {
|
||||||
@ -45,7 +46,8 @@ impl<'a> ValueRef<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If `self` is case `Real`, returns the floating point value. Otherwise,
|
/// If `self` is case `Real`, returns the floating point value. Otherwise,
|
||||||
/// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
|
/// returns [`Err(Error::InvalidColumnType)`](crate::Error::
|
||||||
|
/// InvalidColumnType).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_f64(&self) -> FromSqlResult<f64> {
|
pub fn as_f64(&self) -> FromSqlResult<f64> {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
//!
|
//!
|
||||||
//! Follow these steps to create your own virtual table:
|
//! Follow these steps to create your own virtual table:
|
||||||
//! 1. Write implemenation of [`VTab`] and [`VTabCursor`] traits.
|
//! 1. Write implemenation of [`VTab`] and [`VTabCursor`] traits.
|
||||||
//! 2. Create an instance of the [`Module`] structure specialized for [`VTab`] impl.
|
//! 2. Create an instance of the [`Module`] structure specialized for [`VTab`]
|
||||||
//! from step 1.
|
//! impl. from step 1.
|
||||||
//! 3. Register your [`Module`] structure using [`Connection::create_module`].
|
//! 3. Register your [`Module`] structure using [`Connection::create_module`].
|
||||||
//! 4. Run a `CREATE VIRTUAL TABLE` command that specifies the new module in the
|
//! 4. Run a `CREATE VIRTUAL TABLE` command that specifies the new module in the
|
||||||
//! `USING` clause.
|
//! `USING` clause.
|
||||||
@ -430,7 +430,8 @@ impl IndexConstraint<'_> {
|
|||||||
pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
|
pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
|
||||||
|
|
||||||
impl IndexConstraintUsage<'_> {
|
impl IndexConstraintUsage<'_> {
|
||||||
/// if `argv_index` > 0, constraint is part of argv to [`VTabCursor::filter`]
|
/// if `argv_index` > 0, constraint is part of argv to
|
||||||
|
/// [`VTabCursor::filter`]
|
||||||
#[inline]
|
#[inline]
|
||||||
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;
|
||||||
@ -496,8 +497,8 @@ pub unsafe trait VTabCursor: Sized {
|
|||||||
/// Begin a search of a virtual table.
|
/// Begin a search of a virtual table.
|
||||||
/// (See [SQLite doc](https://sqlite.org/vtab.html#the_xfilter_method))
|
/// (See [SQLite doc](https://sqlite.org/vtab.html#the_xfilter_method))
|
||||||
fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>;
|
fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>;
|
||||||
/// Advance cursor to the next row of a result set initiated by [`filter`](VTabCursor::filter).
|
/// Advance cursor to the next row of a result set initiated by
|
||||||
/// (See [SQLite doc](https://sqlite.org/vtab.html#the_xnext_method))
|
/// [`filter`](VTabCursor::filter). (See [SQLite doc](https://sqlite.org/vtab.html#the_xnext_method))
|
||||||
fn next(&mut self) -> Result<()>;
|
fn next(&mut self) -> Result<()>;
|
||||||
/// Must return `false` if the cursor currently points to a valid row of
|
/// Must return `false` if the cursor currently points to a valid row of
|
||||||
/// data, or `true` otherwise.
|
/// data, or `true` otherwise.
|
||||||
|
Loading…
Reference in New Issue
Block a user