Merge remote-tracking branch 'upstream/master' into time-fmt

This commit is contained in:
gwenn 2021-07-30 21:24:51 +02:00
commit b3f8c283f1
39 changed files with 4641 additions and 3205 deletions

View File

@ -150,6 +150,7 @@ features = [ "array", "backup", "blob", "chrono", "collation", "functions", "lim
all-features = false all-features = false
no-default-features = true no-default-features = true
default-target = "x86_64-unknown-linux-gnu" default-target = "x86_64-unknown-linux-gnu"
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.playground] [package.metadata.playground]
features = ["bundled-full"] features = ["bundled-full"]

View File

@ -42,7 +42,7 @@ winsqlite3 = ["min_sqlite_version_3_7_16"]
openssl-sys = { version = "0.9.58", optional = true } openssl-sys = { version = "0.9.58", optional = true }
[build-dependencies] [build-dependencies]
bindgen = { version = "0.58", optional = true, default-features = false, features = ["runtime"] } bindgen = { version = "0.59", optional = true, default-features = false, features = ["runtime"] }
pkg-config = { version = "0.3.19", optional = true } pkg-config = { version = "0.3.19", optional = true }
cc = { version = "1.0", optional = true } cc = { version = "1.0", optional = true }
vcpkg = { version = "0.2", optional = true } vcpkg = { version = "0.2", optional = true }

View File

@ -181,7 +181,10 @@ mod build_bundled {
if cfg!(feature = "bundled-sqlcipher-vendored-openssl") { if cfg!(feature = "bundled-sqlcipher-vendored-openssl") {
cfg.include(std::env::var("DEP_OPENSSL_INCLUDE").unwrap()); cfg.include(std::env::var("DEP_OPENSSL_INCLUDE").unwrap());
println!("cargo:rustc-link-lib=static=crypto"); // cargo will resolve downstream to the static lib in openssl-sys println!("cargo:rustc-link-lib=static=crypto"); // cargo will
// resolve downstream
// to the static
// lib in openssl-sys
} else if is_windows { } else if is_windows {
// FIXME README says that bundled-sqlcipher is Unix only, and the sources are // FIXME README says that bundled-sqlcipher is Unix only, and the sources are
// configured on a Unix machine. So maybe this should be made unreachable. // configured on a Unix machine. So maybe this should be made unreachable.

View File

@ -1,9 +1,9 @@
/* automatically generated by rust-bindgen 0.58.1 */ /* automatically generated by rust-bindgen 0.58.1 */
pub const SQLITE_VERSION: &'static [u8; 7usize] = b"3.35.5\0"; pub const SQLITE_VERSION: &'static [u8; 7usize] = b"3.36.0\0";
pub const SQLITE_VERSION_NUMBER: i32 = 3035005; pub const SQLITE_VERSION_NUMBER: i32 = 3036000;
pub const SQLITE_SOURCE_ID: &'static [u8; 85usize] = pub const SQLITE_SOURCE_ID: &'static [u8; 85usize] =
b"2021-04-19 18:32:05 1b256d97b553a9611efca188a3d995a2fff712759044ba480f9a0c9e98fae886\0"; b"2021-06-18 18:36:39 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5\0";
pub const SQLITE_OK: i32 = 0; pub const SQLITE_OK: i32 = 0;
pub const SQLITE_ERROR: i32 = 1; pub const SQLITE_ERROR: i32 = 1;
pub const SQLITE_INTERNAL: i32 = 2; pub const SQLITE_INTERNAL: i32 = 2;
@ -192,6 +192,8 @@ pub const SQLITE_FCNTL_SIZE_LIMIT: i32 = 36;
pub const SQLITE_FCNTL_CKPT_DONE: i32 = 37; pub const SQLITE_FCNTL_CKPT_DONE: i32 = 37;
pub const SQLITE_FCNTL_RESERVE_BYTES: i32 = 38; pub const SQLITE_FCNTL_RESERVE_BYTES: i32 = 38;
pub const SQLITE_FCNTL_CKPT_START: i32 = 39; pub const SQLITE_FCNTL_CKPT_START: i32 = 39;
pub const SQLITE_FCNTL_EXTERNAL_READER: i32 = 40;
pub const SQLITE_FCNTL_CKSM_FILE: i32 = 41;
pub const SQLITE_GET_LOCKPROXYFILE: i32 = 2; pub const SQLITE_GET_LOCKPROXYFILE: i32 = 2;
pub const SQLITE_SET_LOCKPROXYFILE: i32 = 3; pub const SQLITE_SET_LOCKPROXYFILE: i32 = 3;
pub const SQLITE_LAST_ERRNO: i32 = 4; pub const SQLITE_LAST_ERRNO: i32 = 4;
@ -389,7 +391,8 @@ pub const SQLITE_TESTCTRL_PRNG_SEED: i32 = 28;
pub const SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: i32 = 29; pub const SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: i32 = 29;
pub const SQLITE_TESTCTRL_SEEK_COUNT: i32 = 30; pub const SQLITE_TESTCTRL_SEEK_COUNT: i32 = 30;
pub const SQLITE_TESTCTRL_TRACEFLAGS: i32 = 31; pub const SQLITE_TESTCTRL_TRACEFLAGS: i32 = 31;
pub const SQLITE_TESTCTRL_LAST: i32 = 31; pub const SQLITE_TESTCTRL_TUNE: i32 = 32;
pub const SQLITE_TESTCTRL_LAST: i32 = 32;
pub const SQLITE_STATUS_MEMORY_USED: i32 = 0; pub const SQLITE_STATUS_MEMORY_USED: i32 = 0;
pub const SQLITE_STATUS_PAGECACHE_USED: i32 = 1; pub const SQLITE_STATUS_PAGECACHE_USED: i32 = 1;
pub const SQLITE_STATUS_PAGECACHE_OVERFLOW: i32 = 2; pub const SQLITE_STATUS_PAGECACHE_OVERFLOW: i32 = 2;

File diff suppressed because it is too large Load Diff

View File

@ -123,9 +123,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.35.5" #define SQLITE_VERSION "3.36.0"
#define SQLITE_VERSION_NUMBER 3035005 #define SQLITE_VERSION_NUMBER 3036000
#define SQLITE_SOURCE_ID "2021-04-19 18:32:05 1b256d97b553a9611efca188a3d995a2fff712759044ba480f9a0c9e98fae886" #define SQLITE_SOURCE_ID "2021-06-18 18:36:39 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers
@ -1128,6 +1128,23 @@ struct sqlite3_io_methods {
** file to the database file, but before the *-shm file is updated to ** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed. ** record the fact that the pages have been checkpointed.
** </ul> ** </ul>
**
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
** whether or not there is a database client in another process with a wal-mode
** transaction open on the database or not. It is only available on unix.The
** (void*) argument passed with this file-control should be a pointer to a
** value of type (int). The integer value is set to 1 if the database is a wal
** mode database and there exists at least one client in another process that
** currently has an SQL transaction open on the database. It is set to 0 if
** the database is not a wal-mode db, or if there is no such connection in any
** other process. This opcode cannot be used to detect transactions opened
** by clients within the current process, only within other processes.
** </ul>
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
** Used by the cksmvfs VFS module only.
** </ul>
*/ */
#define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
@ -1167,6 +1184,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_CKPT_DONE 37
#define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_RESERVE_BYTES 38
#define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_CKPT_START 39
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
/* deprecated names */ /* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@ -4179,6 +4198,15 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
** sqlite3_stmt_readonly() returns false for those commands. ** sqlite3_stmt_readonly() returns false for those commands.
**
** ^This routine returns false if there is any possibility that the
** statement might change the database file. ^A false return does
** not guarantee that the statement will change the database file.
** ^For example, an UPDATE statement might have a WHERE clause that
** makes it a no-op, but the sqlite3_stmt_readonly() result would still
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
** read-only no-op if the table already exists, but
** sqlite3_stmt_readonly() still returns false for such a statement.
*/ */
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
@ -4348,18 +4376,22 @@ typedef struct sqlite3_context sqlite3_context;
** contain embedded NULs. The result of expressions involving strings ** contain embedded NULs. The result of expressions involving strings
** with embedded NULs is undefined. ** with embedded NULs is undefined.
** **
** ^The fifth argument to the BLOB and string binding interfaces ** ^The fifth argument to the BLOB and string binding interfaces controls
** is a destructor used to dispose of the BLOB or ** or indicates the lifetime of the object referenced by the third parameter.
** string after SQLite has finished with it. ^The destructor is called ** These three options exist:
** to dispose of the BLOB or string even if the call to the bind API fails, ** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished
** except the destructor is not called if the third parameter is a NULL ** with it may be passed. ^It is called to dispose of the BLOB or string even
** pointer or the fourth parameter is negative. ** if the call to the bind API fails, except the destructor is not called if
** ^If the fifth argument is ** the third parameter is a NULL pointer or the fourth parameter is negative.
** the special value [SQLITE_STATIC], then SQLite assumes that the ** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
** information is in static, unmanaged space and does not need to be freed. ** the application remains responsible for disposing of the object. ^In this
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then ** case, the object and the provided pointer to it must remain valid until
** SQLite makes its own private copy of the data immediately, before ** either the prepared statement is finalized or the same SQL parameter is
** the sqlite3_bind_*() routine returns. ** bound to something else, whichever occurs sooner.
** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the
** object is to be copied prior to the return from sqlite3_bind_*(). ^The
** object and pointer to it must remain valid until then. ^SQLite will then
** manage the lifetime of its private copy.
** **
** ^The sixth argument to sqlite3_bind_text64() must be one of ** ^The sixth argument to sqlite3_bind_text64() must be one of
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
@ -5101,7 +5133,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions, ** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
** index expressions, or the WHERE clause of partial indexes. ** index expressions, or the WHERE clause of partial indexes.
** **
** <span style="background-color:#ffff90;">
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for ** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
** all application-defined SQL functions that do not need to be ** all application-defined SQL functions that do not need to be
** used inside of triggers, view, CHECK constraints, or other elements of ** used inside of triggers, view, CHECK constraints, or other elements of
@ -5111,7 +5142,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** a database file to include invocations of the function with parameters ** a database file to include invocations of the function with parameters
** chosen by the attacker, which the application will then execute when ** chosen by the attacker, which the application will then execute when
** the database file is opened and read. ** the database file is opened and read.
** </span>
** **
** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^ ** function can gain access to this pointer using [sqlite3_user_data()].)^
@ -7779,7 +7809,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
#define SQLITE_TESTCTRL_SEEK_COUNT 30 #define SQLITE_TESTCTRL_SEEK_COUNT 30
#define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_LAST 31 /* Largest TESTCTRL */ #define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */
/* /*
** CAPI3REF: SQL Keyword Checking ** CAPI3REF: SQL Keyword Checking
@ -9531,6 +9562,15 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; or 2 for changes resulting from triggers called by top-level
** triggers; and so forth. ** triggers; and so forth.
** **
** When the [sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
** callback made with op==SQLITE_DELETE is actuall a write using the
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
** regular DELETE, sqlite3_preupdate_blobwrite() returns -1.
**
** See also: [sqlite3_update_hook()] ** See also: [sqlite3_update_hook()]
*/ */
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) #if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
@ -9551,6 +9591,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
SQLITE_API int sqlite3_preupdate_count(sqlite3 *); SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *);
#endif #endif
/* /*
@ -9789,8 +9830,8 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs. ** allocation error occurs.
** **
** This interface is only available if SQLite is compiled with the ** This interface is omitted if SQLite is compiled with the
** [SQLITE_ENABLE_DESERIALIZE] option. ** [SQLITE_OMIT_DESERIALIZE] option.
*/ */
SQLITE_API unsigned char *sqlite3_serialize( SQLITE_API unsigned char *sqlite3_serialize(
sqlite3 *db, /* The database connection */ sqlite3 *db, /* The database connection */
@ -9841,8 +9882,8 @@ SQLITE_API unsigned char *sqlite3_serialize(
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [sqlite3_free()] is invoked on argument P prior to returning. ** [sqlite3_free()] is invoked on argument P prior to returning.
** **
** This interface is only available if SQLite is compiled with the ** This interface is omitted if SQLite is compiled with the
** [SQLITE_ENABLE_DESERIALIZE] option. ** [SQLITE_OMIT_DESERIALIZE] option.
*/ */
SQLITE_API int sqlite3_deserialize( SQLITE_API int sqlite3_deserialize(
sqlite3 *db, /* The database connection */ sqlite3 *db, /* The database connection */
@ -10091,6 +10132,38 @@ SQLITE_API int sqlite3session_create(
*/ */
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
** CAPIREF: Conigure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
** created. At present the only valid value for the second parameter is
** [SQLITE_SESSION_OBJCONFIG_SIZE].
**
** Arguments for sqlite3session_object_config()
**
** The following values may passed as the the 4th parameter to
** sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
** This option is used to set, clear or query the flag that enables
** the [sqlite3session_changeset_size()] API. Because it imposes some
** computational overhead, this API is disabled by default. Argument
** pArg must point to a value of type (int). If the value is initially
** 0, then the sqlite3session_changeset_size() API is disabled. If it
** is greater than 0, then the same API is enabled. Or, if the initial
** value is less than zero, no change is made. In all cases the (int)
** variable is set to 1 if the sqlite3session_changeset_size() API is
** enabled following the current call, or 0 otherwise.
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
*/
SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
/*
*/
#define SQLITE_SESSION_OBJCONFIG_SIZE 1
/* /*
** CAPI3REF: Enable Or Disable A Session Object ** CAPI3REF: Enable Or Disable A Session Object
@ -10335,6 +10408,22 @@ SQLITE_API int sqlite3session_changeset(
void **ppChangeset /* OUT: Buffer containing changeset */ void **ppChangeset /* OUT: Buffer containing changeset */
); );
/*
** CAPI3REF: Return An Upper-limit For The Size Of The Changeset
** METHOD: sqlite3_session
**
** By default, this function always returns 0. For it to return
** a useful result, the sqlite3_session object must have been configured
** to enable this API using sqlite3session_object_config() with the
** SQLITE_SESSION_OBJCONFIG_SIZE verb.
**
** When enabled, this function returns an upper limit, in bytes, for the size
** of the changeset that might be produced if sqlite3session_changeset() were
** called. The final changeset size might be equal to or smaller than the
** size in bytes returned by this function.
*/
SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession);
/* /*
** CAPI3REF: Load The Difference Between Tables Into A Session ** CAPI3REF: Load The Difference Between Tables Into A Session
** METHOD: sqlite3_session ** METHOD: sqlite3_session

View File

@ -1,4 +1,5 @@
#![allow(non_snake_case, non_camel_case_types)] #![allow(non_snake_case, non_camel_case_types)]
#![cfg_attr(test, allow(deref_nullptr))] // https://github.com/rust-lang/rust-bindgen/issues/2066
pub use self::error::*; pub use self::error::*;

View File

@ -12,7 +12,7 @@ export SQLCIPHER_LIB_DIR="$SCRIPT_DIR/sqlcipher"
export SQLCIPHER_INCLUDE_DIR="$SQLCIPHER_LIB_DIR" export SQLCIPHER_INCLUDE_DIR="$SQLCIPHER_LIB_DIR"
# Download and extract amalgamation # Download and extract amalgamation
SQLITE=sqlite-amalgamation-3350500 SQLITE=sqlite-amalgamation-3360000
curl -O https://sqlite.org/2021/$SQLITE.zip curl -O https://sqlite.org/2021/$SQLITE.zip
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.c" > "$SQLITE3_LIB_DIR/sqlite3.c" unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.c" > "$SQLITE3_LIB_DIR/sqlite3.c"
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.h" > "$SQLITE3_LIB_DIR/sqlite3.h" unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.h" > "$SQLITE3_LIB_DIR/sqlite3.h"

View File

@ -1,4 +1,4 @@
//! `feature = "backup"` Online SQLite backup API. //! Online SQLite backup API.
//! //!
//! 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
@ -40,11 +40,11 @@ use std::time::Duration;
use crate::ffi; use crate::ffi;
use crate::error::{error_from_handle, error_from_sqlite_code}; use crate::error::error_from_handle;
use crate::{Connection, DatabaseName, Result}; use crate::{Connection, DatabaseName, Result};
impl Connection { impl Connection {
/// `feature = "backup"` Back up the `name` database to the given /// Back up the `name` database to the given
/// destination path. /// destination path.
/// ///
/// If `progress` is not `None`, it will be called periodically /// If `progress` is not `None`, it will be called periodically
@ -84,7 +84,7 @@ impl Connection {
} }
} }
/// `feature = "backup"` Restore the given source path into the /// Restore the given source path into the
/// `name` database. If `progress` is not `None`, it will be /// `name` database. If `progress` is not `None`, it will be
/// called periodically until the restore completes. /// called periodically until the restore completes.
/// ///
@ -131,7 +131,7 @@ impl Connection {
} }
} }
/// `feature = "backup"` Possible successful results of calling /// Possible successful results of calling
/// [`Backup::step`]. /// [`Backup::step`].
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
@ -152,7 +152,7 @@ pub enum StepResult {
Locked, Locked,
} }
/// `feature = "backup"` Struct specifying the progress of a backup. The /// 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 /// pagecount`. The progress of a backup is as of the last call to
/// [`step`](Backup::step) - if the source database is modified after a call to /// [`step`](Backup::step) - if the source database is modified after a call to
@ -166,10 +166,10 @@ pub struct Progress {
pub pagecount: c_int, pub pagecount: c_int,
} }
/// `feature = "backup"` A handle to an online backup. /// A handle to an online backup.
pub struct Backup<'a, 'b> { pub struct Backup<'a, 'b> {
phantom_from: PhantomData<&'a Connection>, phantom_from: PhantomData<&'a Connection>,
phantom_to: PhantomData<&'b Connection>, to: &'b Connection,
b: *mut ffi::sqlite3_backup, b: *mut ffi::sqlite3_backup,
} }
@ -223,7 +223,7 @@ impl Backup<'_, '_> {
Ok(Backup { Ok(Backup {
phantom_from: PhantomData, phantom_from: PhantomData,
phantom_to: PhantomData, to,
b, b,
}) })
} }
@ -263,7 +263,7 @@ impl Backup<'_, '_> {
ffi::SQLITE_OK => Ok(More), ffi::SQLITE_OK => Ok(More),
ffi::SQLITE_BUSY => Ok(Busy), ffi::SQLITE_BUSY => Ok(Busy),
ffi::SQLITE_LOCKED => Ok(Locked), ffi::SQLITE_LOCKED => Ok(Locked),
_ => Err(error_from_sqlite_code(rc, None)), _ => self.to.decode_result(rc).map(|_| More),
} }
} }

View File

@ -1,4 +1,4 @@
//! `feature = "blob"` Incremental BLOB I/O. //! Incremental BLOB I/O.
//! //!
//! Note that SQLite does not provide API-level access to change the size of a //! Note that SQLite does not provide API-level access to change the size of a
//! BLOB; that must be performed through SQL statements. //! BLOB; that must be performed through SQL statements.
@ -196,7 +196,7 @@ use crate::{Connection, DatabaseName, Result};
mod pos_io; mod pos_io;
/// `feature = "blob"` Handle to an open BLOB. See /// Handle to an open BLOB. See
/// [`rusqlite::blob`](crate::blob) documentation for in-depth discussion. /// [`rusqlite::blob`](crate::blob) documentation for in-depth discussion.
pub struct Blob<'conn> { pub struct Blob<'conn> {
conn: &'conn Connection, conn: &'conn Connection,
@ -206,7 +206,7 @@ pub struct Blob<'conn> {
} }
impl Connection { impl Connection {
/// `feature = "blob"` Open a handle to the BLOB located in `row_id`, /// Open a handle to the BLOB located in `row_id`,
/// `column`, `table` in database `db`. /// `column`, `table` in database `db`.
/// ///
/// # Failure /// # Failure
@ -223,7 +223,7 @@ impl Connection {
row_id: i64, row_id: i64,
read_only: bool, read_only: bool,
) -> Result<Blob<'a>> { ) -> Result<Blob<'a>> {
let mut c = self.db.borrow_mut(); let c = self.db.borrow_mut();
let mut blob = ptr::null_mut(); let mut blob = ptr::null_mut();
let db = db.as_cstring()?; let db = db.as_cstring()?;
let table = super::str_to_cstring(table)?; let table = super::str_to_cstring(table)?;
@ -400,7 +400,7 @@ impl Drop for Blob<'_> {
} }
} }
/// `feature = "blob"` 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 /// Zeroblobs are intended to serve as placeholders for BLOBs whose content is
/// later written using incremental BLOB I/O routines. /// later written using incremental BLOB I/O routines.

View File

@ -44,15 +44,14 @@ impl<'conn> Blob<'conn> {
// losslessly converted to i32, since `len` came from an i32. // losslessly converted to i32, since `len` came from an i32.
// Sanity check the above. // Sanity check the above.
debug_assert!(i32::try_from(write_start).is_ok() && i32::try_from(buf.len()).is_ok()); debug_assert!(i32::try_from(write_start).is_ok() && i32::try_from(buf.len()).is_ok());
unsafe { self.conn.decode_result(unsafe {
check!(ffi::sqlite3_blob_write( ffi::sqlite3_blob_write(
self.blob, self.blob,
buf.as_ptr() as *const _, buf.as_ptr() as *const _,
buf.len() as i32, buf.len() as i32,
write_start as i32, write_start as i32,
)); )
} })
Ok(())
} }
/// An alias for `write_at` provided for compatibility with the conceptually /// An alias for `write_at` provided for compatibility with the conceptually
@ -151,12 +150,12 @@ impl<'conn> Blob<'conn> {
debug_assert!(i32::try_from(read_len).is_ok()); debug_assert!(i32::try_from(read_len).is_ok());
unsafe { unsafe {
check!(ffi::sqlite3_blob_read( self.conn.decode_result(ffi::sqlite3_blob_read(
self.blob, self.blob,
buf.as_mut_ptr() as *mut _, buf.as_mut_ptr() as *mut _,
read_len as i32, read_len as i32,
read_start as i32, read_start as i32,
)); ))?;
Ok(from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, read_len)) Ok(from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, read_len))
} }

View File

@ -64,7 +64,7 @@ impl Connection {
0 0
} }
} }
let mut c = self.db.borrow_mut(); let c = self.db.borrow_mut();
let r = match callback { let r = match callback {
Some(f) => unsafe { Some(f) => unsafe {
ffi::sqlite3_busy_handler(c.db(), Some(busy_handler_callback), f as *mut c_void) ffi::sqlite3_busy_handler(c.db(), Some(busy_handler_callback), f as *mut c_void)

View File

@ -1,4 +1,4 @@
//! `feature = "collation"` Add, remove, or modify a collation //! Add, remove, or modify a collation
use std::cmp::Ordering; use std::cmp::Ordering;
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::panic::{catch_unwind, UnwindSafe}; use std::panic::{catch_unwind, UnwindSafe};
@ -14,7 +14,7 @@ unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
} }
impl Connection { impl Connection {
/// `feature = "collation"` Add or modify a collation. /// Add or modify a collation.
#[inline] #[inline]
pub fn create_collation<'c, C>(&'c self, collation_name: &str, x_compare: C) -> Result<()> pub fn create_collation<'c, C>(&'c self, collation_name: &str, x_compare: C) -> Result<()>
where where
@ -25,7 +25,7 @@ impl Connection {
.create_collation(collation_name, x_compare) .create_collation(collation_name, x_compare)
} }
/// `feature = "collation"` Collation needed callback /// Collation needed callback
#[inline] #[inline]
pub fn collation_needed( pub fn collation_needed(
&self, &self,
@ -34,7 +34,7 @@ impl Connection {
self.db.borrow_mut().collation_needed(x_coll_needed) self.db.borrow_mut().collation_needed(x_coll_needed)
} }
/// `feature = "collation"` Remove collation. /// Remove collation.
#[inline] #[inline]
pub fn remove_collation(&self, collation_name: &str) -> Result<()> { pub fn remove_collation(&self, collation_name: &str) -> Result<()> {
self.db.borrow_mut().remove_collation(collation_name) self.db.borrow_mut().remove_collation(collation_name)

View File

@ -132,6 +132,7 @@ impl Statement<'_> {
/// sure that current statement has already been stepped once before /// sure that current statement has already been stepped once before
/// calling this method. /// calling this method.
#[cfg(feature = "column_decltype")] #[cfg(feature = "column_decltype")]
#[cfg_attr(docsrs, doc(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();
let mut cols = Vec::with_capacity(n as usize); let mut cols = Vec::with_capacity(n as usize);

View File

@ -2,6 +2,7 @@
use std::os::raw::c_int; use std::os::raw::c_int;
use crate::error::check;
use crate::ffi; use crate::ffi;
use crate::{Connection, Result}; use crate::{Connection, Result};
@ -80,12 +81,12 @@ impl Connection {
let c = self.db.borrow(); let c = self.db.borrow();
unsafe { unsafe {
let mut val = 0; let mut val = 0;
check!(ffi::sqlite3_db_config( check(ffi::sqlite3_db_config(
c.db(), c.db(),
config as c_int, config as c_int,
-1, -1,
&mut val &mut val,
)); ))?;
Ok(val != 0) Ok(val != 0)
} }
} }
@ -109,12 +110,12 @@ impl Connection {
let c = self.db.borrow_mut(); let c = self.db.borrow_mut();
unsafe { unsafe {
let mut val = 0; let mut val = 0;
check!(ffi::sqlite3_db_config( check(ffi::sqlite3_db_config(
c.db(), c.db(),
config as c_int, config as c_int,
if new_val { 1 } else { 0 }, if new_val { 1 } else { 0 },
&mut val &mut val,
)); ))?;
Ok(val != 0) Ok(val != 0)
} }
} }

View File

@ -1,6 +1,6 @@
use crate::types::FromSqlError; use crate::types::FromSqlError;
use crate::types::Type; use crate::types::Type;
use crate::{errmsg_to_string, ffi}; use crate::{errmsg_to_string, ffi, Result};
use std::error; use std::error;
use std::fmt; use std::fmt;
use std::os::raw::c_int; use std::os::raw::c_int;
@ -72,15 +72,18 @@ pub enum Error {
/// [`functions::Context::get`](crate::functions::Context::get) when the /// [`functions::Context::get`](crate::functions::Context::get) when the
/// function argument cannot be converted to the requested type. /// function argument cannot be converted to the requested type.
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
InvalidFunctionParameterType(usize, Type), InvalidFunctionParameterType(usize, Type),
/// Error returned by [`vtab::Values::get`](crate::vtab::Values::get) when /// Error returned by [`vtab::Values::get`](crate::vtab::Values::get) when
/// the filter argument cannot be converted to the requested type. /// the filter argument cannot be converted to the requested type.
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
InvalidFilterParameterType(usize, Type), InvalidFilterParameterType(usize, Type),
/// An error case available for implementors of custom user functions (e.g., /// An error case available for implementors of custom user functions (e.g.,
/// [`create_scalar_function`](crate::Connection::create_scalar_function)). /// [`create_scalar_function`](crate::Connection::create_scalar_function)).
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
#[allow(dead_code)] #[allow(dead_code)]
UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>), UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
@ -94,11 +97,13 @@ pub enum Error {
/// An error case available for implementors of custom modules (e.g., /// An error case available for implementors of custom modules (e.g.,
/// [`create_module`](crate::Connection::create_module)). /// [`create_module`](crate::Connection::create_module)).
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
#[allow(dead_code)] #[allow(dead_code)]
ModuleError(String), ModuleError(String),
/// An unwinding panic occurs in an UDF (user-defined function). /// An unwinding panic occurs in an UDF (user-defined function).
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
UnwindingPanic, UnwindingPanic,
/// An error returned when /// An error returned when
@ -106,6 +111,7 @@ pub enum Error {
/// retrieve data of a different type than what had been stored using /// retrieve data of a different type than what had been stored using
/// [`Context::set_aux`](crate::functions::Context::set_aux). /// [`Context::set_aux`](crate::functions::Context::set_aux).
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
GetAuxWrongType, GetAuxWrongType,
/// Error when the SQL contains multiple statements. /// Error when the SQL contains multiple statements.
@ -120,6 +126,7 @@ pub enum Error {
/// [`Blob::raw_read_at_exact`](crate::blob::Blob::raw_read_at_exact) will /// [`Blob::raw_read_at_exact`](crate::blob::Blob::raw_read_at_exact) will
/// return it if the blob has insufficient data. /// return it if the blob has insufficient data.
#[cfg(feature = "blob")] #[cfg(feature = "blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
BlobSizeError, BlobSizeError,
} }
@ -350,11 +357,10 @@ pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
error_from_sqlite_code(code, message) error_from_sqlite_code(code, message)
} }
macro_rules! check { pub fn check(code: c_int) -> Result<()> {
($funcall:expr) => {{ if code != crate::ffi::SQLITE_OK {
let rc = $funcall; Err(crate::error::error_from_sqlite_code(code, None))
if rc != crate::ffi::SQLITE_OK { } else {
return Err(crate::error::error_from_sqlite_code(rc, None).into()); Ok(())
} }
}};
} }

View File

@ -1,4 +1,4 @@
//! `feature = "functions"` Create or redefine SQL functions. //! Create or redefine SQL functions.
//! //!
//! # Example //! # Example
//! //!
@ -104,7 +104,7 @@ unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
drop(Box::from_raw(p as *mut T)); drop(Box::from_raw(p as *mut T));
} }
/// `feature = "functions"` Context is a wrapper for the SQLite function /// Context is a wrapper for the SQLite function
/// evaluation context. /// evaluation context.
pub struct Context<'a> { pub struct Context<'a> {
ctx: *mut sqlite3_context, ctx: *mut sqlite3_context,
@ -260,7 +260,7 @@ impl Deref for ConnectionRef<'_> {
type AuxInner = Arc<dyn Any + Send + Sync + 'static>; type AuxInner = Arc<dyn Any + Send + Sync + 'static>;
/// `feature = "functions"` Aggregate is the callback interface for user-defined /// Aggregate is the callback interface for user-defined
/// aggregate function. /// aggregate function.
/// ///
/// `A` is the type of the aggregation context and `T` is the type of the final /// `A` is the type of the aggregation context and `T` is the type of the final
@ -292,9 +292,10 @@ where
fn finalize(&self, _: &mut Context<'_>, _: Option<A>) -> Result<T>; fn finalize(&self, _: &mut Context<'_>, _: Option<A>) -> Result<T>;
} }
/// `feature = "window"` WindowAggregate is the callback interface for /// WindowAggregate is the callback interface for
/// user-defined aggregate window function. /// user-defined aggregate window function.
#[cfg(feature = "window")] #[cfg(feature = "window")]
#[cfg_attr(docsrs, doc(cfg(feature = "window")))]
pub trait WindowAggregate<A, T>: Aggregate<A, T> pub trait WindowAggregate<A, T>: Aggregate<A, T>
where where
A: RefUnwindSafe + UnwindSafe, A: RefUnwindSafe + UnwindSafe,
@ -341,7 +342,7 @@ impl Default for FunctionFlags {
} }
impl Connection { impl Connection {
/// `feature = "functions"` Attach a user-defined scalar function to /// Attach a user-defined scalar function to
/// this database connection. /// 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.
@ -395,7 +396,7 @@ impl Connection {
.create_scalar_function(fn_name, n_arg, flags, x_func) .create_scalar_function(fn_name, n_arg, flags, x_func)
} }
/// `feature = "functions"` Attach a user-defined aggregate function to this /// Attach a user-defined aggregate function to this
/// database connection. /// database connection.
/// ///
/// # Failure /// # Failure
@ -419,12 +420,13 @@ impl Connection {
.create_aggregate_function(fn_name, n_arg, flags, aggr) .create_aggregate_function(fn_name, n_arg, flags, aggr)
} }
/// `feature = "window"` Attach a user-defined aggregate window function to /// Attach a user-defined aggregate window function to
/// this database connection. /// this database connection.
/// ///
/// See `https://sqlite.org/windowfunctions.html#udfwinfunc` for more /// See `https://sqlite.org/windowfunctions.html#udfwinfunc` for more
/// information. /// information.
#[cfg(feature = "window")] #[cfg(feature = "window")]
#[cfg_attr(docsrs, doc(cfg(feature = "window")))]
#[inline] #[inline]
pub fn create_window_function<A, W, T>( pub fn create_window_function<A, W, T>(
&self, &self,
@ -443,7 +445,7 @@ impl Connection {
.create_window_function(fn_name, n_arg, flags, aggr) .create_window_function(fn_name, n_arg, flags, aggr)
} }
/// `feature = "functions"` Removes a user-defined function from this /// Removes a user-defined function from this
/// 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

View File

@ -1,4 +1,4 @@
//! `feature = "hooks"` Commit, Data Change and Rollback Notification Callbacks //! Commit, Data Change and Rollback Notification Callbacks
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
@ -9,7 +9,7 @@ use crate::ffi;
use crate::{Connection, InnerConnection}; use crate::{Connection, InnerConnection};
/// `feature = "hooks"` Action Codes /// Action Codes
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[repr(i32)] #[repr(i32)]
#[non_exhaustive] #[non_exhaustive]
@ -37,23 +37,23 @@ impl From<i32> for Action {
} }
} }
/// `feature = "hooks"` The context recieved by an authorizer hook. /// The context recieved by an authorizer hook.
/// ///
/// See <https://sqlite.org/c3ref/set_authorizer.html> for more info. /// See <https://sqlite.org/c3ref/set_authorizer.html> for more info.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct AuthContext<'c> { pub struct AuthContext<'c> {
// The action to be authorized. /// The action to be authorized.
pub action: AuthAction<'c>, pub action: AuthAction<'c>,
/// The database name, if applicable. /// The database name, if applicable.
pub database_name: Option<&'c str>, pub database_name: Option<&'c str>,
// The inner-most trigger or view responsible for the access attempt. /// The inner-most trigger or view responsible for the access attempt.
// `None` if the access attempt was made by top-level SQL code. /// `None` if the access attempt was made by top-level SQL code.
pub accessor: Option<&'c str>, pub accessor: Option<&'c str>,
} }
/// `feature = "hooks"` Actions and arguments found within a statement during /// Actions and arguments found within a statement during
/// preparation. /// preparation.
/// ///
/// See <https://sqlite.org/c3ref/c_alter_table.html> for more info. /// See <https://sqlite.org/c3ref/c_alter_table.html> for more info.
@ -254,7 +254,7 @@ impl<'c> AuthAction<'c> {
table_name, table_name,
column_name, column_name,
}, },
(ffi::SQLITE_SELECT, _, _) => Self::Select, (ffi::SQLITE_SELECT, ..) => Self::Select,
(ffi::SQLITE_TRANSACTION, Some(operation_str), _) => Self::Transaction { (ffi::SQLITE_TRANSACTION, Some(operation_str), _) => Self::Transaction {
operation: TransactionOperation::from_str(operation_str), operation: TransactionOperation::from_str(operation_str),
}, },
@ -286,7 +286,7 @@ impl<'c> AuthAction<'c> {
savepoint_name, savepoint_name,
}, },
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
(ffi::SQLITE_RECURSIVE, _, _) => Self::Recursive, (ffi::SQLITE_RECURSIVE, ..) => Self::Recursive,
(code, arg1, arg2) => Self::Unknown { code, arg1, arg2 }, (code, arg1, arg2) => Self::Unknown { code, arg1, arg2 },
} }
} }
@ -295,9 +295,10 @@ impl<'c> AuthAction<'c> {
pub(crate) type BoxedAuthorizer = pub(crate) type BoxedAuthorizer =
Box<dyn for<'c> FnMut(AuthContext<'c>) -> Authorization + Send + 'static>; Box<dyn for<'c> FnMut(AuthContext<'c>) -> Authorization + Send + 'static>;
/// `feature = "hooks"` A transaction operation. /// A transaction operation.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive] #[non_exhaustive]
#[allow(missing_docs)]
pub enum TransactionOperation { pub enum TransactionOperation {
Unknown, Unknown,
Begin, Begin,
@ -316,6 +317,7 @@ impl TransactionOperation {
} }
} }
/// [`authorizer`](Connection::authorizer) return code
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive] #[non_exhaustive]
pub enum Authorization { pub enum Authorization {
@ -338,7 +340,7 @@ impl Authorization {
} }
impl Connection { impl Connection {
/// `feature = "hooks"` Register a callback function to be invoked whenever /// Register a callback function to be invoked whenever
/// a transaction is committed. /// a transaction is committed.
/// ///
/// The callback returns `true` to rollback. /// The callback returns `true` to rollback.
@ -350,7 +352,7 @@ impl Connection {
self.db.borrow_mut().commit_hook(hook); self.db.borrow_mut().commit_hook(hook);
} }
/// `feature = "hooks"` Register a callback function to be invoked whenever /// Register a callback function to be invoked whenever
/// a transaction is committed. /// a transaction is committed.
/// ///
/// The callback returns `true` to rollback. /// The callback returns `true` to rollback.
@ -362,7 +364,7 @@ impl Connection {
self.db.borrow_mut().rollback_hook(hook); self.db.borrow_mut().rollback_hook(hook);
} }
/// `feature = "hooks"` Register a callback function to be invoked whenever /// Register a callback function to be invoked whenever
/// a row is updated, inserted or deleted in a rowid table. /// a row is updated, inserted or deleted in a rowid table.
/// ///
/// The callback parameters are: /// The callback parameters are:
@ -380,7 +382,7 @@ impl Connection {
self.db.borrow_mut().update_hook(hook); self.db.borrow_mut().update_hook(hook);
} }
/// `feature = "hooks"` Register a query progress callback. /// Register a query progress callback.
/// ///
/// The parameter `num_ops` is the approximate number of virtual machine /// The parameter `num_ops` is the approximate number of virtual machine
/// instructions that are evaluated between successive invocations of the /// instructions that are evaluated between successive invocations of the
@ -395,7 +397,7 @@ impl Connection {
self.db.borrow_mut().progress_handler(num_ops, handler); self.db.borrow_mut().progress_handler(num_ops, handler);
} }
/// `feature = "hooks"` Register an authorizer callback that's invoked /// Register an authorizer callback that's invoked
/// as a statement is being prepared. /// as a statement is being prepared.
#[inline] #[inline]
pub fn authorizer<'c, F>(&self, hook: Option<F>) pub fn authorizer<'c, F>(&self, hook: Option<F>)
@ -597,7 +599,7 @@ impl InnerConnection {
}; };
} }
pub fn authorizer<'c, F>(&'c mut self, authorizer: Option<F>) fn authorizer<'c, F>(&'c mut self, authorizer: Option<F>)
where where
F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + RefUnwindSafe + 'static, F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + RefUnwindSafe + 'static,
{ {

View File

@ -136,7 +136,7 @@ impl InnerConnection {
} }
#[inline] #[inline]
pub fn decode_result(&mut self, code: c_int) -> Result<()> { pub fn decode_result(&self, code: c_int) -> Result<()> {
unsafe { InnerConnection::decode_result_raw(self.db(), code) } unsafe { InnerConnection::decode_result_raw(self.db(), code) }
} }
@ -278,7 +278,7 @@ impl InnerConnection {
} }
#[inline] #[inline]
pub fn changes(&mut self) -> usize { pub fn changes(&self) -> usize {
unsafe { ffi::sqlite3_changes(self.db()) as usize } unsafe { ffi::sqlite3_changes(self.db()) as usize }
} }
@ -302,6 +302,11 @@ impl InnerConnection {
false false
} }
#[cfg(feature = "modern_sqlite")] // 3.10.0
pub fn cache_flush(&mut self) -> Result<()> {
crate::error::check(unsafe { ffi::sqlite3_db_cacheflush(self.db()) })
}
#[cfg(not(feature = "hooks"))] #[cfg(not(feature = "hooks"))]
#[inline] #[inline]
fn remove_hooks(&mut self) {} fn remove_hooks(&mut self) {}

View File

@ -48,6 +48,7 @@
//! } //! }
//! ``` //! ```
#![warn(missing_docs)] #![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub use libsqlite3_sys as ffi; pub use libsqlite3_sys as ffi;
@ -73,8 +74,6 @@ pub use crate::cache::CachedStatement;
pub use crate::column::Column; pub use crate::column::Column;
pub use crate::error::Error; pub use crate::error::Error;
pub use crate::ffi::ErrorCode; pub use crate::ffi::ErrorCode;
#[cfg(feature = "hooks")]
pub use crate::hooks::Action;
#[cfg(feature = "load_extension")] #[cfg(feature = "load_extension")]
pub use crate::load_extension_guard::LoadExtensionGuard; pub use crate::load_extension_guard::LoadExtensionGuard;
pub use crate::params::{params_from_iter, Params, ParamsFromIter}; pub use crate::params::{params_from_iter, Params, ParamsFromIter};
@ -84,27 +83,32 @@ pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBe
pub use crate::types::ToSql; pub use crate::types::ToSql;
pub use crate::version::*; pub use crate::version::*;
#[macro_use]
mod error; mod error;
#[cfg(feature = "backup")] #[cfg(feature = "backup")]
#[cfg_attr(docsrs, doc(cfg(feature = "backup")))]
pub mod backup; pub mod backup;
#[cfg(feature = "blob")] #[cfg(feature = "blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
pub mod blob; pub mod blob;
mod busy; mod busy;
mod cache; mod cache;
#[cfg(feature = "collation")] #[cfg(feature = "collation")]
#[cfg_attr(docsrs, doc(cfg(feature = "collation")))]
mod collation; mod collation;
mod column; mod column;
pub mod config; pub mod config;
#[cfg(any(feature = "functions", feature = "vtab"))] #[cfg(any(feature = "functions", feature = "vtab"))]
mod context; mod context;
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
pub mod functions; pub mod functions;
#[cfg(feature = "hooks")] #[cfg(feature = "hooks")]
mod hooks; #[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]
pub mod hooks;
mod inner_connection; mod inner_connection;
#[cfg(feature = "limits")] #[cfg(feature = "limits")]
#[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
pub mod limits; pub mod limits;
#[cfg(feature = "load_extension")] #[cfg(feature = "load_extension")]
mod load_extension_guard; mod load_extension_guard;
@ -113,15 +117,18 @@ mod pragma;
mod raw_statement; mod raw_statement;
mod row; mod row;
#[cfg(feature = "session")] #[cfg(feature = "session")]
#[cfg_attr(docsrs, doc(cfg(feature = "session")))]
pub mod session; pub mod session;
mod statement; mod statement;
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
#[cfg_attr(docsrs, doc(cfg(feature = "trace")))]
pub mod trace; pub mod trace;
mod transaction; mod transaction;
pub mod types; pub mod types;
mod unlock_notify; mod unlock_notify;
mod version; mod version;
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
pub mod vtab; pub mod vtab;
pub(crate) mod util; pub(crate) mod util;
@ -672,7 +679,7 @@ impl Connection {
stmt.check_no_tail()?; stmt.check_no_tail()?;
let mut rows = stmt.query(params)?; let mut rows = stmt.query(params)?;
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))
} }
/// Prepare a SQL statement for execution. /// Prepare a SQL statement for execution.
@ -714,7 +721,7 @@ impl Connection {
r.map_err(move |err| (self, err)) r.map_err(move |err| (self, err))
} }
/// `feature = "load_extension"` Enable loading of SQLite extensions. /// Enable loading of SQLite extensions.
/// Strongly consider using `LoadExtensionGuard` instead of this function. /// Strongly consider using `LoadExtensionGuard` instead of this function.
/// ///
/// ## Example /// ## Example
@ -733,12 +740,13 @@ impl Connection {
/// ///
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
#[cfg(feature = "load_extension")] #[cfg(feature = "load_extension")]
#[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
#[inline] #[inline]
pub fn load_extension_enable(&self) -> Result<()> { pub fn load_extension_enable(&self) -> Result<()> {
self.db.borrow_mut().enable_load_extension(1) self.db.borrow_mut().enable_load_extension(1)
} }
/// `feature = "load_extension"` Disable loading of SQLite extensions. /// Disable loading of SQLite extensions.
/// ///
/// See `load_extension_enable` for an example. /// See `load_extension_enable` for an example.
/// ///
@ -746,12 +754,13 @@ impl Connection {
/// ///
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
#[cfg(feature = "load_extension")] #[cfg(feature = "load_extension")]
#[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
#[inline] #[inline]
pub fn load_extension_disable(&self) -> Result<()> { pub fn load_extension_disable(&self) -> Result<()> {
self.db.borrow_mut().enable_load_extension(0) self.db.borrow_mut().enable_load_extension(0)
} }
/// `feature = "load_extension"` Load the SQLite extension at `dylib_path`. /// Load the SQLite extension at `dylib_path`.
/// `dylib_path` is passed through to `sqlite3_load_extension`, which may /// `dylib_path` is passed through to `sqlite3_load_extension`, which may
/// attempt OS-specific modifications if the file cannot be loaded directly. /// attempt OS-specific modifications if the file cannot be loaded directly.
/// ///
@ -775,6 +784,7 @@ impl Connection {
/// ///
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
#[cfg(feature = "load_extension")] #[cfg(feature = "load_extension")]
#[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
#[inline] #[inline]
pub fn load_extension<P: AsRef<Path>>( pub fn load_extension<P: AsRef<Path>>(
&self, &self,
@ -832,7 +842,7 @@ impl Connection {
#[inline] #[inline]
fn decode_result(&self, code: c_int) -> Result<()> { fn decode_result(&self, code: c_int) -> Result<()> {
self.db.borrow_mut().decode_result(code) self.db.borrow().decode_result(code)
} }
/// Return the number of rows modified, inserted or deleted by the most /// Return the number of rows modified, inserted or deleted by the most
@ -840,7 +850,7 @@ impl Connection {
/// connection. /// connection.
#[inline] #[inline]
fn changes(&self) -> usize { fn changes(&self) -> usize {
self.db.borrow_mut().changes() self.db.borrow().changes()
} }
/// Test for auto-commit mode. /// Test for auto-commit mode.
@ -853,9 +863,17 @@ impl Connection {
/// Determine if all associated prepared statements have been reset. /// Determine if all associated prepared statements have been reset.
#[inline] #[inline]
#[cfg(feature = "modern_sqlite")] // 3.8.6 #[cfg(feature = "modern_sqlite")] // 3.8.6
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn is_busy(&self) -> bool { pub fn is_busy(&self) -> bool {
self.db.borrow().is_busy() self.db.borrow().is_busy()
} }
/// Flush caches to disk mid-transaction
#[cfg(feature = "modern_sqlite")] // 3.10.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn cache_flush(&self) -> Result<()> {
self.db.borrow_mut().cache_flush()
}
} }
impl fmt::Debug for Connection { impl fmt::Debug for Connection {
@ -1064,7 +1082,7 @@ mod test {
ensure_sync::<InterruptHandle>(); ensure_sync::<InterruptHandle>();
} }
pub fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Connection {
Connection::open_in_memory().unwrap() Connection::open_in_memory().unwrap()
} }
@ -1192,7 +1210,7 @@ mod test {
#[test] #[test]
fn test_close_retry() -> Result<()> { fn test_close_retry() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
// force the DB to be busy by preparing a statement; this must be done at the // force the DB to be busy by preparing a statement; this must be done at the
// FFI level to allow us to call .close() without dropping the prepared // FFI level to allow us to call .close() without dropping the prepared
@ -1245,7 +1263,7 @@ mod test {
#[test] #[test]
fn test_execute_batch() -> Result<()> { fn test_execute_batch() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(1); INSERT INTO foo VALUES(1);
@ -1263,7 +1281,7 @@ mod test {
#[test] #[test]
fn test_execute() -> Result<()> { fn test_execute() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER)")?; db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [1i32])?); assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [1i32])?);
@ -1304,7 +1322,7 @@ mod test {
#[test] #[test]
fn test_prepare_column_names() -> Result<()> { fn test_prepare_column_names() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER);")?; db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let stmt = db.prepare("SELECT * FROM foo")?; let stmt = db.prepare("SELECT * FROM foo")?;
@ -1319,7 +1337,7 @@ mod test {
#[test] #[test]
fn test_prepare_execute() -> Result<()> { fn test_prepare_execute() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER);")?; db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?; let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
@ -1340,7 +1358,7 @@ mod test {
#[test] #[test]
fn test_prepare_query() -> Result<()> { fn test_prepare_query() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER);")?; db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?; let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
@ -1375,7 +1393,7 @@ mod test {
#[test] #[test]
fn test_query_map() -> Result<()> { fn test_query_map() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1394,7 +1412,7 @@ mod test {
#[test] #[test]
fn test_query_row() -> Result<()> { fn test_query_row() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(1); INSERT INTO foo VALUES(1);
@ -1423,7 +1441,7 @@ mod test {
#[test] #[test]
fn test_optional() -> Result<()> { fn test_optional() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 <> 0", [], |r| r.get(0)); let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 <> 0", [], |r| r.get(0));
let result = result.optional(); let result = result.optional();
@ -1447,7 +1465,7 @@ mod test {
#[test] #[test]
fn test_pragma_query_row() -> Result<()> { fn test_pragma_query_row() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
assert_eq!( assert_eq!(
"memory", "memory",
@ -1462,7 +1480,7 @@ mod test {
#[test] #[test]
fn test_prepare_failures() -> Result<()> { fn test_prepare_failures() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER);")?; db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err(); let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
@ -1472,7 +1490,7 @@ mod test {
#[test] #[test]
fn test_last_insert_rowid() -> Result<()> { fn test_last_insert_rowid() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?; db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
db.execute_batch("INSERT INTO foo DEFAULT VALUES")?; db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
@ -1487,18 +1505,19 @@ mod test {
} }
#[test] #[test]
fn test_is_autocommit() { fn test_is_autocommit() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
assert!( assert!(
db.is_autocommit(), db.is_autocommit(),
"autocommit expected to be active by default" "autocommit expected to be active by default"
); );
Ok(())
} }
#[test] #[test]
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
fn test_is_busy() -> Result<()> { fn test_is_busy() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
assert!(!db.is_busy()); assert!(!db.is_busy());
let mut stmt = db.prepare("PRAGMA schema_version")?; let mut stmt = db.prepare("PRAGMA schema_version")?;
assert!(!db.is_busy()); assert!(!db.is_busy());
@ -1515,7 +1534,7 @@ mod test {
#[test] #[test]
fn test_statement_debugging() -> Result<()> { fn test_statement_debugging() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let query = "SELECT 12345"; let query = "SELECT 12345";
let stmt = db.prepare(query)?; let stmt = db.prepare(query)?;
@ -1534,7 +1553,7 @@ mod test {
#[cfg(not(feature = "modern_sqlite"))] #[cfg(not(feature = "modern_sqlite"))]
fn check_extended_code(_extended_code: c_int) {} fn check_extended_code(_extended_code: c_int) {}
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x NOT NULL)")?; db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []); let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
@ -1563,7 +1582,7 @@ mod test {
#[test] #[test]
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
fn test_interrupt() -> Result<()> { fn test_interrupt() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let interrupt_handle = db.get_interrupt_handle(); let interrupt_handle = db.get_interrupt_handle();
@ -1611,7 +1630,7 @@ mod test {
#[test] #[test]
fn test_get_raw() -> Result<()> { fn test_get_raw() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(i, x);")?; db.execute_batch("CREATE TABLE foo(i, x);")?;
let vals = ["foobar", "1234", "qwerty"]; let vals = ["foobar", "1234", "qwerty"];
let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?, ?)")?; let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?, ?)")?;
@ -1644,7 +1663,7 @@ mod test {
#[test] #[test]
fn test_from_handle() -> Result<()> { fn test_from_handle() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let handle = unsafe { db.handle() }; let handle = unsafe { db.handle() };
{ {
let db = unsafe { Connection::from_handle(handle) }?; let db = unsafe { Connection::from_handle(handle) }?;
@ -1696,7 +1715,7 @@ mod test {
#[test] #[test]
fn test_query_and_then() -> Result<()> { fn test_query_and_then() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1716,7 +1735,7 @@ mod test {
#[test] #[test]
fn test_query_and_then_fails() -> Result<()> { fn test_query_and_then_fails() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1746,7 +1765,7 @@ mod test {
#[test] #[test]
fn test_query_and_then_custom_error() -> CustomResult<()> { fn test_query_and_then_custom_error() -> CustomResult<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1767,7 +1786,7 @@ mod test {
#[test] #[test]
fn test_query_and_then_custom_error_fails() -> Result<()> { fn test_query_and_then_custom_error_fails() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1809,7 +1828,7 @@ mod test {
#[test] #[test]
fn test_query_row_and_then_custom_error() -> CustomResult<()> { fn test_query_row_and_then_custom_error() -> CustomResult<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1826,7 +1845,7 @@ mod test {
#[test] #[test]
fn test_query_row_and_then_custom_error_fails() -> Result<()> { fn test_query_row_and_then_custom_error_fails() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1863,7 +1882,7 @@ mod test {
#[test] #[test]
fn test_dynamic() -> Result<()> { fn test_dynamic() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
@ -1877,7 +1896,7 @@ mod test {
} }
#[test] #[test]
fn test_dyn_box() -> Result<()> { fn test_dyn_box() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER);")?; db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let b: Box<dyn ToSql> = Box::new(5); let b: Box<dyn ToSql> = Box::new(5);
db.execute("INSERT INTO foo VALUES(?)", [b])?; db.execute("INSERT INTO foo VALUES(?)", [b])?;
@ -1889,7 +1908,7 @@ mod test {
#[test] #[test]
fn test_params() -> Result<()> { fn test_params() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.query_row( db.query_row(
"SELECT "SELECT
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
@ -1910,7 +1929,7 @@ mod test {
#[test] #[test]
#[cfg(not(feature = "extra_check"))] #[cfg(not(feature = "extra_check"))]
fn test_alter_table() -> Result<()> { fn test_alter_table() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE x(t);")?; db.execute_batch("CREATE TABLE x(t);")?;
// `execute_batch` should be used but `execute` should also work // `execute_batch` should be used but `execute` should also work
db.execute("ALTER TABLE x RENAME TO y;", [])?; db.execute("ALTER TABLE x RENAME TO y;", [])?;
@ -1919,7 +1938,7 @@ mod test {
#[test] #[test]
fn test_batch() -> Result<()> { fn test_batch() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
let sql = r" let sql = r"
CREATE TABLE tbl1 (col); CREATE TABLE tbl1 (col);
CREATE TABLE tbl2 (col); CREATE TABLE tbl2 (col);
@ -1935,7 +1954,7 @@ mod test {
#[test] #[test]
#[cfg(all(feature = "bundled", not(feature = "bundled-sqlcipher")))] // SQLite >= 3.35.0 #[cfg(all(feature = "bundled", not(feature = "bundled-sqlcipher")))] // SQLite >= 3.35.0
fn test_returning() -> Result<()> { fn test_returning() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?; db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
let row_id = let row_id =
db.query_row::<i64, _, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [], |r| { db.query_row::<i64, _, _>("INSERT INTO foo DEFAULT VALUES RETURNING ROWID", [], |r| {
@ -1944,4 +1963,11 @@ mod test {
assert_eq!(row_id, 1); assert_eq!(row_id, 1);
Ok(()) Ok(())
} }
#[test]
#[cfg(feature = "modern_sqlite")]
fn test_cache_flush() -> Result<()> {
let db = Connection::open_in_memory()?;
db.cache_flush()
}
} }

View File

@ -1,4 +1,4 @@
//! `feature = "limits"` Run-Time Limits //! Run-Time Limits
use std::os::raw::c_int; use std::os::raw::c_int;
@ -8,14 +8,14 @@ pub use crate::ffi::Limit;
use crate::Connection; use crate::Connection;
impl Connection { impl Connection {
/// `feature = "limits"` Returns the current value of a limit. /// Returns the current value of a limit.
#[inline] #[inline]
pub fn limit(&self, limit: Limit) -> i32 { pub fn limit(&self, limit: Limit) -> i32 {
let c = self.db.borrow(); let c = self.db.borrow();
unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, -1) } unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, -1) }
} }
/// `feature = "limits"` Changes the limit to `new_val`, returning the prior /// Changes the limit to `new_val`, returning the prior
/// value of the limit. /// value of the limit.
#[inline] #[inline]
pub fn set_limit(&self, limit: Limit, new_val: i32) -> i32 { pub fn set_limit(&self, limit: Limit, new_val: i32) -> i32 {

View File

@ -1,6 +1,6 @@
use crate::{Connection, Result}; use crate::{Connection, Result};
/// `feature = "load_extension"` RAII guard temporarily enabling SQLite /// RAII guard temporarily enabling SQLite
/// extensions to be loaded. /// extensions to be loaded.
/// ///
/// ## Example /// ## Example
@ -14,6 +14,7 @@ use crate::{Connection, Result};
/// conn.load_extension(Path::new("my_sqlite_extension"), None) /// conn.load_extension(Path::new("my_sqlite_extension"), None)
/// } /// }
/// ``` /// ```
#[cfg_attr(docsrs, doc(cfg(feature = "load_extension")))]
pub struct LoadExtensionGuard<'conn> { pub struct LoadExtensionGuard<'conn> {
conn: &'conn Connection, conn: &'conn Connection,
} }

View File

@ -169,8 +169,8 @@ pub trait Params: Sealed {
// Explicitly impl for empty array. Critically, for `conn.execute([])` to be // Explicitly impl for empty array. Critically, for `conn.execute([])` to be
// unambiguous, this must be the *only* implementation for an empty array. This // unambiguous, this must be the *only* implementation for an empty array. This
// avoids `NO_PARAMS` being a necessary part of the API. // avoids `NO_PARAMS` being a necessary part of the API.
impl Sealed for [&dyn ToSql; 0] {} impl Sealed for [&(dyn ToSql + Send + Sync); 0] {}
impl Params for [&dyn ToSql; 0] { impl Params for [&(dyn ToSql + Send + Sync); 0] {
#[inline] #[inline]
fn __bind_in(self, stmt: &mut Statement<'_>) -> Result<()> { fn __bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
// Note: Can't just return `Ok(())` — `Statement::bind_parameters` // Note: Can't just return `Ok(())` — `Statement::bind_parameters`

View File

@ -198,7 +198,7 @@ impl Connection {
let mut rows = stmt.query([])?; let mut rows = stmt.query([])?;
while let Some(result_row) = rows.next()? { while let Some(result_row) = rows.next()? {
let row = result_row; let row = result_row;
f(&row)?; f(row)?;
} }
Ok(()) Ok(())
} }
@ -234,7 +234,7 @@ impl Connection {
let mut rows = stmt.query([])?; let mut rows = stmt.query([])?;
while let Some(result_row) = rows.next()? { while let Some(result_row) = rows.next()? {
let row = result_row; let row = result_row;
f(&row)?; f(row)?;
} }
Ok(()) Ok(())
} }

View File

@ -156,7 +156,7 @@ where
self.rows self.rows
.next() .next()
.transpose() .transpose()
.map(|row_result| row_result.and_then(|row| (map)(&row))) .map(|row_result| row_result.and_then(|row| (map)(row)))
} }
} }
@ -181,7 +181,7 @@ where
self.rows self.rows
.next() .next()
.transpose() .transpose()
.map(|row_result| row_result.map_err(E::from).and_then(|row| (map)(&row))) .map(|row_result| row_result.map_err(E::from).and_then(|row| (map)(row)))
} }
} }
@ -210,7 +210,7 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
#[inline] #[inline]
fn advance(&mut self) -> Result<()> { fn advance(&mut self) -> Result<()> {
match self.stmt { match self.stmt {
Some(ref stmt) => match stmt.step() { Some(stmt) => match stmt.step() {
Ok(true) => { Ok(true) => {
self.row = Some(Row { stmt }); self.row = Some(Row { stmt });
Ok(()) Ok(())

View File

@ -1,4 +1,4 @@
//! `feature = "session"` [Session Extension](https://sqlite.org/sessionintro.html) //! [Session Extension](https://sqlite.org/sessionintro.html)
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use std::ffi::CStr; use std::ffi::CStr;
@ -11,7 +11,7 @@ use std::slice::{from_raw_parts, from_raw_parts_mut};
use fallible_streaming_iterator::FallibleStreamingIterator; use fallible_streaming_iterator::FallibleStreamingIterator;
use crate::error::error_from_sqlite_code; use crate::error::{check, error_from_sqlite_code};
use crate::ffi; use crate::ffi;
use crate::hooks::Action; use crate::hooks::Action;
use crate::types::ValueRef; use crate::types::ValueRef;
@ -19,7 +19,7 @@ use crate::{errmsg_to_string, str_to_cstring, Connection, DatabaseName, Result};
// https://sqlite.org/session.html // https://sqlite.org/session.html
/// `feature = "session"` An instance of this object is a session that can be /// An instance of this object is a session that can be
/// used to record changes to a database. /// used to record changes to a database.
pub struct Session<'conn> { pub struct Session<'conn> {
phantom: PhantomData<&'conn Connection>, phantom: PhantomData<&'conn Connection>,
@ -45,7 +45,7 @@ impl Session<'_> {
let db = db.db.borrow_mut().db; let db = db.db.borrow_mut().db;
let mut s: *mut ffi::sqlite3_session = ptr::null_mut(); let mut s: *mut ffi::sqlite3_session = ptr::null_mut();
check!(unsafe { ffi::sqlite3session_create(db, name.as_ptr(), &mut s) }); check(unsafe { ffi::sqlite3session_create(db, name.as_ptr(), &mut s) })?;
Ok(Session { Ok(Session {
phantom: PhantomData, phantom: PhantomData,
@ -109,15 +109,14 @@ impl Session<'_> {
None None
}; };
let table = table.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); let table = table.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null());
unsafe { check!(ffi::sqlite3session_attach(self.s, table)) }; check(unsafe { ffi::sqlite3session_attach(self.s, table) })
Ok(())
} }
/// Generate a Changeset /// Generate a Changeset
pub fn changeset(&mut self) -> Result<Changeset> { pub fn changeset(&mut self) -> Result<Changeset> {
let mut n = 0; let mut n = 0;
let mut cs: *mut c_void = ptr::null_mut(); let mut cs: *mut c_void = ptr::null_mut();
check!(unsafe { ffi::sqlite3session_changeset(self.s, &mut n, &mut cs) }); check(unsafe { ffi::sqlite3session_changeset(self.s, &mut n, &mut cs) })?;
Ok(Changeset { cs, n }) Ok(Changeset { cs, n })
} }
@ -125,14 +124,13 @@ impl Session<'_> {
#[inline] #[inline]
pub fn changeset_strm(&mut self, output: &mut dyn Write) -> Result<()> { pub fn changeset_strm(&mut self, output: &mut dyn Write) -> Result<()> {
let output_ref = &output; let output_ref = &output;
check!(unsafe { check(unsafe {
ffi::sqlite3session_changeset_strm( ffi::sqlite3session_changeset_strm(
self.s, self.s,
Some(x_output), Some(x_output),
output_ref as *const &mut dyn Write as *mut c_void, output_ref as *const &mut dyn Write as *mut c_void,
) )
}); })
Ok(())
} }
/// Generate a Patchset /// Generate a Patchset
@ -140,7 +138,7 @@ impl Session<'_> {
pub fn patchset(&mut self) -> Result<Changeset> { pub fn patchset(&mut self) -> Result<Changeset> {
let mut n = 0; let mut n = 0;
let mut ps: *mut c_void = ptr::null_mut(); let mut ps: *mut c_void = ptr::null_mut();
check!(unsafe { ffi::sqlite3session_patchset(self.s, &mut n, &mut ps) }); check(unsafe { ffi::sqlite3session_patchset(self.s, &mut n, &mut ps) })?;
// TODO Validate: same struct // TODO Validate: same struct
Ok(Changeset { cs: ps, n }) Ok(Changeset { cs: ps, n })
} }
@ -149,14 +147,13 @@ impl Session<'_> {
#[inline] #[inline]
pub fn patchset_strm(&mut self, output: &mut dyn Write) -> Result<()> { pub fn patchset_strm(&mut self, output: &mut dyn Write) -> Result<()> {
let output_ref = &output; let output_ref = &output;
check!(unsafe { check(unsafe {
ffi::sqlite3session_patchset_strm( ffi::sqlite3session_patchset_strm(
self.s, self.s,
Some(x_output), Some(x_output),
output_ref as *const &mut dyn Write as *mut c_void, output_ref as *const &mut dyn Write as *mut c_void,
) )
}); })
Ok(())
} }
/// Load the difference between tables. /// Load the difference between tables.
@ -223,23 +220,22 @@ impl Drop for Session<'_> {
} }
} }
/// `feature = "session"` Invert a changeset /// Invert a changeset
#[inline] #[inline]
pub fn invert_strm(input: &mut dyn Read, output: &mut dyn Write) -> Result<()> { pub fn invert_strm(input: &mut dyn Read, output: &mut dyn Write) -> Result<()> {
let input_ref = &input; let input_ref = &input;
let output_ref = &output; let output_ref = &output;
check!(unsafe { check(unsafe {
ffi::sqlite3changeset_invert_strm( ffi::sqlite3changeset_invert_strm(
Some(x_input), Some(x_input),
input_ref as *const &mut dyn Read as *mut c_void, input_ref as *const &mut dyn Read as *mut c_void,
Some(x_output), Some(x_output),
output_ref as *const &mut dyn Write as *mut c_void, output_ref as *const &mut dyn Write as *mut c_void,
) )
}); })
Ok(())
} }
/// `feature = "session"` Combine two changesets /// Combine two changesets
#[inline] #[inline]
pub fn concat_strm( pub fn concat_strm(
input_a: &mut dyn Read, input_a: &mut dyn Read,
@ -249,7 +245,7 @@ pub fn concat_strm(
let input_a_ref = &input_a; let input_a_ref = &input_a;
let input_b_ref = &input_b; let input_b_ref = &input_b;
let output_ref = &output; let output_ref = &output;
check!(unsafe { check(unsafe {
ffi::sqlite3changeset_concat_strm( ffi::sqlite3changeset_concat_strm(
Some(x_input), Some(x_input),
input_a_ref as *const &mut dyn Read as *mut c_void, input_a_ref as *const &mut dyn Read as *mut c_void,
@ -258,11 +254,10 @@ pub fn concat_strm(
Some(x_output), Some(x_output),
output_ref as *const &mut dyn Write as *mut c_void, output_ref as *const &mut dyn Write as *mut c_void,
) )
}); })
Ok(())
} }
/// `feature = "session"` Changeset or Patchset /// Changeset or Patchset
pub struct Changeset { pub struct Changeset {
cs: *mut c_void, cs: *mut c_void,
n: c_int, n: c_int,
@ -274,9 +269,9 @@ impl Changeset {
pub fn invert(&self) -> Result<Changeset> { pub fn invert(&self) -> Result<Changeset> {
let mut n = 0; let mut n = 0;
let mut cs = ptr::null_mut(); let mut cs = ptr::null_mut();
check!(unsafe { check(unsafe {
ffi::sqlite3changeset_invert(self.n, self.cs, &mut n, &mut cs as *mut *mut _) ffi::sqlite3changeset_invert(self.n, self.cs, &mut n, &mut cs as *mut *mut _)
}); })?;
Ok(Changeset { cs, n }) Ok(Changeset { cs, n })
} }
@ -284,7 +279,7 @@ impl Changeset {
#[inline] #[inline]
pub fn iter(&self) -> Result<ChangesetIter<'_>> { pub fn iter(&self) -> Result<ChangesetIter<'_>> {
let mut it = ptr::null_mut(); let mut it = ptr::null_mut();
check!(unsafe { ffi::sqlite3changeset_start(&mut it as *mut *mut _, self.n, self.cs) }); check(unsafe { ffi::sqlite3changeset_start(&mut it as *mut *mut _, self.n, self.cs) })?;
Ok(ChangesetIter { Ok(ChangesetIter {
phantom: PhantomData, phantom: PhantomData,
it, it,
@ -297,9 +292,9 @@ impl Changeset {
pub fn concat(a: &Changeset, b: &Changeset) -> Result<Changeset> { pub fn concat(a: &Changeset, b: &Changeset) -> Result<Changeset> {
let mut n = 0; let mut n = 0;
let mut cs = ptr::null_mut(); let mut cs = ptr::null_mut();
check!(unsafe { check(unsafe {
ffi::sqlite3changeset_concat(a.n, a.cs, b.n, b.cs, &mut n, &mut cs as *mut *mut _) ffi::sqlite3changeset_concat(a.n, a.cs, b.n, b.cs, &mut n, &mut cs as *mut *mut _)
}); })?;
Ok(Changeset { cs, n }) Ok(Changeset { cs, n })
} }
} }
@ -313,7 +308,7 @@ impl Drop for Changeset {
} }
} }
/// `feature = "session"` Cursor for iterating over the elements of a changeset /// Cursor for iterating over the elements of a changeset
/// or patchset. /// or patchset.
pub struct ChangesetIter<'changeset> { pub struct ChangesetIter<'changeset> {
phantom: PhantomData<&'changeset Changeset>, phantom: PhantomData<&'changeset Changeset>,
@ -326,13 +321,13 @@ impl ChangesetIter<'_> {
#[inline] #[inline]
pub fn start_strm<'input>(input: &&'input mut dyn Read) -> Result<ChangesetIter<'input>> { pub fn start_strm<'input>(input: &&'input mut dyn Read) -> Result<ChangesetIter<'input>> {
let mut it = ptr::null_mut(); let mut it = ptr::null_mut();
check!(unsafe { check(unsafe {
ffi::sqlite3changeset_start_strm( ffi::sqlite3changeset_start_strm(
&mut it as *mut *mut _, &mut it as *mut *mut _,
Some(x_input), Some(x_input),
input as *const &mut dyn Read as *mut c_void, input as *const &mut dyn Read as *mut c_void,
) )
}); })?;
Ok(ChangesetIter { Ok(ChangesetIter {
phantom: PhantomData, phantom: PhantomData,
it, it,
@ -367,7 +362,7 @@ impl FallibleStreamingIterator for ChangesetIter<'_> {
} }
} }
/// `feature = "session"` /// Operation
pub struct Operation<'item> { pub struct Operation<'item> {
table_name: &'item str, table_name: &'item str,
number_of_columns: i32, number_of_columns: i32,
@ -410,7 +405,7 @@ impl Drop for ChangesetIter<'_> {
} }
} }
/// `feature = "session"` An item passed to a conflict-handler by /// An item passed to a conflict-handler by
/// [`Connection::apply`](crate::Connection::apply), or an item generated by /// [`Connection::apply`](crate::Connection::apply), or an item generated by
/// [`ChangesetIter::next`](ChangesetIter::next). /// [`ChangesetIter::next`](ChangesetIter::next).
// TODO enum ? Delete, Insert, Update, ... // TODO enum ? Delete, Insert, Update, ...
@ -427,11 +422,11 @@ impl ChangesetItem {
pub fn conflict(&self, col: usize) -> Result<ValueRef<'_>> { pub fn conflict(&self, col: usize) -> Result<ValueRef<'_>> {
unsafe { unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut(); let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
check!(ffi::sqlite3changeset_conflict( check(ffi::sqlite3changeset_conflict(
self.it, self.it,
col as i32, col as i32,
&mut p_value, &mut p_value,
)); ))?;
Ok(ValueRef::from_value(p_value)) Ok(ValueRef::from_value(p_value))
} }
} }
@ -444,7 +439,7 @@ impl ChangesetItem {
pub fn fk_conflicts(&self) -> Result<i32> { pub fn fk_conflicts(&self) -> Result<i32> {
unsafe { unsafe {
let mut p_out = 0; let mut p_out = 0;
check!(ffi::sqlite3changeset_fk_conflicts(self.it, &mut p_out)); check(ffi::sqlite3changeset_fk_conflicts(self.it, &mut p_out))?;
Ok(p_out) Ok(p_out)
} }
} }
@ -457,7 +452,7 @@ impl ChangesetItem {
pub fn new_value(&self, col: usize) -> Result<ValueRef<'_>> { pub fn new_value(&self, col: usize) -> Result<ValueRef<'_>> {
unsafe { unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut(); let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
check!(ffi::sqlite3changeset_new(self.it, col as i32, &mut p_value,)); check(ffi::sqlite3changeset_new(self.it, col as i32, &mut p_value))?;
Ok(ValueRef::from_value(p_value)) Ok(ValueRef::from_value(p_value))
} }
} }
@ -470,7 +465,7 @@ impl ChangesetItem {
pub fn old_value(&self, col: usize) -> Result<ValueRef<'_>> { pub fn old_value(&self, col: usize) -> Result<ValueRef<'_>> {
unsafe { unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut(); let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
check!(ffi::sqlite3changeset_old(self.it, col as i32, &mut p_value,)); check(ffi::sqlite3changeset_old(self.it, col as i32, &mut p_value))?;
Ok(ValueRef::from_value(p_value)) Ok(ValueRef::from_value(p_value))
} }
} }
@ -483,13 +478,13 @@ impl ChangesetItem {
let mut indirect = 0; let mut indirect = 0;
let tab = unsafe { let tab = unsafe {
let mut pz_tab: *const c_char = ptr::null(); let mut pz_tab: *const c_char = ptr::null();
check!(ffi::sqlite3changeset_op( check(ffi::sqlite3changeset_op(
self.it, self.it,
&mut pz_tab, &mut pz_tab,
&mut number_of_columns, &mut number_of_columns,
&mut code, &mut code,
&mut indirect &mut indirect,
)); ))?;
CStr::from_ptr(pz_tab) CStr::from_ptr(pz_tab)
}; };
let table_name = tab.to_str()?; let table_name = tab.to_str()?;
@ -507,17 +502,17 @@ impl ChangesetItem {
let mut number_of_columns = 0; let mut number_of_columns = 0;
unsafe { unsafe {
let mut pks: *mut c_uchar = ptr::null_mut(); let mut pks: *mut c_uchar = ptr::null_mut();
check!(ffi::sqlite3changeset_pk( check(ffi::sqlite3changeset_pk(
self.it, self.it,
&mut pks, &mut pks,
&mut number_of_columns &mut number_of_columns,
)); ))?;
Ok(from_raw_parts(pks, number_of_columns as usize)) Ok(from_raw_parts(pks, number_of_columns as usize))
} }
} }
} }
/// `feature = "session"` Used to combine two or more changesets or /// Used to combine two or more changesets or
/// patchsets /// patchsets
pub struct Changegroup { pub struct Changegroup {
cg: *mut ffi::sqlite3_changegroup, cg: *mut ffi::sqlite3_changegroup,
@ -528,29 +523,27 @@ impl Changegroup {
#[inline] #[inline]
pub fn new() -> Result<Self> { pub fn new() -> Result<Self> {
let mut cg = ptr::null_mut(); let mut cg = ptr::null_mut();
check!(unsafe { ffi::sqlite3changegroup_new(&mut cg) }); check(unsafe { ffi::sqlite3changegroup_new(&mut cg) })?;
Ok(Changegroup { cg }) Ok(Changegroup { cg })
} }
/// Add a changeset /// Add a changeset
#[inline] #[inline]
pub fn add(&mut self, cs: &Changeset) -> Result<()> { pub fn add(&mut self, cs: &Changeset) -> Result<()> {
check!(unsafe { ffi::sqlite3changegroup_add(self.cg, cs.n, cs.cs) }); check(unsafe { ffi::sqlite3changegroup_add(self.cg, cs.n, cs.cs) })
Ok(())
} }
/// Add a changeset read from `input` to this change group. /// Add a changeset read from `input` to this change group.
#[inline] #[inline]
pub fn add_stream(&mut self, input: &mut dyn Read) -> Result<()> { pub fn add_stream(&mut self, input: &mut dyn Read) -> Result<()> {
let input_ref = &input; let input_ref = &input;
check!(unsafe { check(unsafe {
ffi::sqlite3changegroup_add_strm( ffi::sqlite3changegroup_add_strm(
self.cg, self.cg,
Some(x_input), Some(x_input),
input_ref as *const &mut dyn Read as *mut c_void, input_ref as *const &mut dyn Read as *mut c_void,
) )
}); })
Ok(())
} }
/// Obtain a composite Changeset /// Obtain a composite Changeset
@ -558,7 +551,7 @@ impl Changegroup {
pub fn output(&mut self) -> Result<Changeset> { pub fn output(&mut self) -> Result<Changeset> {
let mut n = 0; let mut n = 0;
let mut output: *mut c_void = ptr::null_mut(); let mut output: *mut c_void = ptr::null_mut();
check!(unsafe { ffi::sqlite3changegroup_output(self.cg, &mut n, &mut output) }); check(unsafe { ffi::sqlite3changegroup_output(self.cg, &mut n, &mut output) })?;
Ok(Changeset { cs: output, n }) Ok(Changeset { cs: output, n })
} }
@ -566,14 +559,13 @@ impl Changegroup {
#[inline] #[inline]
pub fn output_strm(&mut self, output: &mut dyn Write) -> Result<()> { pub fn output_strm(&mut self, output: &mut dyn Write) -> Result<()> {
let output_ref = &output; let output_ref = &output;
check!(unsafe { check(unsafe {
ffi::sqlite3changegroup_output_strm( ffi::sqlite3changegroup_output_strm(
self.cg, self.cg,
Some(x_output), Some(x_output),
output_ref as *const &mut dyn Write as *mut c_void, output_ref as *const &mut dyn Write as *mut c_void,
) )
}); })
Ok(())
} }
} }
@ -587,7 +579,7 @@ impl Drop for Changegroup {
} }
impl Connection { impl Connection {
/// `feature = "session"` Apply a changeset to a database /// Apply a changeset to a database
pub fn apply<F, C>(&self, cs: &Changeset, filter: Option<F>, conflict: C) -> Result<()> pub fn apply<F, C>(&self, cs: &Changeset, filter: Option<F>, conflict: C) -> Result<()>
where where
F: Fn(&str) -> bool + Send + RefUnwindSafe + 'static, F: Fn(&str) -> bool + Send + RefUnwindSafe + 'static,
@ -597,7 +589,7 @@ impl Connection {
let filtered = filter.is_some(); let filtered = filter.is_some();
let tuple = &mut (filter, conflict); let tuple = &mut (filter, conflict);
check!(unsafe { check(unsafe {
if filtered { if filtered {
ffi::sqlite3changeset_apply( ffi::sqlite3changeset_apply(
db, db,
@ -617,11 +609,10 @@ impl Connection {
tuple as *mut (Option<F>, C) as *mut c_void, tuple as *mut (Option<F>, C) as *mut c_void,
) )
} }
}); })
Ok(())
} }
/// `feature = "session"` Apply a changeset to a database /// Apply a changeset to a database
pub fn apply_strm<F, C>( pub fn apply_strm<F, C>(
&self, &self,
input: &mut dyn Read, input: &mut dyn Read,
@ -637,7 +628,7 @@ impl Connection {
let filtered = filter.is_some(); let filtered = filter.is_some();
let tuple = &mut (filter, conflict); let tuple = &mut (filter, conflict);
check!(unsafe { check(unsafe {
if filtered { if filtered {
ffi::sqlite3changeset_apply_strm( ffi::sqlite3changeset_apply_strm(
db, db,
@ -657,12 +648,11 @@ impl Connection {
tuple as *mut (Option<F>, C) as *mut c_void, tuple as *mut (Option<F>, C) as *mut c_void,
) )
} }
}); })
Ok(())
} }
} }
/// `feature = "session"` Constants passed to the conflict handler /// Constants passed to the conflict handler
/// See [here](https://sqlite.org/session.html#SQLITE_CHANGESET_CONFLICT) for details. /// See [here](https://sqlite.org/session.html#SQLITE_CHANGESET_CONFLICT) for details.
#[allow(missing_docs)] #[allow(missing_docs)]
#[repr(i32)] #[repr(i32)]
@ -690,7 +680,7 @@ impl From<i32> for ConflictType {
} }
} }
/// `feature = "session"` Constants returned by the conflict handler /// Constants returned by the conflict handler
/// See [here](https://sqlite.org/session.html#SQLITE_CHANGESET_ABORT) for details. /// See [here](https://sqlite.org/session.html#SQLITE_CHANGESET_ABORT) for details.
#[allow(missing_docs)] #[allow(missing_docs)]
#[repr(i32)] #[repr(i32)]
@ -826,7 +816,7 @@ mod test {
assert_eq!("foo", op.table_name()); assert_eq!("foo", op.table_name());
assert_eq!(1, op.number_of_columns()); assert_eq!(1, op.number_of_columns());
assert_eq!(Action::SQLITE_INSERT, op.code()); assert_eq!(Action::SQLITE_INSERT, op.code());
assert_eq!(false, op.indirect()); assert!(!op.indirect());
let pk = item.pk()?; let pk = item.pk()?;
assert_eq!(&[1], pk); assert_eq!(&[1], pk);

View File

@ -453,7 +453,7 @@ impl Statement<'_> {
{ {
let mut rows = self.query(params)?; let mut rows = self.query(params)?;
rows.get_expected_row().and_then(|r| f(&r)) rows.get_expected_row().and_then(|r| f(r))
} }
/// Convenience method to execute a query with named parameter(s) that is /// Convenience method to execute a query with named parameter(s) that is
@ -776,6 +776,7 @@ impl Statement<'_> {
/// Returns a string containing the SQL text of prepared statement with /// Returns a string containing the SQL text of prepared statement with
/// bound parameters expanded. /// bound parameters expanded.
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn expanded_sql(&self) -> Option<String> { pub fn expanded_sql(&self) -> Option<String> {
self.stmt self.stmt
.expanded_sql() .expanded_sql()

View File

@ -1,4 +1,4 @@
//! `feature = "trace"` Tracing and profiling functions. Error and warning log. //! Tracing and profiling functions. Error and warning log.
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::mem; use std::mem;
@ -11,7 +11,7 @@ use super::ffi;
use crate::error::error_from_sqlite_code; use crate::error::error_from_sqlite_code;
use crate::{Connection, Result}; use crate::{Connection, Result};
/// `feature = "trace"` Set up the process-wide SQLite error logging callback. /// Set up the process-wide SQLite error logging callback.
/// ///
/// # Safety /// # Safety
/// ///
@ -53,7 +53,7 @@ pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> Result<()> {
} }
} }
/// `feature = "trace"` Write a message into the error log established by /// Write a message into the error log established by
/// `config_log`. /// `config_log`.
#[inline] #[inline]
pub fn log(err_code: c_int, msg: &str) { pub fn log(err_code: c_int, msg: &str) {
@ -64,7 +64,7 @@ pub fn log(err_code: c_int, msg: &str) {
} }
impl Connection { impl Connection {
/// `feature = "trace"` Register or clear a callback function that can be /// Register or clear a callback function that can be
/// used for tracing the execution of SQL statements. /// used for tracing the execution of SQL statements.
/// ///
/// Prepared statement placeholders are replaced/logged with their assigned /// Prepared statement placeholders are replaced/logged with their assigned
@ -89,7 +89,7 @@ impl Connection {
} }
} }
/// `feature = "trace"` Register or clear a callback function that can be /// Register or clear a callback function that can be
/// used for profiling the execution of SQL statements. /// used for profiling the execution of SQL statements.
/// ///
/// There can only be a single profiler defined for each database /// There can only be a single profiler defined for each database

View File

@ -15,15 +15,17 @@ pub enum FromSqlError {
/// requested type. /// requested type.
OutOfRange(i64), OutOfRange(i64),
/// `feature = "i128_blob"` Error returned when reading an `i128` from a /// Error returned when reading an `i128` from a
/// blob with a size other than 16. Only available when the `i128_blob` /// blob with a size other than 16. Only available when the `i128_blob`
/// feature is enabled. /// feature is enabled.
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
InvalidI128Size(usize), InvalidI128Size(usize),
/// `feature = "uuid"` Error returned when reading a `uuid` from a blob with /// Error returned when reading a `uuid` from a blob with
/// a size other than 16. Only available when the `uuid` feature is enabled. /// a size other than 16. Only available when the `uuid` feature is enabled.
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
InvalidUuidSize(usize), InvalidUuidSize(usize),
/// An error case available for implementors of the [`FromSql`] trait. /// An error case available for implementors of the [`FromSql`] trait.
@ -176,6 +178,7 @@ impl FromSql for Vec<u8> {
} }
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
impl FromSql for i128 { impl FromSql for i128 {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
@ -192,6 +195,7 @@ impl FromSql for i128 {
} }
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
impl FromSql for uuid::Uuid { impl FromSql for uuid::Uuid {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {

View File

@ -77,14 +77,18 @@ pub use self::value_ref::ValueRef;
use std::fmt; use std::fmt;
#[cfg(feature = "chrono")] #[cfg(feature = "chrono")]
#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
mod chrono; mod chrono;
mod from_sql; mod from_sql;
#[cfg(feature = "serde_json")] #[cfg(feature = "serde_json")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))]
mod serde_json; mod serde_json;
#[cfg(feature = "time")] #[cfg(feature = "time")]
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
mod time; mod time;
mod to_sql; mod to_sql;
#[cfg(feature = "url")] #[cfg(feature = "url")]
#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
mod url; mod url;
mod value; mod value;
mod value_ref; mod value_ref;

View File

@ -17,12 +17,8 @@ impl ToSql for Value {
impl FromSql for Value { impl FromSql for Value {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value { let bytes = value.as_bytes()?;
ValueRef::Text(s) => serde_json::from_slice(s), serde_json::from_slice(bytes).map_err(|err| FromSqlError::Other(Box::new(err)))
ValueRef::Blob(b) => serde_json::from_slice(b),
_ => return Err(FromSqlError::InvalidType),
}
.map_err(|err| FromSqlError::Other(Box::new(err)))
} }
} }

View File

@ -16,13 +16,15 @@ pub enum ToSqlOutput<'a> {
/// An owned SQLite-representable value. /// An owned SQLite-representable value.
Owned(Value), Owned(Value),
/// `feature = "blob"` A BLOB of the given length that is filled with /// A BLOB of the given length that is filled with
/// zeroes. /// zeroes.
#[cfg(feature = "blob")] #[cfg(feature = "blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
ZeroBlob(i32), ZeroBlob(i32),
/// `feature = "array"` /// `feature = "array"`
#[cfg(feature = "array")] #[cfg(feature = "array")]
#[cfg_attr(docsrs, doc(cfg(feature = "array")))]
Array(Array), Array(Array),
} }
@ -70,9 +72,11 @@ from_value!(Vec<u8>);
// `i128` needs in `Into<Value>`, but it's probably fine for the moment, and not // `i128` needs in `Into<Value>`, but it's probably fine for the moment, and not
// worth adding another case to Value. // worth adding another case to Value.
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
from_value!(i128); from_value!(i128);
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
from_value!(uuid::Uuid); from_value!(uuid::Uuid);
impl ToSql for ToSqlOutput<'_> { impl ToSql for ToSqlOutput<'_> {
@ -162,9 +166,11 @@ to_sql_self!(f32);
to_sql_self!(f64); to_sql_self!(f64);
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
to_sql_self!(i128); to_sql_self!(i128);
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
to_sql_self!(uuid::Uuid); to_sql_self!(uuid::Uuid);
macro_rules! to_sql_self_fallible( macro_rules! to_sql_self_fallible(

View File

@ -41,6 +41,7 @@ impl From<isize> for Value {
} }
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
impl From<i128> for Value { impl From<i128> for Value {
#[inline] #[inline]
fn from(i: i128) -> Value { fn from(i: i128) -> Value {
@ -54,6 +55,7 @@ impl From<i128> for Value {
} }
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
impl From<uuid::Uuid> for Value { impl From<uuid::Uuid> for Value {
#[inline] #[inline]
fn from(id: uuid::Uuid) -> Value { fn from(id: uuid::Uuid) -> Value {

View File

@ -77,6 +77,16 @@ impl<'a> ValueRef<'a> {
_ => Err(FromSqlError::InvalidType), _ => Err(FromSqlError::InvalidType),
} }
} }
/// Returns the byte slice that makes up this ValueRef if it's either
/// [`ValueRef::Blob`] or [`ValueRef::Text`].
#[inline]
pub fn as_bytes(&self) -> FromSqlResult<&'a [u8]> {
match self {
ValueRef::Text(s) | ValueRef::Blob(s) => Ok(s),
_ => Err(FromSqlError::InvalidType),
}
}
} }
impl From<ValueRef<'_>> for Value { impl From<ValueRef<'_>> for Value {

View File

@ -1,4 +1,4 @@
//! `feature = "array"` Array Virtual Table. //! Array Virtual Table.
//! //!
//! Note: `rarray`, not `carray` is the name of the table valued function we //! Note: `rarray`, not `carray` is the name of the table valued function we
//! define. //! define.
@ -57,7 +57,7 @@ impl ToSql for Array {
} }
} }
/// `feature = "array"` Register the "rarray" module. /// Register the "rarray" module.
pub fn load_module(conn: &Connection) -> Result<()> { pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None; let aux: Option<()> = None;
conn.create_module("rarray", eponymous_only_module::<ArrayTab>(), aux) conn.create_module("rarray", eponymous_only_module::<ArrayTab>(), aux)

View File

@ -1,4 +1,4 @@
//! `feature = "csvtab"` CSV Virtual Table. //! CSV Virtual Table.
//! //!
//! Port of [csv](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/csv.c) C //! Port of [csv](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/csv.c) C
//! extension: `https://www.sqlite.org/csv.html` //! extension: `https://www.sqlite.org/csv.html`
@ -35,7 +35,7 @@ use crate::vtab::{
}; };
use crate::{Connection, Error, Result}; use crate::{Connection, Error, Result};
/// `feature = "csvtab"` Register the "csv" module. /// Register the "csv" module.
/// ```sql /// ```sql
/// CREATE VIRTUAL TABLE vtab USING csv( /// CREATE VIRTUAL TABLE vtab USING csv(
/// filename=FILENAME -- Name of file containing CSV content /// filename=FILENAME -- Name of file containing CSV content
@ -212,7 +212,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
if n_col.is_none() && schema.is_none() { if n_col.is_none() && schema.is_none() {
cols = headers cols = headers
.into_iter() .into_iter()
.map(|header| escape_double_quote(&header).into_owned()) .map(|header| escape_double_quote(header).into_owned())
.collect(); .collect();
} }
} }

View File

@ -1,4 +1,4 @@
//! `feature = "vtab"` Create virtual tables. //! Create virtual tables.
//! //!
//! Follow these steps to create your own virtual table: //! Follow these steps to create your own virtual table:
//! 1. Write implementation of [`VTab`] and [`VTabCursor`] traits. //! 1. Write implementation of [`VTab`] and [`VTabCursor`] traits.
@ -57,7 +57,7 @@ use crate::{str_to_cstring, Connection, Error, InnerConnection, Result};
// ffi::sqlite3_vtab => VTab // ffi::sqlite3_vtab => VTab
// ffi::sqlite3_vtab_cursor => VTabCursor // ffi::sqlite3_vtab_cursor => VTabCursor
/// `feature = "vtab"` Virtual table module /// Virtual table module
/// ///
/// (See [SQLite doc](https://sqlite.org/c3ref/module.html)) /// (See [SQLite doc](https://sqlite.org/c3ref/module.html))
#[repr(transparent)] #[repr(transparent)]
@ -84,7 +84,7 @@ const ZERO_MODULE: ffi::sqlite3_module = unsafe {
.module .module
}; };
/// `feature = "vtab"` Create a read-only virtual table implementation. /// Create a read-only virtual table implementation.
/// ///
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> { pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> {
@ -122,7 +122,7 @@ pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab,
} }
} }
/// `feature = "vtab"` Create an eponymous only virtual table implementation. /// Create an eponymous only virtual table implementation.
/// ///
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> { pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> {
@ -187,7 +187,7 @@ impl VTabConnection {
} }
} }
/// `feature = "vtab"` Virtual table instance trait. /// Virtual table instance trait.
/// ///
/// # Safety /// # Safety
/// ///
@ -198,7 +198,7 @@ impl VTabConnection {
/// #[repr(C)] /// #[repr(C)]
/// struct MyTab { /// struct MyTab {
/// /// Base class. Must be first /// /// Base class. Must be first
/// base: ffi::sqlite3_vtab, /// base: rusqlite::vtab::sqlite3_vtab,
/// /* Virtual table implementations will typically add additional fields */ /// /* Virtual table implementations will typically add additional fields */
/// } /// }
/// ``` /// ```
@ -228,7 +228,7 @@ pub unsafe trait VTab<'vtab>: Sized {
fn open(&'vtab self) -> Result<Self::Cursor>; fn open(&'vtab self) -> Result<Self::Cursor>;
} }
/// `feature = "vtab"` Non-eponymous virtual table instance trait. /// Non-eponymous virtual table instance trait.
/// ///
/// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html)) /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
pub trait CreateVTab<'vtab>: VTab<'vtab> { pub trait CreateVTab<'vtab>: VTab<'vtab> {
@ -257,7 +257,7 @@ pub trait CreateVTab<'vtab>: VTab<'vtab> {
} }
} }
/// `feature = "vtab"` Index constraint operator. /// Index constraint operator.
/// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details. /// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[allow(non_snake_case, non_camel_case_types, missing_docs)] #[allow(non_snake_case, non_camel_case_types, missing_docs)]
@ -302,7 +302,7 @@ impl From<u8> for IndexConstraintOp {
} }
} }
/// `feature = "vtab"` Pass information into and receive the reply from the /// Pass information into and receive the reply from the
/// [`VTab::best_index`] method. /// [`VTab::best_index`] method.
/// ///
/// (See [SQLite doc](http://sqlite.org/c3ref/index_info.html)) /// (See [SQLite doc](http://sqlite.org/c3ref/index_info.html))
@ -370,6 +370,7 @@ impl IndexInfo {
/// Estimated number of rows returned. /// Estimated number of rows returned.
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.8.2 #[cfg(feature = "modern_sqlite")] // SQLite >= 3.8.2
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
#[inline] #[inline]
pub fn set_estimated_rows(&mut self, estimated_rows: i64) { pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
unsafe { unsafe {
@ -402,7 +403,7 @@ impl<'a> Iterator for IndexConstraintIter<'a> {
} }
} }
/// `feature = "vtab"` WHERE clause constraint. /// WHERE clause constraint.
pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint); pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
impl IndexConstraint<'_> { impl IndexConstraint<'_> {
@ -425,7 +426,7 @@ impl IndexConstraint<'_> {
} }
} }
/// `feature = "vtab"` Information about what parameters to pass to /// Information about what parameters to pass to
/// [`VTabCursor::filter`]. /// [`VTabCursor::filter`].
pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage); pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
@ -463,7 +464,7 @@ impl<'a> Iterator for OrderByIter<'a> {
} }
} }
/// `feature = "vtab"` A column of the ORDER BY clause. /// A column of the ORDER BY clause.
pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby); pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
impl OrderBy<'_> { impl OrderBy<'_> {
@ -480,14 +481,14 @@ impl OrderBy<'_> {
} }
} }
/// `feature = "vtab"` Virtual table cursor trait. /// Virtual table cursor trait.
/// ///
/// Implementations must be like: /// Implementations must be like:
/// ```rust,ignore /// ```rust,ignore
/// #[repr(C)] /// #[repr(C)]
/// struct MyTabCursor { /// struct MyTabCursor {
/// /// Base class. Must be first /// /// Base class. Must be first
/// base: ffi::sqlite3_vtab_cursor, /// base: rusqlite::vtab::sqlite3_vtab_cursor,
/// /* Virtual table implementations will typically add additional fields */ /// /* Virtual table implementations will typically add additional fields */
/// } /// }
/// ``` /// ```
@ -514,7 +515,7 @@ pub unsafe trait VTabCursor: Sized {
fn rowid(&self) -> Result<i64>; fn rowid(&self) -> Result<i64>;
} }
/// `feature = "vtab"` Context is used by [`VTabCursor::column`] to specify the /// Context is used by [`VTabCursor::column`] to specify the
/// cell value. /// cell value.
pub struct Context(*mut ffi::sqlite3_context); pub struct Context(*mut ffi::sqlite3_context);
@ -530,7 +531,7 @@ impl Context {
// TODO sqlite3_vtab_nochange (http://sqlite.org/c3ref/vtab_nochange.html) // TODO sqlite3_vtab_nochange (http://sqlite.org/c3ref/vtab_nochange.html)
} }
/// `feature = "vtab"` Wrapper to [`VTabCursor::filter`] arguments, the values /// Wrapper to [`VTabCursor::filter`] arguments, the values
/// requested by [`VTab::best_index`]. /// requested by [`VTab::best_index`].
pub struct Values<'a> { pub struct Values<'a> {
args: &'a [*mut ffi::sqlite3_value], args: &'a [*mut ffi::sqlite3_value],
@ -560,10 +561,12 @@ impl Values<'_> {
} }
FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i), FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
FromSqlError::InvalidI128Size(_) => { FromSqlError::InvalidI128Size(_) => {
Error::InvalidColumnType(idx, idx.to_string(), value.data_type()) Error::InvalidColumnType(idx, idx.to_string(), value.data_type())
} }
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
FromSqlError::InvalidUuidSize(_) => { FromSqlError::InvalidUuidSize(_) => {
Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err)) Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
} }
@ -573,6 +576,7 @@ impl Values<'_> {
// `sqlite3_value_type` returns `SQLITE_NULL` for pointer. // `sqlite3_value_type` returns `SQLITE_NULL` for pointer.
// So it seems not possible to enhance `ValueRef::from_value`. // So it seems not possible to enhance `ValueRef::from_value`.
#[cfg(feature = "array")] #[cfg(feature = "array")]
#[cfg_attr(docsrs, doc(cfg(feature = "array")))]
fn get_array(&self, idx: usize) -> Option<array::Array> { fn get_array(&self, idx: usize) -> Option<array::Array> {
use crate::types::Value; use crate::types::Value;
let arg = self.args[idx]; let arg = self.args[idx];
@ -630,7 +634,7 @@ impl<'a> Iterator for ValueIter<'a> {
} }
impl Connection { impl Connection {
/// `feature = "vtab"` Register a virtual table implementation. /// Register a virtual table implementation.
/// ///
/// Step 3 of [Creating New Virtual Table /// Step 3 of [Creating New Virtual Table
/// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
@ -680,7 +684,7 @@ impl InnerConnection {
} }
} }
/// `feature = "vtab"` Escape double-quote (`"`) character occurrences by /// Escape double-quote (`"`) character occurrences by
/// doubling them (`""`). /// doubling them (`""`).
pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> { pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
if identifier.contains('"') { if identifier.contains('"') {
@ -690,7 +694,7 @@ pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
Borrowed(identifier) Borrowed(identifier)
} }
} }
/// `feature = "vtab"` Dequote string /// Dequote string
pub fn dequote(s: &str) -> &str { pub fn dequote(s: &str) -> &str {
if s.len() < 2 { if s.len() < 2 {
return s; return s;
@ -703,7 +707,7 @@ pub fn dequote(s: &str) -> &str {
_ => s, _ => s,
} }
} }
/// `feature = "vtab"` The boolean can be one of: /// The boolean can be one of:
/// ```text /// ```text
/// 1 yes true on /// 1 yes true on
/// 0 no false off /// 0 no false off
@ -1072,10 +1076,13 @@ fn alloc(s: &str) -> *mut c_char {
} }
#[cfg(feature = "array")] #[cfg(feature = "array")]
#[cfg_attr(docsrs, doc(cfg(feature = "array")))]
pub mod array; pub mod array;
#[cfg(feature = "csvtab")] #[cfg(feature = "csvtab")]
#[cfg_attr(docsrs, doc(cfg(feature = "csvtab")))]
pub mod csvtab; pub mod csvtab;
#[cfg(feature = "series")] #[cfg(feature = "series")]
#[cfg_attr(docsrs, doc(cfg(feature = "series")))]
pub mod series; // SQLite >= 3.9.0 pub mod series; // SQLite >= 3.9.0
#[cfg(test)] #[cfg(test)]

View File

@ -1,4 +1,4 @@
//! `feature = "series"` Generate series virtual table. //! Generate series virtual table.
//! //!
//! Port of C [generate series //! Port of C [generate series
//! "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c): //! "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c):
@ -15,7 +15,7 @@ use crate::vtab::{
}; };
use crate::{Connection, Error, Result}; use crate::{Connection, Error, Result};
/// `feature = "series"` Register the "generate_series" module. /// Register the "generate_series" module.
pub fn load_module(conn: &Connection) -> Result<()> { pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None; let aux: Option<()> = None;
conn.create_module("generate_series", eponymous_only_module::<SeriesTab>(), aux) conn.create_module("generate_series", eponymous_only_module::<SeriesTab>(), aux)

View File

@ -85,7 +85,7 @@ fn test_dummy_module() -> rusqlite::Result<()> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.create_module::<DummyTab>("dummy", &module, None)?; db.create_module::<DummyTab>("dummy", module, None)?;
let version = version_number(); let version = version_number();
if version < 3_008_012 { if version < 3_008_012 {