Merge remote-tracking branch 'upstream/master' into sub_type

# Conflicts:
#	src/functions.rs
This commit is contained in:
gwenn 2022-10-30 09:01:28 +01:00
commit 40a5035c8a
54 changed files with 25196 additions and 28094 deletions

View File

@ -1,7 +1,7 @@
[package]
name = "rusqlite"
# Note: Update version in README.md when you change this.
version = "0.27.0"
version = "0.28.0"
authors = ["The rusqlite developers"]
edition = "2018"
description = "Ergonomic wrapper for SQLite"
@ -35,16 +35,16 @@ members = ["libsqlite3-sys"]
[features]
load_extension = []
# hot-backup interface: 3.6.11 (2009-02-18)
backup = ["libsqlite3-sys/min_sqlite_version_3_6_23"]
backup = []
# sqlite3_blob_reopen: 3.7.4
blob = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
blob = []
collation = []
# sqlite3_create_function_v2: 3.7.3 (2010-10-08)
functions = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
functions = []
# sqlite3_log: 3.6.23 (2010-03-09)
trace = ["libsqlite3-sys/min_sqlite_version_3_6_23"]
trace = []
# sqlite3_db_release_memory: 3.7.10 (2012-01-16)
release_memory = ["libsqlite3-sys/min_sqlite_version_3_7_16"]
release_memory = []
bundled = ["libsqlite3-sys/bundled", "modern_sqlite"]
bundled-sqlcipher = ["libsqlite3-sys/bundled-sqlcipher", "bundled"]
bundled-sqlcipher-vendored-openssl = ["libsqlite3-sys/bundled-sqlcipher-vendored-openssl", "bundled-sqlcipher"]
@ -55,7 +55,7 @@ i128_blob = []
sqlcipher = ["libsqlite3-sys/sqlcipher"]
unlock_notify = ["libsqlite3-sys/unlock_notify"]
# xSavepoint, xRelease and xRollbackTo: 3.7.7 (2011-06-23)
vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
vtab = []
csvtab = ["csv", "vtab"]
# pointer passing interfaces: 3.20.0
array = ["vtab"]
@ -67,6 +67,7 @@ window = ["functions"]
series = ["vtab"]
# check for invalid query.
extra_check = []
# ]3.14.0, last]
modern_sqlite = ["libsqlite3-sys/bundled_bindings"]
in_gecko = ["modern_sqlite", "libsqlite3-sys/in_gecko"]
bundled-windows = ["libsqlite3-sys/bundled-windows"]
@ -136,7 +137,7 @@ bencher = "0.1"
[dependencies.libsqlite3-sys]
path = "libsqlite3-sys"
version = "0.24.0"
version = "0.25.0"
[[test]]
name = "config_log"

View File

@ -27,7 +27,7 @@ In your Cargo.toml:
# That said, it's not ideal for all scenarios and in particular, generic
# libraries built around `rusqlite` should probably not enable it, which
# is why it is not a default feature -- it could become hard to disable.
rusqlite = { version = "0.27.0", features = ["bundled"] }
rusqlite = { version = "0.28.0", features = ["bundled"] }
```
Simple example usage:
@ -81,7 +81,7 @@ fn main() -> Result<()> {
### Supported SQLite Versions
The base `rusqlite` package supports SQLite version 3.6.8 or newer. If you need
The base `rusqlite` package supports SQLite version 3.14.0 or newer. If you need
support for older versions, please file an issue. Some cargo features require a
newer SQLite version; see details below.
@ -149,11 +149,11 @@ You can adjust this behavior in a number of ways:
* If you use the `bundled`, `bundled-sqlcipher`, or `bundled-sqlcipher-vendored-openssl` features, `libsqlite3-sys` will use the
[cc](https://crates.io/crates/cc) crate to compile SQLite or SQLCipher from source and
link against that. This source is embedded in the `libsqlite3-sys` crate and
is currently SQLite 3.38.0 (as of `rusqlite` 0.27.0 / `libsqlite3-sys`
0.24.0). This is probably the simplest solution to any build problems. You can enable this by adding the following in your `Cargo.toml` file:
is currently SQLite 3.39.0 (as of `rusqlite` 0.28.0 / `libsqlite3-sys`
0.25.0). This is probably the simplest solution to any build problems. You can enable this by adding the following in your `Cargo.toml` file:
```toml
[dependencies.rusqlite]
version = "0.27.0"
version = "0.28.0"
features = ["bundled"]
```
* When using any of the `bundled` features, the build script will honor `SQLITE_MAX_VARIABLE_NUMBER` and `SQLITE_MAX_EXPR_DEPTH` variables. It will also honor a `LIBSQLITE3_FLAGS` variable, which can have a format like `"-USQLITE_ALPHA -DSQLITE_BETA SQLITE_GAMMA ..."`. That would disable the `SQLITE_ALPHA` flag, and set the `SQLITE_BETA` and `SQLITE_GAMMA` flags. (The initial `-D` can be omitted, as on the last one.)
@ -191,9 +191,7 @@ minimum SQLite version that supports your chosen features. If you are using
`libsqlite3-sys` directly, you can use the same features to choose which
pregenerated bindings are chosen:
* `min_sqlite_version_3_6_8` - SQLite 3.6.8 bindings (this is the default)
* `min_sqlite_version_3_6_23` - SQLite 3.6.23 bindings
* `min_sqlite_version_3_7_7` - SQLite 3.7.7 bindings
* `min_sqlite_version_3_14_0` - SQLite 3.14.0 bindings (this is the default)
If you use any of the `bundled` features, you will get pregenerated bindings for the
bundled version of SQLite/SQLCipher. If you need other specific pregenerated binding

View File

@ -1,6 +1,6 @@
[package]
name = "libsqlite3-sys"
version = "0.24.2"
version = "0.25.2"
authors = ["The rusqlite developers"]
edition = "2018"
repository = "https://github.com/rusqlite/rusqlite"
@ -12,17 +12,14 @@ keywords = ["sqlite", "sqlcipher", "ffi"]
categories = ["external-ffi-bindings"]
[features]
default = ["min_sqlite_version_3_6_8"]
default = ["min_sqlite_version_3_14_0"]
bundled = ["cc", "bundled_bindings"]
bundled-windows = ["cc", "bundled_bindings"]
bundled-sqlcipher = ["bundled"]
bundled-sqlcipher-vendored-openssl = ["bundled-sqlcipher", "openssl-sys/vendored"]
buildtime_bindgen = ["bindgen", "pkg-config", "vcpkg"]
sqlcipher = []
min_sqlite_version_3_6_8 = ["pkg-config", "vcpkg"]
min_sqlite_version_3_6_23 = ["pkg-config", "vcpkg"]
min_sqlite_version_3_7_7 = ["pkg-config", "vcpkg"]
min_sqlite_version_3_7_16 = ["pkg-config", "vcpkg"]
min_sqlite_version_3_14_0 = ["pkg-config", "vcpkg"]
# Bundle only the bindings file. Note that this does nothing if
# `buildtime_bindgen` is enabled.
bundled_bindings = []
@ -41,13 +38,13 @@ wasm32-wasi-vfs = []
# Note that because `winsqlite3.dll` exports SQLite functions using a atypical
# ABI on 32-bit systems, this is currently unsupported on these. This may change
# in the future.
winsqlite3 = ["min_sqlite_version_3_7_16"]
winsqlite3 = []
[dependencies]
openssl-sys = { version = "0.9", optional = true }
[build-dependencies]
bindgen = { version = "0.59", optional = true, default-features = false, features = ["runtime"] }
bindgen = { version = "0.61", optional = true, default-features = false, features = ["runtime"] }
pkg-config = { version = "0.3.19", optional = true }
cc = { version = "1.0", optional = true }
vcpkg = { version = "0.2", optional = true }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,14 +8,14 @@ use std::path::Path;
/// targetting, and this test must be made at run-time (of the build script) See
/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
fn win_target() -> bool {
std::env::var("CARGO_CFG_WINDOWS").is_ok()
env::var("CARGO_CFG_WINDOWS").is_ok()
}
/// Tells whether we're building for Android.
/// See [`win_target`]
#[cfg(any(feature = "bundled", feature = "bundled-windows"))]
fn android_target() -> bool {
std::env::var("CARGO_CFG_TARGET_OS").map_or(false, |v| v == "android")
env::var("CARGO_CFG_TARGET_OS").map_or(false, |v| v == "android")
}
/// Tells whether a given compiler will be used `compiler_name` is compared to
@ -23,7 +23,7 @@ fn android_target() -> bool {
///
/// See [`win_target`]
fn is_compiler(compiler_name: &str) -> bool {
std::env::var("CARGO_CFG_TARGET_ENV").map_or(false, |v| v == compiler_name)
env::var("CARGO_CFG_TARGET_ENV").map_or(false, |v| v == compiler_name)
}
fn main() {
@ -98,15 +98,15 @@ mod build_bundled {
#[cfg(not(feature = "buildtime_bindgen"))]
{
use std::fs;
fs::copy(format!("{}/bindgen_bundled_version.rs", lib_name), out_path)
fs::copy(format!("{lib_name}/bindgen_bundled_version.rs"), out_path)
.expect("Could not copy bindings to output directory");
}
// println!("cargo:rerun-if-changed=sqlite3/sqlite3.c");
// println!("cargo:rerun-if-changed=sqlcipher/sqlite3.c");
println!("cargo:rerun-if-changed={}/sqlite3.c", lib_name);
println!("cargo:rerun-if-changed={lib_name}/sqlite3.c");
println!("cargo:rerun-if-changed=sqlite3/wasm32-wasi-vfs.c");
let mut cfg = cc::Build::new();
cfg.file(format!("{}/sqlite3.c", lib_name))
cfg.file(format!("{lib_name}/sqlite3.c"))
.flag("-DSQLITE_CORE")
.flag("-DSQLITE_DEFAULT_FOREIGN_KEYS=1")
.flag("-DSQLITE_ENABLE_API_ARMOR")
@ -178,7 +178,7 @@ mod build_bundled {
};
if cfg!(feature = "bundled-sqlcipher-vendored-openssl") {
cfg.include(std::env::var("DEP_OPENSSL_INCLUDE").unwrap());
cfg.include(env::var("DEP_OPENSSL_INCLUDE").unwrap());
// cargo will resolve downstream to the static lib in
// openssl-sys
} else if is_windows {
@ -261,12 +261,12 @@ mod build_bundled {
}
if let Ok(limit) = env::var("SQLITE_MAX_VARIABLE_NUMBER") {
cfg.flag(&format!("-DSQLITE_MAX_VARIABLE_NUMBER={}", limit));
cfg.flag(&format!("-DSQLITE_MAX_VARIABLE_NUMBER={limit}"));
}
println!("cargo:rerun-if-env-changed=SQLITE_MAX_VARIABLE_NUMBER");
if let Ok(limit) = env::var("SQLITE_MAX_EXPR_DEPTH") {
cfg.flag(&format!("-DSQLITE_MAX_EXPR_DEPTH={}", limit));
cfg.flag(&format!("-DSQLITE_MAX_EXPR_DEPTH={limit}"));
}
println!("cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH");
@ -275,7 +275,7 @@ mod build_bundled {
if extra.starts_with("-D") || extra.starts_with("-U") {
cfg.flag(extra);
} else if extra.starts_with("SQLITE_") {
cfg.flag(&format!("-D{}", extra));
cfg.flag(&format!("-D{extra}"));
} else {
panic!("Don't understand {} in LIBSQLITE3_FLAGS", extra);
}
@ -285,13 +285,13 @@ mod build_bundled {
cfg.compile(lib_name);
println!("cargo:lib_dir={}", out_dir);
println!("cargo:lib_dir={out_dir}");
}
fn env(name: &str) -> Option<OsString> {
let prefix = env::var("TARGET").unwrap().to_uppercase().replace('-', "_");
let prefixed = format!("{}_{}", prefix, name);
let var = env::var_os(&prefixed);
let prefixed = format!("{prefix}_{name}");
let var = env::var_os(prefixed);
match var {
None => env::var_os(name),
@ -334,7 +334,7 @@ impl From<HeaderLocation> for String {
match header {
HeaderLocation::FromEnvironment => {
let prefix = env_prefix();
let mut header = env::var(format!("{}_INCLUDE_DIR", prefix)).unwrap_or_else(|_| {
let mut header = env::var(format!("{prefix}_INCLUDE_DIR")).unwrap_or_else(|_| {
panic!(
"{}_INCLUDE_DIR must be set if {}_LIB_DIR is set",
prefix, prefix
@ -404,10 +404,10 @@ mod build_linked {
// `links=` value in our Cargo.toml) to get this value. This might be
// useful if you need to ensure whatever crypto library sqlcipher relies
// on is available, for example.
println!("cargo:link-target={}", link_lib);
println!("cargo:link-target={link_lib}");
if win_target() && cfg!(feature = "winsqlite3") {
println!("cargo:rustc-link-lib=dylib={}", link_lib);
println!("cargo:rustc-link-lib=dylib={link_lib}");
return HeaderLocation::Wrapper;
}
@ -418,8 +418,8 @@ mod build_linked {
env::set_var("PKG_CONFIG_PATH", pkgconfig_path);
if pkg_config::Config::new().probe(link_lib).is_err() {
// Otherwise just emit the bare minimum link commands.
println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
println!("cargo:rustc-link-search={}", dir);
println!("cargo:rustc-link-lib={}={link_lib}", find_link_mode());
println!("cargo:rustc-link-search={dir}");
}
return HeaderLocation::FromEnvironment;
}
@ -444,7 +444,7 @@ mod build_linked {
// request and hope that the library exists on the system paths. We used to
// output /usr/lib explicitly, but that can introduce other linking problems;
// see https://github.com/rusqlite/rusqlite/issues/207.
println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
println!("cargo:rustc-link-lib={}={link_lib}", find_link_mode());
HeaderLocation::Wrapper
}
}
@ -473,15 +473,7 @@ mod bindings {
use std::fs;
use std::path::Path;
static PREBUILT_BINDGEN_PATHS: &[&str] = &[
"bindgen-bindings/bindgen_3.6.8.rs",
#[cfg(feature = "min_sqlite_version_3_6_23")]
"bindgen-bindings/bindgen_3.6.23.rs",
#[cfg(feature = "min_sqlite_version_3_7_7")]
"bindgen-bindings/bindgen_3.7.7.rs",
#[cfg(feature = "min_sqlite_version_3_7_16")]
"bindgen-bindings/bindgen_3.7.16.rs",
];
static PREBUILT_BINDGEN_PATHS: &[&str] = &["bindgen-bindings/bindgen_3.14.0.rs"];
pub fn write_to_out_dir(_header: HeaderLocation, out_path: &Path) {
let in_path = PREBUILT_BINDGEN_PATHS[PREBUILT_BINDGEN_PATHS.len() - 1];
@ -505,7 +497,7 @@ mod bindings {
impl ParseCallbacks for SqliteTypeChooser {
fn int_macro(&self, _name: &str, value: i64) -> Option<IntKind> {
if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 {
if value >= i32::MIN as i64 && value <= i32::MAX as i64 {
Some(IntKind::I32)
} else {
None
@ -607,6 +599,7 @@ mod bindings {
}
bindings
.layout_tests(false)
.generate()
.unwrap_or_else(|_| panic!("could not run bindgen on header {}", header))
.write(Box::new(&mut output))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.37.2"
#define SQLITE_VERSION_NUMBER 3037002
#define SQLITE_SOURCE_ID "2022-01-06 13:25:41 872ba256cbf61d9290b571c0e6d82a20c224ca3ad82971edc46b29818d5dalt1"
#define SQLITE_VERSION "3.39.2"
#define SQLITE_VERSION_NUMBER 3039002
#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668ealt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -566,7 +566,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */
/*
** CAPI3REF: Flags For File Open Operations
@ -3824,13 +3824,14 @@ SQLITE_API void sqlite3_free_filename(char*);
** sqlite3_extended_errcode() might change with each API call.
** Except, there are some interfaces that are guaranteed to never
** change the value of the error code. The error-code preserving
** interfaces are:
** interfaces include the following:
**
** <ul>
** <li> sqlite3_errcode()
** <li> sqlite3_extended_errcode()
** <li> sqlite3_errmsg()
** <li> sqlite3_errmsg16()
** <li> sqlite3_error_offset()
** </ul>
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
@ -3845,6 +3846,13 @@ SQLITE_API void sqlite3_free_filename(char*);
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
** ^If the most recent error references a specific token in the input
** SQL, the sqlite3_error_offset() interface returns the byte offset
** of the start of that token. ^The byte offset returned by
** sqlite3_error_offset() assumes that the input SQL is UTF8.
** ^If the most recent error does not reference a specific token in the input
** SQL, then the sqlite3_error_offset() function returns -1.
**
** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces.
@ -3864,6 +3872,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
SQLITE_API const char *sqlite3_errstr(int);
SQLITE_API int sqlite3_error_offset(sqlite3 *db);
/*
** CAPI3REF: Prepared Statement Object
@ -4275,6 +4284,10 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
** 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.
**
** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN]
** statement, then sqlite3_stmt_readonly(X) returns the same value as
** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted.
*/
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
@ -4343,6 +4356,8 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
**
** ^The sqlite3_value objects that are passed as parameters into the
** implementation of [application-defined SQL functions] are protected.
** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()]
** are protected.
** ^The sqlite3_value object returned by
** [sqlite3_column_value()] is unprotected.
** Unprotected sqlite3_value objects may only be used as arguments
@ -4964,6 +4979,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** even empty strings, are always zero-terminated. ^The return
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
**
** ^Strings returned by sqlite3_column_text16() always have the endianness
** which is native to the platform, regardless of the text encoding set
** for the database.
**
** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
** [unprotected sqlite3_value] object. In a multithreaded environment,
** an unprotected sqlite3_value object may only be used safely with
@ -4977,7 +4996,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** [application-defined SQL functions] or [virtual tables], not within
** top-level application code.
**
** The these routines may attempt to convert the datatype of the result.
** These routines may attempt to convert the datatype of the result.
** ^For example, if the internal representation is FLOAT and a text result
** is requested, [sqlite3_snprintf()] is used internally to perform the
** conversion automatically. ^(The following table details the conversions
@ -5002,7 +5021,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** <tr><td> TEXT <td> BLOB <td> No change
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
** <tr><td> BLOB <td> TEXT <td> [CAST] to TEXT, ensure zero terminator
** </table>
** </blockquote>)^
**
@ -5574,7 +5593,8 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
** is a [protected sqlite3_value] object even if the input is not.
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
** memory allocation fails.
** memory allocation fails. ^If V is a [pointer value], then the result
** of sqlite3_value_dup(V) is a NULL value.
**
** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object
** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
@ -6316,6 +6336,28 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
*/
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Schema Name For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
** for the N-th database on database connection D, or a NULL pointer of N is
** out of range. An N value of 0 means the main database file. An N of 1 is
** the "temp" schema. Larger values of N correspond to various ATTACH-ed
** databases.
**
** Space to hold the string that is returned by sqlite3_db_name() is managed
** by SQLite itself. The string might be deallocated by any operation that
** changes the schema, including [ATTACH] or [DETACH] or calls to
** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that
** occur on a different thread. Applications that need to
** remember the string long-term should make their own copy. Applications that
** are accessing the same database connection simultaneously on multiple
** threads should mutex-protect calls to this API and should make their own
** private copy of the result prior to releasing the mutex.
*/
SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
@ -7182,24 +7224,56 @@ struct sqlite3_index_info {
**
** These macros define the allowed values for the
** [sqlite3_index_info].aConstraint[].op field. Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** an operator that is part of a constraint term in the WHERE clause of
** a query that uses a [virtual table].
**
** ^The left-hand operand of the operator is given by the corresponding
** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand
** operand is the rowid.
** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET
** operators have no left-hand operand, and so for those operators the
** corresponding aConstraint[].iColumn is meaningless and should not be
** used.
**
** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through
** value 255 are reserved to represent functions that are overloaded
** by the [xFindFunction|xFindFunction method] of the virtual table
** implementation.
**
** The right-hand operands for each constraint might be accessible using
** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand
** operand is only available if it appears as a single constant literal
** in the input SQL. If the right-hand operand is another column or an
** expression (even a constant expression) or a parameter, then the
** sqlite3_vtab_rhs_value() probably will not be able to extract it.
** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and
** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand
** and hence calls to sqlite3_vtab_rhs_value() for those operators will
** always return SQLITE_NOTFOUND.
**
** The collating sequence to be used for comparison can be found using
** the [sqlite3_vtab_collation()] interface. For most real-world virtual
** tables, the collating sequence of constraints does not matter (for example
** because the constraints are numeric) and so the sqlite3_vtab_collation()
** interface is no commonly needed.
*/
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
#define SQLITE_INDEX_CONSTRAINT_LT 16
#define SQLITE_INDEX_CONSTRAINT_GE 32
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
#define SQLITE_INDEX_CONSTRAINT_LIKE 65
#define SQLITE_INDEX_CONSTRAINT_GLOB 66
#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
#define SQLITE_INDEX_CONSTRAINT_NE 68
#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
#define SQLITE_INDEX_CONSTRAINT_IS 72
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
#define SQLITE_INDEX_CONSTRAINT_LT 16
#define SQLITE_INDEX_CONSTRAINT_GE 32
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
#define SQLITE_INDEX_CONSTRAINT_LIKE 65
#define SQLITE_INDEX_CONSTRAINT_GLOB 66
#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
#define SQLITE_INDEX_CONSTRAINT_NE 68
#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
#define SQLITE_INDEX_CONSTRAINT_IS 72
#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
/*
** CAPI3REF: Register A Virtual Table Implementation
@ -7228,7 +7302,7 @@ struct sqlite3_index_info {
** destructor.
**
** ^If the third parameter (the pointer to the sqlite3_module object) is
** NULL then no new module is create and any existing modules with the
** NULL then no new module is created and any existing modules with the
** same name are dropped.
**
** See also: [sqlite3_drop_modules()]
@ -8004,7 +8078,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SEEK_COUNT 30
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */
#define SQLITE_TESTCTRL_LOGEST 33
#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@ -8527,6 +8602,16 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** The counter is incremented on the first [sqlite3_step()] call of each
** cycle.
**
** [[SQLITE_STMTSTATUS_FILTER_MISS]]
** [[SQLITE_STMTSTATUS_FILTER HIT]]
** <dt>SQLITE_STMTSTATUS_FILTER_HIT<br>
** SQLITE_STMTSTATUS_FILTER_MISS</dt>
** <dd>^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join
** step was bypassed because a Bloom filter returned not-found. The
** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
** times that the Bloom filter returned a find, and thus the join step
** had to be processed as normal.
**
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
** <dd>^This is the approximate number of bytes of heap memory
** used to store the prepared statement. ^This value is not actually
@ -8541,6 +8626,8 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
#define SQLITE_STMTSTATUS_VM_STEP 4
#define SQLITE_STMTSTATUS_REPREPARE 5
#define SQLITE_STMTSTATUS_RUN 6
#define SQLITE_STMTSTATUS_FILTER_MISS 7
#define SQLITE_STMTSTATUS_FILTER_HIT 8
#define SQLITE_STMTSTATUS_MEMUSED 99
/*
@ -9509,19 +9596,276 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
/*
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
** METHOD: sqlite3_index_info
**
** This function may only be called from within a call to the [xBestIndex]
** method of a [virtual table].
** method of a [virtual table]. This function returns a pointer to a string
** that is the name of the appropriate collation sequence to use for text
** comparisons on the constraint identified by its arguments.
**
** The first argument must be the sqlite3_index_info object that is the
** first parameter to the xBestIndex() method. The second argument must be
** an index into the aConstraint[] array belonging to the sqlite3_index_info
** structure passed to xBestIndex. This function returns a pointer to a buffer
** containing the name of the collation sequence for the corresponding
** constraint.
** The first argument must be the pointer to the [sqlite3_index_info] object
** that is the first parameter to the xBestIndex() method. The second argument
** must be an index into the aConstraint[] array belonging to the
** sqlite3_index_info structure passed to xBestIndex.
**
** Important:
** The first parameter must be the same pointer that is passed into the
** xBestMethod() method. The first parameter may not be a pointer to a
** different [sqlite3_index_info] object, even an exact copy.
**
** The return value is computed as follows:
**
** <ol>
** <li><p> If the constraint comes from a WHERE clause expression that contains
** a [COLLATE operator], then the name of the collation specified by
** that COLLATE operator is returned.
** <li><p> If there is no COLLATE operator, but the column that is the subject
** of the constraint specifies an alternative collating sequence via
** a [COLLATE clause] on the column definition within the CREATE TABLE
** statement that was passed into [sqlite3_declare_vtab()], then the
** name of that alternative collating sequence is returned.
** <li><p> Otherwise, "BINARY" is returned.
** </ol>
*/
SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
/*
** CAPI3REF: Determine if a virtual table query is DISTINCT
** METHOD: sqlite3_index_info
**
** This API may only be used from within an [xBestIndex|xBestIndex method]
** of a [virtual table] implementation. The result of calling this
** interface from outside of xBestIndex() is undefined and probably harmful.
**
** ^The sqlite3_vtab_distinct() interface returns an integer between 0 and
** 3. The integer returned by sqlite3_vtab_distinct()
** gives the virtual table additional information about how the query
** planner wants the output to be ordered. As long as the virtual table
** can meet the ordering requirements of the query planner, it may set
** the "orderByConsumed" flag.
**
** <ol><li value="0"><p>
** ^If the sqlite3_vtab_distinct() interface returns 0, that means
** that the query planner needs the virtual table to return all rows in the
** sort order defined by the "nOrderBy" and "aOrderBy" fields of the
** [sqlite3_index_info] object. This is the default expectation. If the
** virtual table outputs all rows in sorted order, then it is always safe for
** the xBestIndex method to set the "orderByConsumed" flag, regardless of
** the return value from sqlite3_vtab_distinct().
** <li value="1"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 1, that means
** that the query planner does not need the rows to be returned in sorted order
** as long as all rows with the same values in all columns identified by the
** "aOrderBy" field are adjacent.)^ This mode is used when the query planner
** is doing a GROUP BY.
** <li value="2"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular
** order, as long as rows with the same values in all "aOrderBy" columns
** are adjacent.)^ ^(Furthermore, only a single row for each particular
** combination of values in the columns identified by the "aOrderBy" field
** needs to be returned.)^ ^It is always ok for two or more rows with the same
** values in all "aOrderBy" columns to be returned, as long as all such rows
** are adjacent. ^The virtual table may, if it chooses, omit extra rows
** that have the same value for all columns identified by "aOrderBy".
** ^However omitting the extra rows is optional.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 3, that means
** that the query planner needs only distinct rows but it does need the
** rows to be sorted.)^ ^The virtual table implementation is free to omit
** rows that are identical in all aOrderBy columns, if it wants to, but
** it is not required to omit any rows. This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
** (or "IS NOT DISTINCT FROM") and not "==".
**
** If a virtual table implementation is unable to meet the requirements
** specified above, then it must not set the "orderByConsumed" flag in the
** [sqlite3_index_info] object or an incorrect answer may result.
**
** ^A virtual table implementation is always free to return rows in any order
** it wants, as long as the "orderByConsumed" flag is not set. ^When the
** the "orderByConsumed" flag is unset, the query planner will add extra
** [bytecode] to ensure that the final results returned by the SQL query are
** ordered correctly. The use of the "orderByConsumed" flag and the
** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed"
** flag might help queries against a virtual table to run faster. Being
** overly aggressive and setting the "orderByConsumed" flag when it is not
** valid to do so, on the other hand, might cause SQLite to return incorrect
** results.
*/
SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
/*
** CAPI3REF: Identify and handle IN constraints in xBestIndex
**
** This interface may only be used from within an
** [xBestIndex|xBestIndex() method] of a [virtual table] implementation.
** The result of invoking this interface from any other context is
** undefined and probably harmful.
**
** ^(A constraint on a virtual table of the form
** "[IN operator|column IN (...)]" is
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
** only sees a single value from the right-hand side of the IN operator
** at a time.
**
** In some cases, however, it would be advantageous for the virtual
** table to see all values on the right-hand of the IN operator all at
** once. The sqlite3_vtab_in() interfaces facilitates this in two ways:
**
** <ol>
** <li><p>
** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero)
** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint
** is an [IN operator] that can be processed all at once. ^In other words,
** sqlite3_vtab_in() with -1 in the third argument is a mechanism
** by which the virtual table can ask SQLite if all-at-once processing
** of the IN operator is even possible.
**
** <li><p>
** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates
** to SQLite that the virtual table does or does not want to process
** the IN operator all-at-once, respectively. ^Thus when the third
** parameter (F) is non-negative, this interface is the mechanism by
** which the virtual table tells SQLite how it wants to process the
** IN operator.
** </ol>
**
** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times
** within the same xBestIndex method call. ^For any given P,N pair,
** the return value from sqlite3_vtab_in(P,N,F) will always be the same
** within the same xBestIndex call. ^If the interface returns true
** (non-zero), that means that the constraint is an IN operator
** that can be processed all-at-once. ^If the constraint is not an IN
** operator or cannot be processed all-at-once, then the interface returns
** false.
**
** ^(All-at-once processing of the IN operator is selected if both of the
** following conditions are met:
**
** <ol>
** <li><p> The P->aConstraintUsage[N].argvIndex value is set to a positive
** integer. This is how the virtual table tells SQLite that it wants to
** use the N-th constraint.
**
** <li><p> The last call to sqlite3_vtab_in(P,N,F) for which F was
** non-negative had F>=1.
** </ol>)^
**
** ^If either or both of the conditions above are false, then SQLite uses
** the traditional one-at-a-time processing strategy for the IN constraint.
** ^If both conditions are true, then the argvIndex-th parameter to the
** xFilter method will be an [sqlite3_value] that appears to be NULL,
** but which can be passed to [sqlite3_vtab_in_first()] and
** [sqlite3_vtab_in_next()] to find all values on the right-hand side
** of the IN constraint.
*/
SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
/*
** CAPI3REF: Find all elements on the right-hand side of an IN constraint.
**
** These interfaces are only useful from within the
** [xFilter|xFilter() method] of a [virtual table] implementation.
** The result of invoking these interfaces from any other context
** is undefined and probably harmful.
**
** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
** sqlite3_vtab_in_next(X,P) must be one of the parameters to the
** xFilter method which invokes these routines, and specifically
** a parameter that was previously selected for all-at-once IN constraint
** processing use the [sqlite3_vtab_in()] interface in the
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
** an xFilter argument that was selected for all-at-once IN constraint
** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
** exhibit some other undefined or harmful behavior.
**
** ^(Use these routines to access all values on the right-hand side
** of the IN constraint using code like the following:
**
** <blockquote><pre>
** &nbsp; for(rc=sqlite3_vtab_in_first(pList, &pVal);
** &nbsp; rc==SQLITE_OK && pVal
** &nbsp; rc=sqlite3_vtab_in_next(pList, &pVal)
** &nbsp; ){
** &nbsp; // do something with pVal
** &nbsp; }
** &nbsp; if( rc!=SQLITE_OK ){
** &nbsp; // an error has occurred
** &nbsp; }
** </pre></blockquote>)^
**
** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P)
** routines return SQLITE_OK and set *P to point to the first or next value
** on the RHS of the IN constraint. ^If there are no more values on the
** right hand side of the IN constraint, then *P is set to NULL and these
** routines return [SQLITE_DONE]. ^The return value might be
** some other value, such as SQLITE_NOMEM, in the event of a malfunction.
**
** The *ppOut values returned by these routines are only valid until the
** next call to either of these routines or until the end of the xFilter
** method from which these routines were called. If the virtual table
** implementation needs to retain the *ppOut values for longer, it must make
** copies. The *ppOut values are [protected sqlite3_value|protected].
*/
SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
/*
** CAPI3REF: Constraint values in xBestIndex()
** METHOD: sqlite3_index_info
**
** This API may only be used from within the [xBestIndex|xBestIndex method]
** of a [virtual table] implementation. The result of calling this interface
** from outside of an xBestIndex method are undefined and probably harmful.
**
** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
** the [xBestIndex] method of a [virtual table] implementation, with P being
** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and
** J being a 0-based index into P->aConstraint[], then this routine
** attempts to set *V to the value of the right-hand operand of
** that constraint if the right-hand operand is known. ^If the
** right-hand operand is not known, then *V is set to a NULL pointer.
** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if
** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
** something goes wrong.
**
** The sqlite3_vtab_rhs_value() interface is usually only successful if
** the right-hand operand of a constraint is a literal value in the original
** SQL statement. If the right-hand operand is an expression or a reference
** to some other column or a [host parameter], then sqlite3_vtab_rhs_value()
** will probably return [SQLITE_NOTFOUND].
**
** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and
** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such
** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^
**
** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value
** and remains valid for the duration of the xBestIndex method call.
** ^When xBestIndex returns, the sqlite3_value object returned by
** sqlite3_vtab_rhs_value() is automatically deallocated.
**
** The "_rhs_" in the name of this routine is an abbreviation for
** "Right-Hand Side".
*/
SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}

View File

@ -344,6 +344,19 @@ struct sqlite3_api_routines {
int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*));
/* Version 3.38.0 and later */
int (*error_offset)(sqlite3*);
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
int (*vtab_distinct)(sqlite3_index_info*);
int (*vtab_in)(sqlite3_index_info*,int,int);
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
};
/*
@ -655,6 +668,19 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
/* Version 3.38.0 and later */
#define sqlite3_error_offset sqlite3_api->error_offset
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
#define sqlite3_vtab_in sqlite3_api->vtab_in
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize sqlite3_api->deserialize
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.38.3"
#define SQLITE_VERSION_NUMBER 3038003
#define SQLITE_SOURCE_ID "2022-04-27 12:03:15 9547e2c38a1c6f751a77d4d796894dec4dc5d8f5d79b1cd39e1ffc50df7b3be4"
#define SQLITE_VERSION "3.39.4"
#define SQLITE_VERSION_NUMBER 3039004
#define SQLITE_SOURCE_ID "2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26b309"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -5593,7 +5593,8 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
** is a [protected sqlite3_value] object even if the input is not.
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
** memory allocation fails.
** memory allocation fails. ^If V is a [pointer value], then the result
** of sqlite3_value_dup(V) is a NULL value.
**
** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object
** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
@ -6275,6 +6276,28 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
*/
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Schema Name For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
** for the N-th database on database connection D, or a NULL pointer of N is
** out of range. An N value of 0 means the main database file. An N of 1 is
** the "temp" schema. Larger values of N correspond to various ATTACH-ed
** databases.
**
** Space to hold the string that is returned by sqlite3_db_name() is managed
** by SQLite itself. The string might be deallocated by any operation that
** changes the schema, including [ATTACH] or [DETACH] or calls to
** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that
** occur on a different thread. Applications that need to
** remember the string long-term should make their own copy. Applications that
** are accessing the same database connection simultaneously on multiple
** threads should mutex-protect calls to this API and should make their own
** private copy of the result prior to releasing the mutex.
*/
SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
@ -9554,8 +9577,8 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
** of a [virtual table] implementation. The result of calling this
** interface from outside of xBestIndex() is undefined and probably harmful.
**
** ^The sqlite3_vtab_distinct() interface returns an integer that is
** either 0, 1, or 2. The integer returned by sqlite3_vtab_distinct()
** ^The sqlite3_vtab_distinct() interface returns an integer between 0 and
** 3. The integer returned by sqlite3_vtab_distinct()
** gives the virtual table additional information about how the query
** planner wants the output to be ordered. As long as the virtual table
** can meet the ordering requirements of the query planner, it may set
@ -9587,6 +9610,13 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
** that have the same value for all columns identified by "aOrderBy".
** ^However omitting the extra rows is optional.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 3, that means
** that the query planner needs only distinct rows but it does need the
** rows to be sorted.)^ ^The virtual table implementation is free to omit
** rows that are identical in all aOrderBy columns, if it wants to, but
** it is not required to omit any rows. This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
** ^For the purposes of comparing virtual table output values to see if the

View File

@ -351,6 +351,12 @@ struct sqlite3_api_routines {
int (*vtab_in)(sqlite3_index_info*,int,int);
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
};
/*
@ -669,6 +675,12 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_vtab_in sqlite3_api->vtab_in
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize sqlite3_api->deserialize
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

View File

@ -122,77 +122,32 @@ impl error::Error for Error {
// so we don't have to worry about which version of SQLite added which
// constants, and we only use them to implement code_to_str below.
const SQLITE_NOTICE: c_int = 27;
const SQLITE_WARNING: c_int = 28;
// Extended result codes.
const SQLITE_ERROR_MISSING_COLLSEQ: c_int = super::SQLITE_ERROR | (1 << 8);
const SQLITE_ERROR_RETRY: c_int = super::SQLITE_ERROR | (2 << 8);
const SQLITE_ERROR_SNAPSHOT: c_int = super::SQLITE_ERROR | (3 << 8);
const SQLITE_IOERR_SHMOPEN: c_int = super::SQLITE_IOERR | (18 << 8);
const SQLITE_IOERR_SHMSIZE: c_int = super::SQLITE_IOERR | (19 << 8);
const SQLITE_IOERR_SHMLOCK: c_int = super::SQLITE_IOERR | (20 << 8);
const SQLITE_IOERR_SHMMAP: c_int = super::SQLITE_IOERR | (21 << 8);
const SQLITE_IOERR_SEEK: c_int = super::SQLITE_IOERR | (22 << 8);
const SQLITE_IOERR_DELETE_NOENT: c_int = super::SQLITE_IOERR | (23 << 8);
const SQLITE_IOERR_MMAP: c_int = super::SQLITE_IOERR | (24 << 8);
const SQLITE_IOERR_GETTEMPPATH: c_int = super::SQLITE_IOERR | (25 << 8);
const SQLITE_IOERR_CONVPATH: c_int = super::SQLITE_IOERR | (26 << 8);
const SQLITE_IOERR_VNODE: c_int = super::SQLITE_IOERR | (27 << 8);
const SQLITE_IOERR_AUTH: c_int = super::SQLITE_IOERR | (28 << 8);
const SQLITE_IOERR_BEGIN_ATOMIC: c_int = super::SQLITE_IOERR | (29 << 8);
const SQLITE_IOERR_COMMIT_ATOMIC: c_int = super::SQLITE_IOERR | (30 << 8);
const SQLITE_IOERR_ROLLBACK_ATOMIC: c_int = super::SQLITE_IOERR | (31 << 8);
const SQLITE_IOERR_DATA: c_int = super::SQLITE_IOERR | (32 << 8);
const SQLITE_LOCKED_SHAREDCACHE: c_int = super::SQLITE_LOCKED | (1 << 8);
const SQLITE_LOCKED_VTAB: c_int = super::SQLITE_LOCKED | (2 << 8);
const SQLITE_BUSY_RECOVERY: c_int = super::SQLITE_BUSY | (1 << 8);
const SQLITE_BUSY_SNAPSHOT: c_int = super::SQLITE_BUSY | (2 << 8);
const SQLITE_BUSY_TIMEOUT: c_int = super::SQLITE_BUSY | (3 << 8);
const SQLITE_CANTOPEN_NOTEMPDIR: c_int = super::SQLITE_CANTOPEN | (1 << 8);
const SQLITE_CANTOPEN_ISDIR: c_int = super::SQLITE_CANTOPEN | (2 << 8);
const SQLITE_CANTOPEN_FULLPATH: c_int = super::SQLITE_CANTOPEN | (3 << 8);
const SQLITE_CANTOPEN_CONVPATH: c_int = super::SQLITE_CANTOPEN | (4 << 8);
const SQLITE_CANTOPEN_SYMLINK: c_int = super::SQLITE_CANTOPEN | (6 << 8);
const SQLITE_CORRUPT_VTAB: c_int = super::SQLITE_CORRUPT | (1 << 8);
const SQLITE_CORRUPT_SEQUENCE: c_int = super::SQLITE_CORRUPT | (2 << 8);
const SQLITE_CORRUPT_INDEX: c_int = super::SQLITE_CORRUPT | (3 << 8);
const SQLITE_READONLY_RECOVERY: c_int = super::SQLITE_READONLY | (1 << 8);
const SQLITE_READONLY_CANTLOCK: c_int = super::SQLITE_READONLY | (2 << 8);
const SQLITE_READONLY_ROLLBACK: c_int = super::SQLITE_READONLY | (3 << 8);
const SQLITE_READONLY_DBMOVED: c_int = super::SQLITE_READONLY | (4 << 8);
const SQLITE_READONLY_CANTINIT: c_int = super::SQLITE_READONLY | (5 << 8);
const SQLITE_READONLY_DIRECTORY: c_int = super::SQLITE_READONLY | (6 << 8);
const SQLITE_ABORT_ROLLBACK: c_int = super::SQLITE_ABORT | (2 << 8);
const SQLITE_CONSTRAINT_CHECK: c_int = super::SQLITE_CONSTRAINT | (1 << 8);
const SQLITE_CONSTRAINT_COMMITHOOK: c_int = super::SQLITE_CONSTRAINT | (2 << 8);
const SQLITE_CONSTRAINT_FOREIGNKEY: c_int = super::SQLITE_CONSTRAINT | (3 << 8);
const SQLITE_CONSTRAINT_FUNCTION: c_int = super::SQLITE_CONSTRAINT | (4 << 8);
const SQLITE_CONSTRAINT_NOTNULL: c_int = super::SQLITE_CONSTRAINT | (5 << 8);
const SQLITE_CONSTRAINT_PRIMARYKEY: c_int = super::SQLITE_CONSTRAINT | (6 << 8);
const SQLITE_CONSTRAINT_TRIGGER: c_int = super::SQLITE_CONSTRAINT | (7 << 8);
const SQLITE_CONSTRAINT_UNIQUE: c_int = super::SQLITE_CONSTRAINT | (8 << 8);
const SQLITE_CONSTRAINT_VTAB: c_int = super::SQLITE_CONSTRAINT | (9 << 8);
const SQLITE_CONSTRAINT_ROWID: c_int = super::SQLITE_CONSTRAINT | (10 << 8);
const SQLITE_CONSTRAINT_PINNED: c_int = super::SQLITE_CONSTRAINT | (11 << 8);
const SQLITE_CONSTRAINT_DATATYPE: c_int = super::SQLITE_CONSTRAINT | (12 << 8);
const SQLITE_NOTICE_RECOVER_WAL: c_int = SQLITE_NOTICE | (1 << 8);
const SQLITE_NOTICE_RECOVER_ROLLBACK: c_int = SQLITE_NOTICE | (2 << 8);
const SQLITE_WARNING_AUTOINDEX: c_int = SQLITE_WARNING | (1 << 8);
const SQLITE_AUTH_USER: c_int = super::SQLITE_AUTH | (1 << 8);
#[must_use]
pub fn code_to_str(code: c_int) -> &'static str {
match code {
@ -223,8 +178,8 @@ pub fn code_to_str(code: c_int) -> &'static str {
super::SQLITE_FORMAT => "Auxiliary database format error",
super::SQLITE_RANGE => "2nd parameter to sqlite3_bind out of range",
super::SQLITE_NOTADB => "File opened that is not a database file",
SQLITE_NOTICE => "Notifications from sqlite3_log()",
SQLITE_WARNING => "Warnings from sqlite3_log()",
super::SQLITE_NOTICE => "Notifications from sqlite3_log()",
super::SQLITE_WARNING => "Warnings from sqlite3_log()",
super::SQLITE_ROW => "sqlite3_step() has another row ready",
super::SQLITE_DONE => "sqlite3_step() has finished executing",
@ -249,67 +204,67 @@ pub fn code_to_str(code: c_int) -> &'static str {
super::SQLITE_IOERR_LOCK => "I/O error in the advisory file locking layer",
super::SQLITE_IOERR_CLOSE => "I/O error within the xClose method",
super::SQLITE_IOERR_DIR_CLOSE => "SQLITE_IOERR_DIR_CLOSE", // no longer used
SQLITE_IOERR_SHMOPEN => "I/O error within the xShmMap method (trying to open a new shared-memory segment)",
SQLITE_IOERR_SHMSIZE => "I/O error within the xShmMap method (trying to resize an existing shared-memory segment)",
SQLITE_IOERR_SHMLOCK => "SQLITE_IOERR_SHMLOCK", // no longer used
SQLITE_IOERR_SHMMAP => "I/O error within the xShmMap method (trying to map a shared-memory segment into process address space)",
SQLITE_IOERR_SEEK => "I/O error within the xRead or xWrite (trying to seek within a file)",
SQLITE_IOERR_DELETE_NOENT => "File being deleted does not exist",
SQLITE_IOERR_MMAP => "I/O error while trying to map or unmap part of the database file into process address space",
SQLITE_IOERR_GETTEMPPATH => "VFS is unable to determine a suitable directory for temporary files",
SQLITE_IOERR_CONVPATH => "cygwin_conv_path() system call failed",
SQLITE_IOERR_VNODE => "SQLITE_IOERR_VNODE", // not documented?
SQLITE_IOERR_AUTH => "SQLITE_IOERR_AUTH",
super::SQLITE_IOERR_SHMOPEN => "I/O error within the xShmMap method (trying to open a new shared-memory segment)",
super::SQLITE_IOERR_SHMSIZE => "I/O error within the xShmMap method (trying to resize an existing shared-memory segment)",
super::SQLITE_IOERR_SHMLOCK => "SQLITE_IOERR_SHMLOCK", // no longer used
super::SQLITE_IOERR_SHMMAP => "I/O error within the xShmMap method (trying to map a shared-memory segment into process address space)",
super::SQLITE_IOERR_SEEK => "I/O error within the xRead or xWrite (trying to seek within a file)",
super::SQLITE_IOERR_DELETE_NOENT => "File being deleted does not exist",
super::SQLITE_IOERR_MMAP => "I/O error while trying to map or unmap part of the database file into process address space",
super::SQLITE_IOERR_GETTEMPPATH => "VFS is unable to determine a suitable directory for temporary files",
super::SQLITE_IOERR_CONVPATH => "cygwin_conv_path() system call failed",
super::SQLITE_IOERR_VNODE => "SQLITE_IOERR_VNODE", // not documented?
super::SQLITE_IOERR_AUTH => "SQLITE_IOERR_AUTH",
SQLITE_IOERR_BEGIN_ATOMIC => "SQLITE_IOERR_BEGIN_ATOMIC",
SQLITE_IOERR_COMMIT_ATOMIC => "SQLITE_IOERR_COMMIT_ATOMIC",
SQLITE_IOERR_ROLLBACK_ATOMIC => "SQLITE_IOERR_ROLLBACK_ATOMIC",
SQLITE_IOERR_DATA => "SQLITE_IOERR_DATA",
SQLITE_LOCKED_SHAREDCACHE => "Locking conflict due to another connection with a shared cache",
super::SQLITE_LOCKED_SHAREDCACHE => "Locking conflict due to another connection with a shared cache",
SQLITE_LOCKED_VTAB => "SQLITE_LOCKED_VTAB",
SQLITE_BUSY_RECOVERY => "Another process is recovering a WAL mode database file",
SQLITE_BUSY_SNAPSHOT => "Cannot promote read transaction to write transaction because of writes by another connection",
super::SQLITE_BUSY_RECOVERY => "Another process is recovering a WAL mode database file",
super::SQLITE_BUSY_SNAPSHOT => "Cannot promote read transaction to write transaction because of writes by another connection",
SQLITE_BUSY_TIMEOUT => "SQLITE_BUSY_TIMEOUT",
SQLITE_CANTOPEN_NOTEMPDIR => "SQLITE_CANTOPEN_NOTEMPDIR", // no longer used
SQLITE_CANTOPEN_ISDIR => "Attempted to open directory as file",
SQLITE_CANTOPEN_FULLPATH => "Unable to convert filename into full pathname",
SQLITE_CANTOPEN_CONVPATH => "cygwin_conv_path() system call failed",
super::SQLITE_CANTOPEN_NOTEMPDIR => "SQLITE_CANTOPEN_NOTEMPDIR", // no longer used
super::SQLITE_CANTOPEN_ISDIR => "Attempted to open directory as file",
super::SQLITE_CANTOPEN_FULLPATH => "Unable to convert filename into full pathname",
super::SQLITE_CANTOPEN_CONVPATH => "cygwin_conv_path() system call failed",
SQLITE_CANTOPEN_SYMLINK => "SQLITE_CANTOPEN_SYMLINK",
SQLITE_CORRUPT_VTAB => "Content in the virtual table is corrupt",
super::SQLITE_CORRUPT_VTAB => "Content in the virtual table is corrupt",
SQLITE_CORRUPT_SEQUENCE => "SQLITE_CORRUPT_SEQUENCE",
SQLITE_CORRUPT_INDEX => "SQLITE_CORRUPT_INDEX",
SQLITE_READONLY_RECOVERY => "WAL mode database file needs recovery (requires write access)",
SQLITE_READONLY_CANTLOCK => "Shared-memory file associated with WAL mode database is read-only",
SQLITE_READONLY_ROLLBACK => "Database has hot journal that must be rolled back (requires write access)",
SQLITE_READONLY_DBMOVED => "Database cannot be modified because database file has moved",
super::SQLITE_READONLY_RECOVERY => "WAL mode database file needs recovery (requires write access)",
super::SQLITE_READONLY_CANTLOCK => "Shared-memory file associated with WAL mode database is read-only",
super::SQLITE_READONLY_ROLLBACK => "Database has hot journal that must be rolled back (requires write access)",
super::SQLITE_READONLY_DBMOVED => "Database cannot be modified because database file has moved",
SQLITE_READONLY_CANTINIT => "SQLITE_READONLY_CANTINIT",
SQLITE_READONLY_DIRECTORY => "SQLITE_READONLY_DIRECTORY",
SQLITE_ABORT_ROLLBACK => "Transaction was rolled back",
super::SQLITE_ABORT_ROLLBACK => "Transaction was rolled back",
SQLITE_CONSTRAINT_CHECK => "A CHECK constraint failed",
SQLITE_CONSTRAINT_COMMITHOOK => "Commit hook caused rollback",
SQLITE_CONSTRAINT_FOREIGNKEY => "Foreign key constraint failed",
SQLITE_CONSTRAINT_FUNCTION => "Error returned from extension function",
SQLITE_CONSTRAINT_NOTNULL => "A NOT NULL constraint failed",
SQLITE_CONSTRAINT_PRIMARYKEY => "A PRIMARY KEY constraint failed",
SQLITE_CONSTRAINT_TRIGGER => "A RAISE function within a trigger fired",
SQLITE_CONSTRAINT_UNIQUE => "A UNIQUE constraint failed",
SQLITE_CONSTRAINT_VTAB => "An application-defined virtual table error occurred",
SQLITE_CONSTRAINT_ROWID => "A non-unique rowid occurred",
super::SQLITE_CONSTRAINT_CHECK => "A CHECK constraint failed",
super::SQLITE_CONSTRAINT_COMMITHOOK => "Commit hook caused rollback",
super::SQLITE_CONSTRAINT_FOREIGNKEY => "Foreign key constraint failed",
super::SQLITE_CONSTRAINT_FUNCTION => "Error returned from extension function",
super::SQLITE_CONSTRAINT_NOTNULL => "A NOT NULL constraint failed",
super::SQLITE_CONSTRAINT_PRIMARYKEY => "A PRIMARY KEY constraint failed",
super::SQLITE_CONSTRAINT_TRIGGER => "A RAISE function within a trigger fired",
super::SQLITE_CONSTRAINT_UNIQUE => "A UNIQUE constraint failed",
super::SQLITE_CONSTRAINT_VTAB => "An application-defined virtual table error occurred",
super::SQLITE_CONSTRAINT_ROWID => "A non-unique rowid occurred",
SQLITE_CONSTRAINT_PINNED => "SQLITE_CONSTRAINT_PINNED",
SQLITE_CONSTRAINT_DATATYPE => "SQLITE_CONSTRAINT_DATATYPE",
SQLITE_NOTICE_RECOVER_WAL => "A WAL mode database file was recovered",
SQLITE_NOTICE_RECOVER_ROLLBACK => "Hot journal was rolled back",
super::SQLITE_NOTICE_RECOVER_WAL => "A WAL mode database file was recovered",
super::SQLITE_NOTICE_RECOVER_ROLLBACK => "Hot journal was rolled back",
SQLITE_WARNING_AUTOINDEX => "Automatic indexing used - database might benefit from additional indexes",
super::SQLITE_WARNING_AUTOINDEX => "Automatic indexing used - database might benefit from additional indexes",
SQLITE_AUTH_USER => "SQLITE_AUTH_USER", // not documented?
super::SQLITE_AUTH_USER => "SQLITE_AUTH_USER", // not documented?
_ => "Unknown error code",
}

View File

@ -9,7 +9,7 @@ export SQLITE3_LIB_DIR="$SCRIPT_DIR/sqlite3"
export SQLITE3_INCLUDE_DIR="$SQLITE3_LIB_DIR"
# Download and extract amalgamation
SQLITE=sqlite-amalgamation-3380300
SQLITE=sqlite-amalgamation-3390400
curl -O https://sqlite.org/2022/$SQLITE.zip
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.c" > "$SQLITE3_LIB_DIR/sqlite3.c"
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.h" > "$SQLITE3_LIB_DIR/sqlite3.h"

View File

@ -8,7 +8,7 @@ mkdir -p "$SCRIPT_DIR/../target" "$SCRIPT_DIR/sqlcipher"
export SQLCIPHER_LIB_DIR="$SCRIPT_DIR/sqlcipher"
export SQLCIPHER_INCLUDE_DIR="$SQLCIPHER_LIB_DIR"
SQLCIPHER_VERSION="4.5.1"
SQLCIPHER_VERSION="4.5.2"
# Download and generate sqlcipher amalgamation
mkdir -p $SCRIPT_DIR/sqlcipher.src
[ -e "v${SQLCIPHER_VERSION}.tar.gz" ] || curl -sfL -O "https://github.com/sqlcipher/sqlcipher/archive/v${SQLCIPHER_VERSION}.tar.gz"

View File

@ -235,7 +235,7 @@ impl Connection {
table.as_ptr(),
column.as_ptr(),
row_id,
if read_only { 0 } else { 1 },
!read_only as std::os::raw::c_int,
&mut blob,
)
};
@ -473,14 +473,14 @@ mod test {
assert_eq!(&bytes, b"Clob5");
// should not be able to seek negative or past end
assert!(blob.seek(SeekFrom::Current(-20)).is_err());
assert!(blob.seek(SeekFrom::End(0)).is_ok());
assert!(blob.seek(SeekFrom::Current(1)).is_err());
blob.seek(SeekFrom::Current(-20)).unwrap_err();
blob.seek(SeekFrom::End(0)).unwrap();
blob.seek(SeekFrom::Current(1)).unwrap_err();
// write_all should detect when we return Ok(0) because there is no space left,
// and return a write error
blob.reopen(rowid)?;
assert!(blob.write_all(b"0123456789x").is_err());
blob.write_all(b"0123456789x").unwrap_err();
Ok(())
}
@ -519,7 +519,7 @@ mod test {
// trying to write too much and then flush should fail
assert_eq!(8, writer.write(b"01234567").unwrap());
assert_eq!(8, writer.write(b"01234567").unwrap());
assert!(writer.flush().is_err());
writer.flush().unwrap_err();
}
{
@ -536,7 +536,7 @@ mod test {
// trying to write_all too much should fail
writer.write_all(b"aaaaaaaaaabbbbb").unwrap();
assert!(writer.flush().is_err());
writer.flush().unwrap_err();
}
{

View File

@ -214,7 +214,7 @@ mod test {
let mut s = [0u8; 10];
blob.read_at_exact(&mut s, 0).unwrap();
assert_eq!(&s, &one2ten, "write should go through");
assert!(blob.read_at_exact(&mut s, 1).is_err());
blob.read_at_exact(&mut s, 1).unwrap_err();
blob.read_at_exact(&mut s, 0).unwrap();
assert_eq!(&s, &one2ten, "should be unchanged");
@ -225,13 +225,13 @@ mod test {
blob.read_at_exact(&mut fives, 5).unwrap();
assert_eq!(&fives, &[6u8, 7, 8, 9, 10]);
assert!(blob.read_at_exact(&mut fives, 7).is_err());
assert!(blob.read_at_exact(&mut fives, 12).is_err());
assert!(blob.read_at_exact(&mut fives, 10).is_err());
assert!(blob.read_at_exact(&mut fives, i32::MAX as usize).is_err());
assert!(blob
.read_at_exact(&mut fives, i32::MAX as usize + 1)
.is_err());
blob.read_at_exact(&mut fives, 7).unwrap_err();
blob.read_at_exact(&mut fives, 12).unwrap_err();
blob.read_at_exact(&mut fives, 10).unwrap_err();
blob.read_at_exact(&mut fives, i32::MAX as usize)
.unwrap_err();
blob.read_at_exact(&mut fives, i32::MAX as usize + 1)
.unwrap_err();
// zero length writes are fine if in bounds
blob.read_at_exact(&mut [], 10).unwrap();
@ -242,13 +242,11 @@ mod test {
blob.read_at_exact(&mut s, 0).unwrap();
assert_eq!(&s, &[1u8, 2, 3, 4, 5, 16, 17, 18, 19, 20]);
assert!(blob.write_at(&[100, 99, 98, 97, 96], 6).is_err());
assert!(blob
.write_at(&[100, 99, 98, 97, 96], i32::MAX as usize)
.is_err());
assert!(blob
.write_at(&[100, 99, 98, 97, 96], i32::MAX as usize + 1)
.is_err());
blob.write_at(&[100, 99, 98, 97, 96], 6).unwrap_err();
blob.write_at(&[100, 99, 98, 97, 96], i32::MAX as usize)
.unwrap_err();
blob.write_at(&[100, 99, 98, 97, 96], i32::MAX as usize + 1)
.unwrap_err();
blob.read_at_exact(&mut s, 0).unwrap();
assert_eq!(&s, &[1u8, 2, 3, 4, 5, 16, 17, 18, 19, 20]);
@ -265,7 +263,7 @@ mod test {
blob.raw_read_at_exact(&mut empty, 0).unwrap().as_ptr(),
empty.as_ptr().cast(),
));
assert!(blob.raw_read_at_exact(&mut s2, 5).is_err());
blob.raw_read_at_exact(&mut s2, 5).unwrap_err();
let end_pos = blob.seek(std::io::SeekFrom::Current(0)).unwrap();
assert_eq!(end_pos, 1);

View File

@ -58,11 +58,7 @@ impl Connection {
pub fn busy_handler(&self, callback: Option<fn(i32) -> bool>) -> Result<()> {
unsafe extern "C" fn busy_handler_callback(p_arg: *mut c_void, count: c_int) -> c_int {
let handler_fn: fn(i32) -> bool = mem::transmute(p_arg);
if let Ok(true) = catch_unwind(|| handler_fn(count)) {
1
} else {
0
}
c_int::from(catch_unwind(|| handler_fn(count)).unwrap_or_default())
}
let c = self.db.borrow_mut();
let r = match callback {

View File

@ -33,7 +33,7 @@ impl Statement<'_> {
/// calling this method.
pub fn column_names(&self) -> Vec<&str> {
let n = self.column_count();
let mut cols = Vec::with_capacity(n as usize);
let mut cols = Vec::with_capacity(n);
for i in 0..n {
let s = self.column_name_unwrap(i);
cols.push(s);
@ -95,6 +95,7 @@ impl Statement<'_> {
pub fn column_name(&self, col: usize) -> Result<&str> {
self.stmt
.column_name(col)
// clippy::or_fun_call (nightly) vs clippy::unnecessary-lazy-evaluations (stable)
.ok_or(Error::InvalidColumnIndex(col))
.map(|slice| {
str::from_utf8(slice.to_bytes()).expect("Invalid UTF-8 sequence in column name")
@ -137,7 +138,7 @@ impl Statement<'_> {
#[cfg_attr(docsrs, doc(cfg(feature = "column_decltype")))]
pub fn columns(&self) -> Vec<Column> {
let n = self.column_count();
let mut cols = Vec::with_capacity(n as usize);
let mut cols = Vec::with_capacity(n);
for i in 0..n {
let name = self.column_name_unwrap(i);
let slice = self.stmt.column_decltype(i);

View File

@ -16,12 +16,12 @@ pub enum DbConfig {
//SQLITE_DBCONFIG_MAINDBNAME = 1000, /* const char* */
//SQLITE_DBCONFIG_LOOKASIDE = 1001, /* void* int int */
/// Enable or disable the enforcement of foreign key constraints.
SQLITE_DBCONFIG_ENABLE_FKEY = 1002,
SQLITE_DBCONFIG_ENABLE_FKEY = ffi::SQLITE_DBCONFIG_ENABLE_FKEY,
/// Enable or disable triggers.
SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003,
SQLITE_DBCONFIG_ENABLE_TRIGGER = ffi::SQLITE_DBCONFIG_ENABLE_TRIGGER,
/// Enable or disable the fts3_tokenizer() function which is part of the
/// FTS3 full-text search engine extension.
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004, // 3.12.0
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, // 3.12.0
//SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005,
/// In WAL mode, enable or disable the checkpoint operation before closing
/// the connection.
@ -115,7 +115,7 @@ impl Connection {
check(ffi::sqlite3_db_config(
c.db(),
config as c_int,
if new_val { 1 } else { 0 },
new_val as c_int,
&mut val,
))?;
Ok(val != 0)

View File

@ -43,7 +43,7 @@ pub(super) unsafe fn set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<
ValueRef::Real(r) => ffi::sqlite3_result_double(ctx, r),
ValueRef::Text(s) => {
let length = s.len();
if length > c_int::max_value() as usize {
if length > c_int::MAX as usize {
ffi::sqlite3_result_error_toobig(ctx);
} else {
let (c_str, len, destructor) = match str_for_sqlite(s) {
@ -57,7 +57,7 @@ pub(super) unsafe fn set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<
}
ValueRef::Blob(b) => {
let length = b.len();
if length > c_int::max_value() as usize {
if length > c_int::MAX as usize {
ffi::sqlite3_result_error_toobig(ctx);
} else if length == 0 {
ffi::sqlite3_result_zeroblob(ctx, 0);

View File

@ -34,7 +34,7 @@ pub enum Error {
/// Error converting a string to a C-compatible string because it contained
/// an embedded nul.
NulError(::std::ffi::NulError),
NulError(std::ffi::NulError),
/// Error when using SQL named parameters and passing a parameter name not
/// present in the SQL.
@ -212,14 +212,14 @@ impl From<str::Utf8Error> for Error {
}
}
impl From<::std::ffi::NulError> for Error {
impl From<std::ffi::NulError> for Error {
#[cold]
fn from(err: ::std::ffi::NulError) -> Error {
fn from(err: std::ffi::NulError) -> Error {
Error::NulError(err)
}
}
const UNKNOWN_COLUMN: usize = std::usize::MAX;
const UNKNOWN_COLUMN: usize = usize::MAX;
/// The conversion isn't precise, but it's convenient to have it
/// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
@ -245,7 +245,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Error::SqliteFailure(ref err, None) => err.fmt(f),
Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
Error::SqliteFailure(_, Some(ref s)) => write!(f, "{s}"),
Error::SqliteSingleThreadedMode => write!(
f,
"SQLite was compiled or configured for single-threaded use only"
@ -263,21 +263,21 @@ impl fmt::Display for Error {
}
Error::IntegralValueOutOfRange(col, val) => {
if col != UNKNOWN_COLUMN {
write!(f, "Integer {} out of range at index {}", val, col)
write!(f, "Integer {val} out of range at index {col}")
} else {
write!(f, "Integer {} out of range", val)
write!(f, "Integer {val} out of range")
}
}
Error::Utf8Error(ref err) => err.fmt(f),
Error::NulError(ref err) => err.fmt(f),
Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {name}"),
Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
Error::ExecuteReturnedResults => {
write!(f, "Execute returned results - did you mean to call query?")
}
Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"),
Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"),
Error::InvalidColumnType(i, ref name, ref t) => write!(
f,
"Invalid column type {} at index: {}, name: {}",
@ -288,22 +288,22 @@ impl fmt::Display for Error {
"Wrong number of parameters passed to query. Got {}, needed {}",
i1, n1
),
Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
Error::StatementChangedRows(i) => write!(f, "Query changed {i} rows"),
#[cfg(feature = "functions")]
Error::InvalidFunctionParameterType(i, ref t) => {
write!(f, "Invalid function parameter type {} at index {}", t, i)
write!(f, "Invalid function parameter type {t} at index {i}")
}
#[cfg(feature = "vtab")]
Error::InvalidFilterParameterType(i, ref t) => {
write!(f, "Invalid filter parameter type {} at index {}", t, i)
write!(f, "Invalid filter parameter type {t} at index {i}")
}
#[cfg(feature = "functions")]
Error::UserFunctionError(ref err) => err.fmt(f),
Error::ToSqlConversionFailure(ref err) => err.fmt(f),
Error::InvalidQuery => write!(f, "Query is not read-only"),
#[cfg(feature = "vtab")]
Error::ModuleError(ref desc) => write!(f, "{}", desc),
Error::ModuleError(ref desc) => write!(f, "{desc}"),
#[cfg(feature = "functions")]
Error::UnwindingPanic => write!(f, "unwinding panic"),
#[cfg(feature = "functions")]
@ -317,7 +317,7 @@ impl fmt::Display for Error {
offset,
ref sql,
..
} => write!(f, "{} in {} at offset {}", msg, sql, offset),
} => write!(f, "{msg} in {sql} at offset {offset}"),
}
}
}
@ -408,13 +408,13 @@ pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
}
#[cold]
#[cfg(not(all(feature = "modern_sqlite", not(feature = "bundled-sqlcipher"))))] // SQLite >= 3.38.0
#[cfg(not(feature = "modern_sqlite"))] // SQLite >= 3.38.0
pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, _sql: &str) -> Error {
error_from_handle(db, code)
}
#[cold]
#[cfg(all(feature = "modern_sqlite", not(feature = "bundled-sqlcipher")))] // SQLite >= 3.38.0
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error {
if db.is_null() {
error_from_sqlite_code(code, None)
@ -438,7 +438,7 @@ pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -
pub fn check(code: c_int) -> Result<()> {
if code != crate::ffi::SQLITE_OK {
Err(crate::error::error_from_sqlite_code(code, None))
Err(error_from_sqlite_code(code, None))
} else {
Ok(())
}

View File

@ -75,14 +75,9 @@ unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) {
// an explicit feature check for that, and this doesn't really warrant one.
// We'll use the extended code if we're on the bundled version (since it's
// at least 3.17.0) and the normal constraint error code if not.
#[cfg(feature = "modern_sqlite")]
fn constraint_error_code() -> i32 {
ffi::SQLITE_CONSTRAINT_FUNCTION
}
#[cfg(not(feature = "modern_sqlite"))]
fn constraint_error_code() -> i32 {
ffi::SQLITE_CONSTRAINT
}
if let Error::SqliteFailure(ref err, ref s) = *err {
ffi::sqlite3_result_error_code(ctx, err.extended_code);
@ -168,8 +163,6 @@ impl Context<'_> {
///
/// Will panic if `idx` is greater than or equal to
/// [`self.len()`](Context::len).
#[cfg(feature = "modern_sqlite")] // 3.9.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn get_subtype(&self, idx: usize) -> std::os::raw::c_uint {
let arg = self.args[idx];
unsafe { ffi::sqlite3_value_subtype(arg) }
@ -639,7 +632,7 @@ unsafe extern "C" fn call_boxed_step<A, D, T>(
D: Aggregate<A, T>,
T: ToSql,
{
let pac = if let Some(pac) = aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
let pac = if let Some(pac) = aggregate_context(ctx, std::mem::size_of::<*mut A>()) {
pac
} else {
ffi::sqlite3_result_error_nomem(ctx);
@ -686,7 +679,7 @@ unsafe extern "C" fn call_boxed_inverse<A, W, T>(
W: WindowAggregate<A, T>,
T: ToSql,
{
let pac = if let Some(pac) = aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
let pac = if let Some(pac) = aggregate_context(ctx, std::mem::size_of::<*mut A>()) {
pac
} else {
ffi::sqlite3_result_error_nomem(ctx);
@ -821,7 +814,6 @@ where
#[cfg(test)]
mod test {
use regex::Regex;
use std::f64::EPSILON;
use std::os::raw::c_double;
#[cfg(feature = "window")]
@ -846,7 +838,7 @@ mod test {
)?;
let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0));
assert!((3f64 - result?).abs() < EPSILON);
assert!((3f64 - result?).abs() < f64::EPSILON);
Ok(())
}
@ -860,11 +852,11 @@ mod test {
half,
)?;
let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0));
assert!((3f64 - result?).abs() < EPSILON);
assert!((3f64 - result?).abs() < f64::EPSILON);
db.remove_function("half", 1)?;
let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0));
assert!(result.is_err());
result.unwrap_err();
Ok(())
}

View File

@ -10,7 +10,7 @@ use crate::ffi;
use crate::{Connection, InnerConnection};
/// Action Codes
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(i32)]
#[non_exhaustive]
#[allow(clippy::upper_case_acronyms)]
@ -37,10 +37,10 @@ impl From<i32> for Action {
}
}
/// The context recieved by an authorizer hook.
/// The context received by an authorizer hook.
///
/// See <https://sqlite.org/c3ref/set_authorizer.html> for more info.
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AuthContext<'c> {
/// The action to be authorized.
pub action: AuthAction<'c>,
@ -57,7 +57,7 @@ pub struct AuthContext<'c> {
/// preparation.
///
/// See <https://sqlite.org/c3ref/c_alter_table.html> for more info.
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum AuthAction<'c> {
@ -181,7 +181,6 @@ pub enum AuthAction<'c> {
operation: TransactionOperation,
savepoint_name: &'c str,
},
#[cfg(feature = "modern_sqlite")]
Recursive,
}
@ -285,7 +284,6 @@ impl<'c> AuthAction<'c> {
operation: TransactionOperation::from_str(operation_str),
savepoint_name,
},
#[cfg(feature = "modern_sqlite")] // 3.8.3
(ffi::SQLITE_RECURSIVE, ..) => Self::Recursive,
(code, arg1, arg2) => Self::Unknown { code, arg1, arg2 },
}
@ -296,7 +294,7 @@ pub(crate) type BoxedAuthorizer =
Box<dyn for<'c> FnMut(AuthContext<'c>) -> Authorization + Send + 'static>;
/// A transaction operation.
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum TransactionOperation {
@ -318,7 +316,7 @@ impl TransactionOperation {
}
/// [`authorizer`](Connection::authorizer) return code
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Authorization {
/// Authorize the action.
@ -428,11 +426,7 @@ impl InnerConnection {
let boxed_hook: *mut F = p_arg.cast::<F>();
(*boxed_hook)()
});
if let Ok(true) = r {
1
} else {
0
}
c_int::from(r.unwrap_or_default())
}
// unlike `sqlite3_create_function_v2`, we cannot specify a `xDestroy` with
@ -570,11 +564,7 @@ impl InnerConnection {
let boxed_handler: *mut F = p_arg.cast::<F>();
(*boxed_handler)()
});
if let Ok(true) = r {
1
} else {
0
}
c_int::from(r.unwrap_or_default())
}
if let Some(handler) = handler {

View File

@ -25,11 +25,11 @@ pub struct InnerConnection {
// interrupt would only acquire the lock after the query's completion.
interrupt_lock: Arc<Mutex<*mut ffi::sqlite3>>,
#[cfg(feature = "hooks")]
pub free_commit_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>,
pub free_commit_hook: Option<unsafe fn(*mut std::os::raw::c_void)>,
#[cfg(feature = "hooks")]
pub free_rollback_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>,
pub free_rollback_hook: Option<unsafe fn(*mut std::os::raw::c_void)>,
#[cfg(feature = "hooks")]
pub free_update_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>,
pub free_update_hook: Option<unsafe fn(*mut std::os::raw::c_void)>,
#[cfg(feature = "hooks")]
pub progress_handler: Option<Box<dyn FnMut() -> bool + Send>>,
#[cfg(feature = "hooks")]
@ -105,7 +105,7 @@ impl InnerConnection {
{
e = Error::SqliteFailure(
ffi::Error::new(r),
Some(format!("{}: {}", msg, c_path.to_string_lossy())),
Some(format!("{msg}: {}", c_path.to_string_lossy())),
);
}
ffi::sqlite3_close(db);
@ -208,7 +208,7 @@ impl InnerConnection {
Ok(())
} else {
let message = super::errmsg_to_string(errmsg);
ffi::sqlite3_free(errmsg.cast::<::std::os::raw::c_void>());
ffi::sqlite3_free(errmsg.cast::<std::os::raw::c_void>());
Err(error_from_sqlite_code(r, Some(message)))
}
}
@ -295,7 +295,6 @@ impl InnerConnection {
unsafe { ffi::sqlite3_get_autocommit(self.db()) != 0 }
}
#[cfg(feature = "modern_sqlite")] // 3.8.6
pub fn is_busy(&self) -> bool {
let db = self.db();
unsafe {
@ -310,7 +309,6 @@ impl InnerConnection {
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()) })
}
@ -319,7 +317,6 @@ impl InnerConnection {
#[inline]
fn remove_hooks(&mut self) {}
#[cfg(feature = "modern_sqlite")] // 3.7.11
pub fn db_readonly(&self, db_name: super::DatabaseName<'_>) -> Result<bool> {
let name = db_name.as_cstring()?;
let r = unsafe { ffi::sqlite3_db_readonly(self.db, name.as_ptr()) };
@ -328,7 +325,7 @@ impl InnerConnection {
1 => Ok(true),
-1 => Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("{:?} is not the name of a database", db_name)),
Some(format!("{db_name:?} is not the name of a database")),
)),
_ => Err(error_from_sqlite_code(
r,
@ -354,7 +351,7 @@ impl InnerConnection {
2 => Ok(super::transaction::TransactionState::Write),
-1 => Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("{:?} is not the name of a valid schema", db_name)),
Some(format!("{db_name:?} is not the name of a valid schema")),
)),
_ => Err(error_from_sqlite_code(
r,
@ -378,7 +375,7 @@ impl Drop for InnerConnection {
if let Err(e) = self.close() {
if panicking() {
eprintln!("Error while closing SQLite connection: {:?}", e);
eprintln!("Error while closing SQLite connection: {e:?}");
} else {
panic!("Error while closing SQLite connection: {:?}", e);
}
@ -400,7 +397,7 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> {
#[cfg(not(any(target_arch = "wasm32")))]
fn ensure_safe_sqlite_threading_mode() -> Result<()> {
// Ensure SQLite was compiled in thredsafe mode.
// Ensure SQLite was compiled in threadsafe mode.
if unsafe { ffi::sqlite3_threadsafe() == 0 } {
return Err(Error::SqliteSingleThreadedMode);
}

View File

@ -57,7 +57,6 @@
pub use libsqlite3_sys as ffi;
use std::cell::RefCell;
use std::convert;
use std::default::Default;
use std::ffi::{CStr, CString};
use std::fmt;
@ -272,7 +271,7 @@ fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destru
// Helper to cast to c_int safely, returning the correct error type if the cast
// failed.
fn len_as_c_int(len: usize) -> Result<c_int> {
if len >= (c_int::max_value() as usize) {
if len >= (c_int::MAX as usize) {
Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_TOOBIG),
None,
@ -315,15 +314,9 @@ pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
// Currently DatabaseName is only used by the backup and blob mods, so hide
// this (private) impl to avoid dead code warnings.
#[cfg(any(
feature = "backup",
feature = "blob",
feature = "session",
feature = "modern_sqlite"
))]
impl DatabaseName<'_> {
#[inline]
fn as_cstring(&self) -> Result<util::SmallCString> {
fn as_cstring(&self) -> Result<SmallCString> {
use self::DatabaseName::{Attached, Main, Temp};
match *self {
Main => str_to_cstring("main"),
@ -724,7 +717,7 @@ impl Connection {
where
P: Params,
F: FnOnce(&Row<'_>) -> Result<T, E>,
E: convert::From<Error>,
E: From<Error>,
{
let mut stmt = self.prepare(sql)?;
stmt.check_no_tail()?;
@ -962,22 +955,16 @@ impl Connection {
/// Determine if all associated prepared statements have been reset.
#[inline]
#[cfg(feature = "modern_sqlite")] // 3.8.6
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn is_busy(&self) -> bool {
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()
}
/// Determine if a database is read-only
#[cfg(feature = "modern_sqlite")] // 3.7.11
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> {
self.db.borrow().db_readonly(db_name)
}
@ -1071,9 +1058,9 @@ bitflags::bitflags! {
/// The database is created if it does not already exist
const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
/// The filename can be interpreted as a URI if this flag is set.
const SQLITE_OPEN_URI = 0x0000_0040;
const SQLITE_OPEN_URI = ffi::SQLITE_OPEN_URI;
/// The database will be opened as an in-memory database.
const SQLITE_OPEN_MEMORY = 0x0000_0080;
const SQLITE_OPEN_MEMORY = ffi::SQLITE_OPEN_MEMORY;
/// The new database connection will not use a per-connection mutex (the
/// connection will use the "multi-thread" threading mode, in SQLite
/// parlance).
@ -1177,7 +1164,6 @@ impl InterruptHandle {
}
}
#[cfg(feature = "modern_sqlite")] // 3.7.10
unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option<PathBuf> {
let db_name = DatabaseName::Main.as_cstring().unwrap();
let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
@ -1187,10 +1173,6 @@ unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option<PathBuf> {
CStr::from_ptr(db_filename).to_str().ok().map(PathBuf::from)
}
}
#[cfg(not(feature = "modern_sqlite"))]
unsafe fn db_filename(_: *mut ffi::sqlite3) -> Option<PathBuf> {
None
}
#[cfg(doctest)]
doc_comment::doctest!("../README.md");
@ -1278,7 +1260,7 @@ mod test {
}
let path_string = path.to_str().unwrap();
let db = Connection::open(&path_string)?;
let db = Connection::open(path_string)?;
let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
assert_eq!(42i64, the_answer?);
@ -1287,17 +1269,16 @@ mod test {
#[test]
fn test_open() {
assert!(Connection::open_in_memory().is_ok());
Connection::open_in_memory().unwrap();
let db = checked_memory_handle();
assert!(db.close().is_ok());
db.close().unwrap();
}
#[test]
fn test_open_failure() {
let filename = "no_such_file.db";
let result = Connection::open_with_flags(filename, OpenFlags::SQLITE_OPEN_READ_ONLY);
assert!(result.is_err());
let err = result.unwrap_err();
if let Error::SqliteFailure(e, Some(msg)) = err {
assert_eq!(ErrorCode::CannotOpen, e.code);
@ -1392,7 +1373,7 @@ mod test {
OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE,
] {
assert!(Connection::open_in_memory_with_flags(*bad_flags).is_err());
Connection::open_in_memory_with_flags(*bad_flags).unwrap_err();
}
}
@ -1410,7 +1391,7 @@ mod test {
db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
assert!(db.execute_batch("INVALID SQL").is_err());
db.execute_batch("INVALID SQL").unwrap_err();
Ok(())
}
@ -1434,8 +1415,9 @@ mod test {
fn test_execute_select() {
let db = checked_memory_handle();
let err = db.execute("SELECT 1 WHERE 1 < ?", [1i32]).unwrap_err();
assert!(
err == Error::ExecuteReturnedResults,
assert_eq!(
err,
Error::ExecuteReturnedResults,
"Unexpected error: {}",
err
);
@ -1572,7 +1554,7 @@ mod test {
let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
assert!(bad_query_result.is_err());
bad_query_result.unwrap_err();
Ok(())
}
@ -1596,7 +1578,7 @@ mod test {
let bad_query_result: Result<i64> = db.query_row("NOT A PROPER QUERY", [], |r| r.get(0));
let bad_query_result = bad_query_result.optional();
assert!(bad_query_result.is_err());
bad_query_result.unwrap_err();
Ok(())
}
@ -1634,7 +1616,7 @@ mod test {
db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
assert!(format!("{}", err).contains("does_not_exist"));
assert!(format!("{err}").contains("does_not_exist"));
Ok(())
}
@ -1665,7 +1647,6 @@ mod test {
}
#[test]
#[cfg(feature = "modern_sqlite")]
fn test_is_busy() -> Result<()> {
let db = Connection::open_in_memory()?;
assert!(!db.is_busy());
@ -1688,7 +1669,7 @@ mod test {
let query = "SELECT 12345";
let stmt = db.prepare(query)?;
assert!(format!("{:?}", stmt).contains(query));
assert!(format!("{stmt:?}").contains(query));
Ok(())
}
@ -1696,18 +1677,14 @@ mod test {
fn test_notnull_constraint_error() -> Result<()> {
// extended error codes for constraints were added in SQLite 3.7.16; if we're
// running on our bundled version, we know the extended error code exists.
#[cfg(feature = "modern_sqlite")]
fn check_extended_code(extended_code: c_int) {
assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
}
#[cfg(not(feature = "modern_sqlite"))]
fn check_extended_code(_extended_code: c_int) {}
let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
assert!(result.is_err());
match result.unwrap_err() {
Error::SqliteFailure(err, _) => {
@ -1726,7 +1703,7 @@ mod test {
let minor = (n % 1_000_000) / 1_000;
let patch = n % 1_000;
assert!(version().contains(&format!("{}.{}.{}", major, minor, patch)));
assert!(version().contains(&format!("{major}.{minor}.{patch}")));
}
#[test]
@ -1739,7 +1716,7 @@ mod test {
db.create_scalar_function(
"interrupt",
0,
crate::functions::FunctionFlags::default(),
functions::FunctionFlags::default(),
move |_| {
interrupt_handle.interrupt();
Ok((0, None))
@ -1833,7 +1810,7 @@ mod test {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match *self {
CustomError::SomeError => write!(f, "my custom error"),
CustomError::Sqlite(ref se) => write!(f, "my custom error: {}", se),
CustomError::Sqlite(ref se) => write!(f, "my custom error: {se}"),
}
}
}
@ -2111,17 +2088,15 @@ mod test {
}
#[test]
#[cfg(feature = "modern_sqlite")]
fn test_cache_flush() -> Result<()> {
let db = Connection::open_in_memory()?;
db.cache_flush()
}
#[test]
#[cfg(feature = "modern_sqlite")]
pub fn db_readonly() -> Result<()> {
let db = Connection::open_in_memory()?;
assert!(!db.is_readonly(super::MAIN_DB)?);
assert!(!db.is_readonly(MAIN_DB)?);
Ok(())
}
}

View File

@ -39,10 +39,10 @@ pub enum Limit {
/// The maximum index number of any parameter in an SQL statement.
SQLITE_LIMIT_VARIABLE_NUMBER = ffi::SQLITE_LIMIT_VARIABLE_NUMBER,
/// The maximum depth of recursion for triggers.
SQLITE_LIMIT_TRIGGER_DEPTH = 10,
SQLITE_LIMIT_TRIGGER_DEPTH = ffi::SQLITE_LIMIT_TRIGGER_DEPTH,
/// The maximum number of auxiliary worker threads that a single prepared
/// statement may start.
SQLITE_LIMIT_WORKER_THREADS = 11,
SQLITE_LIMIT_WORKER_THREADS = ffi::SQLITE_LIMIT_WORKER_THREADS,
}
impl Connection {
@ -71,55 +71,49 @@ mod test {
#[test]
fn test_limit_values() {
assert_eq!(
Limit::SQLITE_LIMIT_LENGTH as i32,
ffi::SQLITE_LIMIT_LENGTH as i32,
);
assert_eq!(Limit::SQLITE_LIMIT_LENGTH as i32, ffi::SQLITE_LIMIT_LENGTH,);
assert_eq!(
Limit::SQLITE_LIMIT_SQL_LENGTH as i32,
ffi::SQLITE_LIMIT_SQL_LENGTH as i32,
);
assert_eq!(
Limit::SQLITE_LIMIT_COLUMN as i32,
ffi::SQLITE_LIMIT_COLUMN as i32,
ffi::SQLITE_LIMIT_SQL_LENGTH,
);
assert_eq!(Limit::SQLITE_LIMIT_COLUMN as i32, ffi::SQLITE_LIMIT_COLUMN,);
assert_eq!(
Limit::SQLITE_LIMIT_EXPR_DEPTH as i32,
ffi::SQLITE_LIMIT_EXPR_DEPTH as i32,
ffi::SQLITE_LIMIT_EXPR_DEPTH,
);
assert_eq!(
Limit::SQLITE_LIMIT_COMPOUND_SELECT as i32,
ffi::SQLITE_LIMIT_COMPOUND_SELECT as i32,
ffi::SQLITE_LIMIT_COMPOUND_SELECT,
);
assert_eq!(
Limit::SQLITE_LIMIT_VDBE_OP as i32,
ffi::SQLITE_LIMIT_VDBE_OP as i32,
ffi::SQLITE_LIMIT_VDBE_OP,
);
assert_eq!(
Limit::SQLITE_LIMIT_FUNCTION_ARG as i32,
ffi::SQLITE_LIMIT_FUNCTION_ARG as i32,
ffi::SQLITE_LIMIT_FUNCTION_ARG,
);
assert_eq!(
Limit::SQLITE_LIMIT_ATTACHED as i32,
ffi::SQLITE_LIMIT_ATTACHED as i32,
ffi::SQLITE_LIMIT_ATTACHED,
);
assert_eq!(
Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH as i32,
ffi::SQLITE_LIMIT_LIKE_PATTERN_LENGTH as i32,
ffi::SQLITE_LIMIT_LIKE_PATTERN_LENGTH,
);
assert_eq!(
Limit::SQLITE_LIMIT_VARIABLE_NUMBER as i32,
ffi::SQLITE_LIMIT_VARIABLE_NUMBER as i32,
ffi::SQLITE_LIMIT_VARIABLE_NUMBER,
);
#[cfg(feature = "bundled")]
assert_eq!(
Limit::SQLITE_LIMIT_TRIGGER_DEPTH as i32,
ffi::SQLITE_LIMIT_TRIGGER_DEPTH as i32,
ffi::SQLITE_LIMIT_TRIGGER_DEPTH,
);
#[cfg(feature = "bundled")]
assert_eq!(
Limit::SQLITE_LIMIT_WORKER_THREADS as i32,
ffi::SQLITE_LIMIT_WORKER_THREADS as i32,
ffi::SQLITE_LIMIT_WORKER_THREADS,
);
}

View File

@ -41,7 +41,7 @@ use sealed::Sealed;
/// - Using the [`rusqlite::params!`](crate::params!) macro, e.g.
/// `thing.query(rusqlite::params![1, "foo", bar])`. This is mostly useful for
/// heterogeneous lists where the number of parameters greater than 16, or
/// homogenous lists of paramters where the number of parameters exceeds 32.
/// homogenous lists of parameters where the number of parameters exceeds 32.
///
/// - For small homogeneous lists of parameters, they can either be passed as:
///

View File

@ -37,7 +37,7 @@ impl Sql {
} else {
Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Invalid keyword \"{}\"", keyword)),
Some(format!("Invalid keyword \"{keyword}\"")),
))
}
}
@ -67,14 +67,14 @@ impl Sql {
ToSqlOutput::ZeroBlob(_) => {
return Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{:?}\"", value)),
Some(format!("Unsupported value \"{value:?}\"")),
));
}
#[cfg(feature = "array")]
ToSqlOutput::Array(_) => {
return Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{:?}\"", value)),
Some(format!("Unsupported value \"{value:?}\"")),
));
}
};
@ -92,7 +92,7 @@ impl Sql {
_ => {
return Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{:?}\"", value)),
Some(format!("Unsupported value \"{value:?}\"")),
));
}
};
@ -369,7 +369,7 @@ mod test {
fn pragma() -> Result<()> {
let db = Connection::open_in_memory()?;
let mut columns = Vec::new();
db.pragma(None, "table_info", &"sqlite_master", |row| {
db.pragma(None, "table_info", "sqlite_master", |row| {
let column: String = row.get(1)?;
columns.push(column);
Ok(())
@ -412,8 +412,8 @@ mod test {
journal_mode,
);
// Sanity checks to ensure the move to a generic `ToSql` wasn't breaking
let mode = db
.pragma_update_and_check(None, "journal_mode", &"OFF", |row| row.get::<_, String>(0))?;
let mode =
db.pragma_update_and_check(None, "journal_mode", "OFF", |row| row.get::<_, String>(0))?;
assert!(mode == "off" || mode == "memory", "mode: {:?}", mode);
let param: &dyn crate::ToSql = &"OFF";
@ -448,7 +448,7 @@ mod test {
#[test]
fn locking_mode() -> Result<()> {
let db = Connection::open_in_memory()?;
let r = db.pragma_update(None, "locking_mode", &"exclusive");
let r = db.pragma_update(None, "locking_mode", "exclusive");
if cfg!(feature = "extra_check") {
r.unwrap_err();
} else {

View File

@ -1,7 +1,6 @@
use super::ffi;
use super::StatementStatus;
use crate::util::ParamIndexCache;
#[cfg(feature = "modern_sqlite")]
use crate::util::SqliteMallocString;
use std::ffi::CStr;
use std::os::raw::c_int;
@ -110,7 +109,7 @@ impl RawStatement {
#[cfg(feature = "unlock_notify")]
pub fn step(&self) -> c_int {
use crate::unlock_notify;
let mut db = core::ptr::null_mut::<ffi::sqlite3>();
let mut db = ptr::null_mut::<ffi::sqlite3>();
loop {
unsafe {
let mut rc = ffi::sqlite3_step(self.ptr);
@ -196,14 +195,13 @@ impl RawStatement {
}
// does not work for PRAGMA
#[cfg(feature = "extra_check")]
#[inline]
#[cfg(all(feature = "extra_check", feature = "modern_sqlite"))] // 3.7.4
pub fn readonly(&self) -> bool {
unsafe { ffi::sqlite3_stmt_readonly(self.ptr) != 0 }
}
#[inline]
#[cfg(feature = "modern_sqlite")] // 3.14.0
pub(crate) fn expanded_sql(&self) -> Option<SqliteMallocString> {
unsafe { SqliteMallocString::from_raw(ffi::sqlite3_expanded_sql(self.ptr)) }
}

View File

@ -171,7 +171,7 @@ pub struct AndThenRows<'stmt, F> {
impl<T, E, F> Iterator for AndThenRows<'_, F>
where
E: convert::From<Error>,
E: From<Error>,
F: FnMut(&Row<'_>) -> Result<T, E>,
{
type Item = Result<T, E>;
@ -391,7 +391,7 @@ impl RowIndex for usize {
impl RowIndex for &'_ str {
#[inline]
fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
stmt.column_index(*self)
stmt.column_index(self)
}
}
@ -448,7 +448,7 @@ mod tests {
let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
assert_eq!(val, (42,));
let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
assert!(fail.is_err());
fail.unwrap_err();
Ok(())
}
@ -466,7 +466,7 @@ mod tests {
let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
<(u32, u32, u32)>::try_from(row)
});
assert!(fail.is_err());
fail.unwrap_err();
Ok(())
}

View File

@ -19,12 +19,14 @@ use crate::{errmsg_to_string, str_to_cstring, Connection, DatabaseName, Result};
// https://sqlite.org/session.html
type Filter = Option<Box<dyn Fn(&str) -> bool>>;
/// An instance of this object is a session that can be
/// used to record changes to a database.
pub struct Session<'conn> {
phantom: PhantomData<&'conn Connection>,
s: *mut ffi::sqlite3_session,
filter: Option<Box<dyn Fn(&str) -> bool>>,
filter: Filter,
}
impl Session<'_> {
@ -168,7 +170,7 @@ impl Session<'_> {
if r != ffi::SQLITE_OK {
let errmsg: *mut c_char = errmsg;
let message = errmsg_to_string(&*errmsg);
ffi::sqlite3_free(errmsg as *mut ::std::os::raw::c_void);
ffi::sqlite3_free(errmsg as *mut c_void);
return Err(error_from_sqlite_code(r, Some(message)));
}
}
@ -656,7 +658,7 @@ impl Connection {
/// See [here](https://sqlite.org/session.html#SQLITE_CHANGESET_CONFLICT) for details.
#[allow(missing_docs)]
#[repr(i32)]
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq)]
#[non_exhaustive]
#[allow(clippy::upper_case_acronyms)]
pub enum ConflictType {
@ -684,7 +686,7 @@ impl From<i32> for ConflictType {
/// See [here](https://sqlite.org/session.html#SQLITE_CHANGESET_ABORT) for details.
#[allow(missing_docs)]
#[repr(i32)]
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq)]
#[non_exhaustive]
#[allow(clippy::upper_case_acronyms)]
pub enum ConflictAction {

View File

@ -3,7 +3,7 @@ use std::os::raw::{c_int, c_void};
#[cfg(feature = "array")]
use std::rc::Rc;
use std::slice::from_raw_parts;
use std::{convert, fmt, mem, ptr, str};
use std::{fmt, mem, ptr, str};
use super::ffi;
use super::{len_as_c_int, str_for_sqlite};
@ -202,7 +202,7 @@ impl Statement<'_> {
/// }
/// ```
///
/// Or, equivalently (but without the [`params!`] macro).
/// Or, equivalently (but without the [`crate::params!`] macro).
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result};
@ -417,7 +417,7 @@ impl Statement<'_> {
pub fn query_and_then<T, E, P, F>(&mut self, params: P, f: F) -> Result<AndThenRows<'_, F>>
where
P: Params,
E: convert::From<Error>,
E: From<Error>,
F: FnMut(&Row<'_>) -> Result<T, E>,
{
self.query(params).map(|rows| rows.and_then(f))
@ -447,7 +447,7 @@ impl Statement<'_> {
f: F,
) -> Result<AndThenRows<'_, F>>
where
E: convert::From<Error>,
E: From<Error>,
F: FnMut(&Row<'_>) -> Result<T, E>,
{
self.query_and_then(params, f)
@ -796,7 +796,7 @@ impl Statement<'_> {
self.conn.decode_result(stmt.finalize())
}
#[cfg(all(feature = "modern_sqlite", feature = "extra_check"))]
#[cfg(feature = "extra_check")]
#[inline]
fn check_update(&self) -> Result<()> {
// sqlite3_column_count works for DML but not for DDL (ie ALTER)
@ -806,16 +806,6 @@ impl Statement<'_> {
Ok(())
}
#[cfg(all(not(feature = "modern_sqlite"), feature = "extra_check"))]
#[inline]
fn check_update(&self) -> Result<()> {
// sqlite3_column_count works for DML but not for DDL (ie ALTER)
if self.column_count() > 0 {
return Err(Error::ExecuteReturnedResults);
}
Ok(())
}
#[cfg(not(feature = "extra_check"))]
#[inline]
#[allow(clippy::unnecessary_wraps)]
@ -825,8 +815,6 @@ impl Statement<'_> {
/// Returns a string containing the SQL text of prepared statement with
/// bound parameters expanded.
#[cfg(feature = "modern_sqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn expanded_sql(&self) -> Option<String> {
self.stmt
.expanded_sql()
@ -1407,7 +1395,6 @@ mod test {
}
#[test]
#[cfg(feature = "modern_sqlite")]
fn test_expanded_sql() -> Result<()> {
let db = Connection::open_in_memory()?;
let stmt = db.prepare("SELECT ?")?;
@ -1422,7 +1409,7 @@ mod test {
// dynamic slice:
db.query_row(
"SELECT ?1, ?2, ?3",
&[&1u8 as &dyn ToSql, &"one", &Some("one")],
[&1u8 as &dyn ToSql, &"one", &Some("one")],
|row| row.get::<_, u8>(0),
)?;
// existing collection:
@ -1474,10 +1461,10 @@ mod test {
let conn = Connection::open_in_memory()?;
let mut stmt = conn.prepare("")?;
assert_eq!(0, stmt.column_count());
assert!(stmt.parameter_index("test").is_ok());
assert!(stmt.step().is_err());
stmt.parameter_index("test").unwrap();
stmt.step().unwrap_err();
stmt.reset();
assert!(stmt.execute([]).is_err());
stmt.execute([]).unwrap_err();
Ok(())
}
@ -1507,12 +1494,12 @@ mod test {
#[test]
fn test_utf16_conversion() -> Result<()> {
let db = Connection::open_in_memory()?;
db.pragma_update(None, "encoding", &"UTF-16le")?;
db.pragma_update(None, "encoding", "UTF-16le")?;
let encoding: String = db.pragma_query_value(None, "encoding", |row| row.get(0))?;
assert_eq!("UTF-16le", encoding);
db.execute_batch("CREATE TABLE foo(x TEXT)")?;
let expected = "テスト";
db.execute("INSERT INTO foo(x) VALUES (?)", &[&expected])?;
db.execute("INSERT INTO foo(x) VALUES (?)", [&expected])?;
let actual: String = db.query_row("SELECT x FROM foo", [], |row| row.get(0))?;
assert_eq!(expected, actual);
Ok(())
@ -1537,12 +1524,11 @@ mod test {
}
#[test]
#[cfg(all(feature = "modern_sqlite", not(feature = "bundled-sqlcipher")))] // SQLite >= 3.38.0
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
fn test_error_offset() -> Result<()> {
use crate::ffi::ErrorCode;
let db = Connection::open_in_memory()?;
let r = db.execute_batch("SELECT CURRENT_TIMESTANP;");
assert!(r.is_err());
match r.unwrap_err() {
Error::SqlInputError { error, offset, .. } => {
assert_eq!(error.code, ErrorCode::Unknown);

View File

@ -255,7 +255,7 @@ impl Savepoint<'_> {
name: T,
) -> Result<Savepoint<'_>> {
let name = name.into();
conn.execute_batch(&format!("SAVEPOINT {}", name))
conn.execute_batch(&format!("SAVEPOINT {name}"))
.map(|_| Savepoint {
conn,
name,
@ -267,7 +267,7 @@ impl Savepoint<'_> {
#[inline]
fn with_depth(conn: &Connection, depth: u32) -> Result<Savepoint<'_>> {
let name = format!("_rusqlite_sp_{}", depth);
let name = format!("_rusqlite_sp_{depth}");
Savepoint::with_depth_and_name(conn, depth, name)
}
@ -559,7 +559,7 @@ mod test {
}
Ok(())
}
fn assert_nested_tx_error(e: crate::Error) {
fn assert_nested_tx_error(e: Error) {
if let Error::SqliteFailure(e, Some(m)) = &e {
assert_eq!(e.extended_code, crate::ffi::SQLITE_ERROR);
// FIXME: Not ideal...

View File

@ -287,15 +287,15 @@ mod test {
fn test_sqlite_functions() -> Result<()> {
let db = checked_memory_handle()?;
let result: Result<NaiveTime> = db.query_row("SELECT CURRENT_TIME", [], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
let result: Result<NaiveDate> = db.query_row("SELECT CURRENT_DATE", [], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
let result: Result<NaiveDateTime> =
db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
let result: Result<DateTime<Utc>> =
db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
Ok(())
}
@ -303,7 +303,7 @@ mod test {
fn test_naive_date_time_param() -> Result<()> {
let db = checked_memory_handle()?;
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [Utc::now().naive_utc()], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
Ok(())
}
@ -311,13 +311,13 @@ mod test {
fn test_date_time_param() -> Result<()> {
let db = checked_memory_handle()?;
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [Utc::now()], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
Ok(())
}
#[test]
fn test_lenient_parse_timezone() {
assert!(DateTime::<Utc>::column_result(ValueRef::Text(b"1970-01-01T00:00:00Z")).is_ok());
assert!(DateTime::<Utc>::column_result(ValueRef::Text(b"1970-01-01T00:00:00+00")).is_ok());
DateTime::<Utc>::column_result(ValueRef::Text(b"1970-01-01T00:00:00Z")).unwrap();
DateTime::<Utc>::column_result(ValueRef::Text(b"1970-01-01T00:00:00+00")).unwrap();
}
}

View File

@ -52,7 +52,7 @@ impl fmt::Display for FromSqlError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
FromSqlError::InvalidType => write!(f, "Invalid type"),
FromSqlError::OutOfRange(i) => write!(f, "Value {} out of range", i),
FromSqlError::OutOfRange(i) => write!(f, "Value {i} out of range"),
FromSqlError::InvalidBlobSize {
expected_size,
blob_size,
@ -240,11 +240,11 @@ mod test {
fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
where
T: Into<i64> + FromSql + ::std::fmt::Debug,
T: Into<i64> + FromSql + std::fmt::Debug,
{
for n in out_of_range {
let err = db
.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
.query_row("SELECT ?", [n], |r| r.get::<_, T>(0))
.unwrap_err();
match err {
Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
@ -254,7 +254,7 @@ mod test {
for n in in_range {
assert_eq!(
*n,
db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
db.query_row("SELECT ?", [n], |r| r.get::<_, T>(0))
.unwrap()
.into()
);

View File

@ -140,7 +140,6 @@ impl fmt::Display for Type {
mod test {
use super::Value;
use crate::{params, Connection, Error, Result, Statement};
use std::f64::EPSILON;
use std::os::raw::{c_double, c_int};
fn checked_memory_handle() -> Result<Connection> {
@ -154,7 +153,7 @@ mod test {
let db = checked_memory_handle()?;
let v1234 = vec![1u8, 2, 3, 4];
db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234])?;
db.execute("INSERT INTO foo(b) VALUES (?)", [&v1234])?;
let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
assert_eq!(v, v1234);
@ -166,7 +165,7 @@ mod test {
let db = checked_memory_handle()?;
let empty = vec![];
db.execute("INSERT INTO foo(b) VALUES (?)", &[&empty])?;
db.execute("INSERT INTO foo(b) VALUES (?)", [&empty])?;
let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
assert_eq!(v, empty);
@ -178,7 +177,7 @@ mod test {
let db = checked_memory_handle()?;
let s = "hello, world!";
db.execute("INSERT INTO foo(t) VALUES (?)", &[&s])?;
db.execute("INSERT INTO foo(t) VALUES (?)", [&s])?;
let from: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(from, s);
@ -217,8 +216,8 @@ mod test {
let s = Some("hello, world!");
let b = Some(vec![1u8, 2, 3, 4]);
db.execute("INSERT INTO foo(t) VALUES (?)", &[&s])?;
db.execute("INSERT INTO foo(b) VALUES (?)", &[&b])?;
db.execute("INSERT INTO foo(t) VALUES (?)", [&s])?;
db.execute("INSERT INTO foo(b) VALUES (?)", [&b])?;
let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC")?;
let mut rows = stmt.query([])?;
@ -264,7 +263,7 @@ mod test {
assert_eq!(vec![1, 2], row.get::<_, Vec<u8>>(0)?);
assert_eq!("text", row.get::<_, String>(1)?);
assert_eq!(1, row.get::<_, c_int>(2)?);
assert!((1.5 - row.get::<_, c_double>(3)?).abs() < EPSILON);
assert!((1.5 - row.get::<_, c_double>(3)?).abs() < f64::EPSILON);
assert_eq!(row.get::<_, Option<c_int>>(4)?, None);
assert_eq!(row.get::<_, Option<c_double>>(4)?, None);
assert_eq!(row.get::<_, Option<String>>(4)?, None);
@ -355,7 +354,7 @@ mod test {
assert_eq!(Value::Text(String::from("text")), row.get::<_, Value>(1)?);
assert_eq!(Value::Integer(1), row.get::<_, Value>(2)?);
match row.get::<_, Value>(3)? {
Value::Real(val) => assert!((1.5 - val).abs() < EPSILON),
Value::Real(val) => assert!((1.5 - val).abs() < f64::EPSILON),
x => panic!("Invalid Value {:?}", x),
}
assert_eq!(Value::Null, row.get::<_, Value>(4)?);

View File

@ -41,7 +41,7 @@ mod test {
let data: serde_json::Value = serde_json::from_str(json).unwrap();
db.execute(
"INSERT INTO foo (t, b) VALUES (?, ?)",
&[&data as &dyn ToSql, &json.as_bytes()],
[&data as &dyn ToSql, &json.as_bytes()],
)?;
let t: serde_json::Value = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;

View File

@ -154,7 +154,7 @@ mod test {
let db = Connection::open_in_memory()?;
let result: Result<OffsetDateTime> =
db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
Ok(())
}
@ -162,7 +162,7 @@ mod test {
fn test_param() -> Result<()> {
let db = Connection::open_in_memory()?;
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [OffsetDateTime::now_utc()], |r| r.get(0));
assert!(result.is_ok());
result.unwrap();
Ok(())
}
}

View File

@ -278,7 +278,7 @@ mod test {
let _a: &[&dyn ToSql] = crate::params![a];
let r = ToSql::to_sql(&a);
assert!(r.is_ok());
r.unwrap();
}
#[test]
@ -287,10 +287,10 @@ mod test {
let s = "str";
let cow: Cow<str> = Cow::Borrowed(s);
let r = cow.to_sql();
assert!(r.is_ok());
r.unwrap();
let cow: Cow<str> = Cow::Owned::<str>(String::from(s));
let r = cow.to_sql();
assert!(r.is_ok());
r.unwrap();
// Ensure this compiles.
let _p: &[&dyn ToSql] = crate::params![cow];
}
@ -301,7 +301,7 @@ mod test {
let _s: &[&dyn ToSql] = crate::params![s];
let r = ToSql::to_sql(&s);
assert!(r.is_ok());
r.unwrap();
}
#[test]
@ -310,7 +310,7 @@ mod test {
let _s: &[&dyn ToSql] = crate::params![s];
let r = s.to_sql();
assert!(r.is_ok());
r.unwrap();
}
#[test]
@ -319,7 +319,7 @@ mod test {
let _s: &[&dyn ToSql] = crate::params![s];
let r = ToSql::to_sql(&s);
assert!(r.is_ok());
r.unwrap();
}
#[test]
@ -331,39 +331,38 @@ mod test {
let s: Rc<Box<str>> = Rc::new(source_str.clone());
let _s: &[&dyn ToSql] = crate::params![s];
let r = s.to_sql();
assert!(r.is_ok());
r.unwrap();
let s: Arc<Box<str>> = Arc::new(source_str.clone());
let _s: &[&dyn ToSql] = crate::params![s];
let r = s.to_sql();
assert!(r.is_ok());
r.unwrap();
let s: Arc<str> = Arc::from(&*source_str);
let _s: &[&dyn ToSql] = crate::params![s];
let r = s.to_sql();
assert!(r.is_ok());
r.unwrap();
let s: Arc<dyn ToSql> = Arc::new(source_str.clone());
let _s: &[&dyn ToSql] = crate::params![s];
let r = s.to_sql();
assert!(r.is_ok());
r.unwrap();
let s: Rc<str> = Rc::from(&*source_str);
let _s: &[&dyn ToSql] = crate::params![s];
let r = s.to_sql();
assert!(r.is_ok());
r.unwrap();
let s: Rc<dyn ToSql> = Rc::new(source_str);
let _s: &[&dyn ToSql] = crate::params![s];
let r = s.to_sql();
assert!(r.is_ok());
r.unwrap();
}
#[cfg(feature = "i128_blob")]
#[test]
fn test_i128() -> crate::Result<()> {
use crate::Connection;
use std::i128;
let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (i128 BLOB, desc TEXT)")?;
db.execute(

View File

@ -5,7 +5,5 @@ pub(crate) use param_cache::ParamIndexCache;
pub(crate) use small_cstr::SmallCString;
// Doesn't use any modern features or vtab stuff, but is only used by them.
#[cfg(any(feature = "modern_sqlite", feature = "vtab"))]
mod sqlite_string;
#[cfg(any(feature = "modern_sqlite", feature = "vtab"))]
pub(crate) use sqlite_string::SqliteMallocString;

View File

@ -5,7 +5,7 @@ use std::ffi::{CStr, CString, NulError};
/// small enough. Also guarantees it's input is UTF-8 -- used for cases where we
/// need to pass a NUL-terminated string to SQLite, and we have a `&str`.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct SmallCString(smallvec::SmallVec<[u8; 16]>);
pub(crate) struct SmallCString(SmallVec<[u8; 16]>);
impl SmallCString {
#[inline]
@ -163,8 +163,8 @@ mod test {
assert_eq!(SmallCString::new("").unwrap().0.as_slice(), b"\0");
assert_eq!(SmallCString::new("").unwrap().as_bytes_without_nul(), b"");
assert!(SmallCString::new("\0").is_err());
assert!(SmallCString::new("\0abc").is_err());
assert!(SmallCString::new("abc\0").is_err());
SmallCString::new("\0").unwrap_err();
SmallCString::new("\0abc").unwrap_err();
SmallCString::new("abc\0").unwrap_err();
}
}

View File

@ -1,10 +1,7 @@
// This is used when either vtab or modern-sqlite is on. Different methods are
// used in each feature. Avoid having to track this for each function. We will
// still warn for anything that's not used by either, though.
#![cfg_attr(
not(all(feature = "vtab", feature = "modern-sqlite")),
allow(dead_code)
)]
#![cfg_attr(not(feature = "vtab"), allow(dead_code))]
use crate::ffi;
use std::marker::PhantomData;
use std::os::raw::{c_char, c_int};
@ -134,7 +131,8 @@ impl SqliteMallocString {
// (everything is aligned to 1)
// - `size` is also never zero, although this function doesn't actually require
// it now.
let layout = Layout::from_size_align_unchecked(s.len().saturating_add(1), 1);
let len = s.len().saturating_add(1).min(isize::MAX as usize);
let layout = Layout::from_size_align_unchecked(len, 1);
// Note: This call does not return.
handle_alloc_error(layout);
});
@ -214,7 +212,7 @@ mod test {
let mut v = vec![];
for i in 0..1000 {
v.push(SqliteMallocString::from_str(&i.to_string()).into_raw());
v.push(SqliteMallocString::from_str(&format!("abc {} 😀", i)).into_raw());
v.push(SqliteMallocString::from_str(&format!("abc {i} 😀")).into_raw());
}
unsafe {
for (i, s) in v.chunks_mut(2).enumerate() {
@ -226,7 +224,7 @@ mod test {
);
assert_eq!(
std::ffi::CStr::from_ptr(s1).to_str().unwrap(),
&format!("abc {} 😀", i)
&format!("abc {i} 😀")
);
let _ = SqliteMallocString::from_raw(s0).unwrap();
let _ = SqliteMallocString::from_raw(s1).unwrap();

View File

@ -208,7 +208,7 @@ mod test {
{
let mut stmt = db.prepare("SELECT value from rarray(?);")?;
let rows = stmt.query_map(&[&ptr], |row| row.get::<_, i64>(0))?;
let rows = stmt.query_map([&ptr], |row| row.get::<_, i64>(0))?;
assert_eq!(2, Rc::strong_count(&ptr));
let mut count = 0;
for (i, value) in rows.enumerate() {

View File

@ -11,7 +11,7 @@
//! // Note: This should be done once (usually when opening the DB).
//! let db = Connection::open_in_memory()?;
//! rusqlite::vtab::csvtab::load_module(&db)?;
//! // Assum3e my_csv.csv
//! // Assume my_csv.csv
//! let schema = "
//! CREATE VIRTUAL TABLE my_csv_data
//! USING csv(filename = 'my_csv.csv')
@ -208,13 +208,13 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
let mut record = csv::ByteRecord::new();
if reader.read_byte_record(&mut record)? {
for (i, _) in record.iter().enumerate() {
cols.push(format!("c{}", i));
cols.push(format!("c{i}"));
}
}
}
} else if let Some(n_col) = n_col {
for i in 0..n_col {
cols.push(format!("c{}", i));
cols.push(format!("c{i}"));
}
}

View File

@ -187,8 +187,7 @@ pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab,
/// Virtual table configuration options
#[repr(i32)]
#[non_exhaustive]
#[cfg(feature = "modern_sqlite")] // 3.7.7
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum VTabConfig {
/// Equivalent to SQLITE_VTAB_CONSTRAINT_SUPPORT
ConstraintSupport = 1,
@ -203,8 +202,6 @@ pub struct VTabConnection(*mut ffi::sqlite3);
impl VTabConnection {
/// Configure various facets of the virtual table interface
#[cfg(feature = "modern_sqlite")] // 3.7.7
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn config(&mut self, config: VTabConfig) -> Result<()> {
crate::error::check(unsafe { ffi::sqlite3_vtab_config(self.0, config as c_int) })
}
@ -322,7 +319,7 @@ pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
/// Index constraint operator.
/// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
#[derive(Debug, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
#[allow(non_snake_case, non_camel_case_types, missing_docs)]
#[allow(clippy::upper_case_acronyms)]
pub enum IndexConstraintOp {
@ -369,7 +366,6 @@ impl From<u8> for IndexConstraintOp {
}
}
#[cfg(feature = "modern_sqlite")] // 3.9.0
bitflags::bitflags! {
/// Virtual table scan flags
/// See [Function Flags](https://sqlite.org/c3ref/c_index_scan_unique.html) for details.
@ -461,7 +457,7 @@ impl IndexInfo {
#[inline]
pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
unsafe {
(*self.0).orderByConsumed = if order_by_consumed { 1 } else { 0 };
(*self.0).orderByConsumed = order_by_consumed as c_int;
}
}
@ -474,8 +470,6 @@ impl IndexInfo {
}
/// Estimated number of rows returned.
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.8.2
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
#[inline]
pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
unsafe {
@ -484,16 +478,12 @@ impl IndexInfo {
}
/// Mask of SQLITE_INDEX_SCAN_* flags.
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.9.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
#[inline]
pub fn set_idx_flags(&mut self, flags: IndexFlags) {
unsafe { (*self.0).idxFlags = flags.bits() };
}
/// Mask of columns used by statement
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.10.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
#[inline]
pub fn col_used(&self) -> u64 {
unsafe { (*self.0).colUsed }
@ -509,7 +499,7 @@ impl IndexInfo {
if collation.is_null() {
return Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("{} is out of range", constraint_idx)),
Some(format!("{constraint_idx} is out of range")),
));
}
Ok(unsafe { CStr::from_ptr(collation) }.to_str()?)
@ -623,7 +613,7 @@ impl IndexConstraintUsage<'_> {
/// if `omit`, do not code a test for this constraint
#[inline]
pub fn set_omit(&mut self, omit: bool) {
self.0.omit = if omit { 1 } else { 0 };
self.0.omit = omit as std::os::raw::c_uchar;
}
}
@ -934,7 +924,7 @@ pub fn parameter(c_slice: &[u8]) -> Result<(&str, &str)> {
return Ok((param, value));
}
}
Err(Error::ModuleError(format!("illegal argument: '{}'", arg)))
Err(Error::ModuleError(format!("illegal argument: '{arg}'")))
}
// FIXME copy/paste from function.rs
@ -963,7 +953,7 @@ where
.map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
.collect::<Vec<_>>();
match T::create(&mut conn, aux.as_ref(), &vec[..]) {
Ok((sql, vtab)) => match ::std::ffi::CString::new(sql) {
Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
Ok(c_sql) => {
let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
if rc == ffi::SQLITE_OK {
@ -1015,7 +1005,7 @@ where
.map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
.collect::<Vec<_>>();
match T::connect(&mut conn, aux.as_ref(), &vec[..]) {
Ok((sql, vtab)) => match ::std::ffi::CString::new(sql) {
Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
Ok(c_sql) => {
let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
if rc == ffi::SQLITE_OK {
@ -1334,7 +1324,7 @@ pub mod csvtab;
#[cfg(feature = "series")]
#[cfg_attr(docsrs, doc(cfg(feature = "series")))]
pub mod series; // SQLite >= 3.9.0
#[cfg(test)]
#[cfg(all(test, feature = "modern_sqlite"))]
mod vtablog;
#[cfg(test)]

View File

@ -115,6 +115,7 @@ unsafe impl<'vtab> VTab<'vtab> for SeriesTab {
}
if idx_num.contains(QueryPlanFlags::BOTH) {
// Both start= and stop= boundaries are available.
//#[allow(clippy::bool_to_int_with_if)]
info.set_estimated_cost(f64::from(
2 - if idx_num.contains(QueryPlanFlags::STEP) {
1

View File

@ -153,7 +153,7 @@ impl<'vtab> CreateVTab<'vtab> for VTabLog {
impl<'vtab> UpdateVTab<'vtab> for VTabLog {
fn delete(&mut self, arg: ValueRef<'_>) -> Result<()> {
println!("VTabLog::delete({}, {:?})", self.i_inst, arg);
println!("VTabLog::delete({}, {arg:?})", self.i_inst);
Ok(())
}
@ -163,7 +163,7 @@ impl<'vtab> UpdateVTab<'vtab> for VTabLog {
self.i_inst,
args.iter().collect::<Vec<ValueRef<'_>>>()
);
Ok(self.n_row as i64)
Ok(self.n_row)
}
fn update(&mut self, args: &Values<'_>) -> Result<()> {
@ -246,7 +246,7 @@ unsafe impl VTabCursor for VTabLogCursor<'_> {
self.row_id
)
} else {
format!("{}{}", i, self.row_id)
format!("{i}{}", self.row_id)
};
println!(
"VTabLogCursor::column(tab={}, cursor={}, i={}): {}",

View File

@ -16,5 +16,5 @@ fn test_error_when_singlethread_mode() {
assert_eq!(ffi::sqlite3_initialize(), ffi::SQLITE_OK);
}
let res = Connection::open_in_memory();
assert!(res.is_err());
res.unwrap_err();
}