Merge branch 'master' into captured_identifiers

This commit is contained in:
gwenn 2023-08-19 12:50:10 +02:00 committed by GitHub
commit e8f73c93c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 6214 additions and 3060 deletions

View File

@ -49,7 +49,7 @@ jobs:
# The `{ sharedKey: ... }` allows different actions to share the cache. # The `{ sharedKey: ... }` allows different actions to share the cache.
# We're using a `fullBuild` key mostly as a "this needs to do the # We're using a `fullBuild` key mostly as a "this needs to do the
# complete" that needs to do the complete build (that is, including # complete" that needs to do the complete build (that is, including
# `--features 'bundled-full session buildtime_bindgen`), which is very # `--features 'bundled-full session buildtime_bindgen'`), which is very
# slow, and has several deps. # slow, and has several deps.
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with: { sharedKey: fullBuild } with: { sharedKey: fullBuild }

View File

@ -3,10 +3,10 @@ name = "rusqlite"
# Note: Update version in README.md when you change this. # Note: Update version in README.md when you change this.
version = "0.29.0" version = "0.29.0"
authors = ["The rusqlite developers"] authors = ["The rusqlite developers"]
edition = "2018" edition = "2021"
description = "Ergonomic wrapper for SQLite" description = "Ergonomic wrapper for SQLite"
repository = "https://github.com/rusqlite/rusqlite" repository = "https://github.com/rusqlite/rusqlite"
documentation = "http://docs.rs/rusqlite/" documentation = "https://docs.rs/rusqlite/"
readme = "README.md" readme = "README.md"
keywords = ["sqlite", "database", "ffi"] keywords = ["sqlite", "database", "ffi"]
license = "MIT" license = "MIT"
@ -77,6 +77,8 @@ column_decltype = []
wasm32-wasi-vfs = ["libsqlite3-sys/wasm32-wasi-vfs"] wasm32-wasi-vfs = ["libsqlite3-sys/wasm32-wasi-vfs"]
# Note: doesn't support 32-bit. # Note: doesn't support 32-bit.
winsqlite3 = ["libsqlite3-sys/winsqlite3"] winsqlite3 = ["libsqlite3-sys/winsqlite3"]
# 3.23.0
serialize = ["modern_sqlite"]
# Helper feature for enabling most non-build-related optional features # Helper feature for enabling most non-build-related optional features
# or dependencies (except `session`). This is useful for running tests / clippy # or dependencies (except `session`). This is useful for running tests / clippy
@ -118,7 +120,7 @@ chrono = { version = "0.4", optional = true, default-features = false, features
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
csv = { version = "1.1", optional = true } csv = { version = "1.1", optional = true }
url = { version = "2.1", optional = true } url = { version = "2.1", optional = true }
fallible-iterator = "0.2" fallible-iterator = "0.3"
fallible-streaming-iterator = "0.1" fallible-streaming-iterator = "0.1"
uuid = { version = "1.0", optional = true } uuid = { version = "1.0", optional = true }
smallvec = "1.6.1" smallvec = "1.6.1"

View File

@ -15,7 +15,7 @@ For version 0.15.0 and above, see [Releases](https://github.com/rusqlite/rusqlit
* Add DropBehavior::Panic to enforce intentional commit or rollback. * Add DropBehavior::Panic to enforce intentional commit or rollback.
* Implement `sqlite3_update_hook` (#260, #328), `sqlite3_commit_hook` and `sqlite3_rollback_hook`. * Implement `sqlite3_update_hook` (#260, #328), `sqlite3_commit_hook` and `sqlite3_rollback_hook`.
* Add support to unlock notification behind `unlock_notify` feature (#294, #331). * Add support to unlock notification behind `unlock_notify` feature (#294, #331).
* Make `Statement::column_index` case insensitive (#330). * Make `Statement::column_index` case-insensitive (#330).
* Add comment to justify `&mut Connection` in `Transaction`. * Add comment to justify `&mut Connection` in `Transaction`.
* Fix `tyvar_behind_raw_pointer` warnings. * Fix `tyvar_behind_raw_pointer` warnings.
* Fix handful of clippy warnings. * Fix handful of clippy warnings.
@ -29,7 +29,7 @@ For version 0.15.0 and above, see [Releases](https://github.com/rusqlite/rusqlit
# Version 0.13.0 (2017-11-13) # Version 0.13.0 (2017-11-13)
* Added ToSqlConversionFailure case to Error enum. * Added ToSqlConversionFailure case to Error enum.
* Now depends on chrono 0.4, bitflats 1.0, and (optionally) cc 1.0 / bindgen 0.31. * Now depends on chrono 0.4, bitflags 1.0, and (optionally) cc 1.0 / bindgen 0.31.
* The ToSql/FromSql implementations for time::Timespec now include * The ToSql/FromSql implementations for time::Timespec now include
and expect fractional seconds and timezone in the serialized string. and expect fractional seconds and timezone in the serialized string.
* The RowIndex type used in Row::get is now publicly exported. * The RowIndex type used in Row::get is now publicly exported.
@ -61,18 +61,18 @@ For version 0.15.0 and above, see [Releases](https://github.com/rusqlite/rusqlit
* Adds `version()` and `version_number()` functions for querying the version of SQLite in use. * Adds `version()` and `version_number()` functions for querying the version of SQLite in use.
* Adds the `limits` feature, exposing `limit()` and `set_limit()` methods on `Connection`. * Adds the `limits` feature, exposing `limit()` and `set_limit()` methods on `Connection`.
* Updates to `libsqlite3-sys` 0.7.0, which runs rust-bindgen at build-time instead of assuming the * Updates to `libsqlite3-sys` 0.7.0, which runs rust-bindgen at build-time instead of assuming the
precense of all expected SQLite constants and functions. presence of all expected SQLite constants and functions.
* Clarifies supported SQLite versions. Running with SQLite older than 3.6.8 now panics, and * Clarifies supported SQLite versions. Running with SQLite older than 3.6.8 now panics, and
some features will not compile unless a sufficiently-recent SQLite version is used. See some features will not compile unless a sufficiently-recent SQLite version is used. See
the README for requirements of particular features. the README for requirements of particular features.
* When running with SQLite 3.6.x, rusqlite attempts to perform SQLite initialization. If it fails, * When running with SQLite 3.6.x, rusqlite attempts to perform SQLite initialization. If it fails,
rusqlite will panic since it cannot ensure the threading mode for SQLite. This check can by rusqlite will panic since it cannot ensure the threading mode for SQLite. This check can be
skipped by calling the unsafe function `rusqlite::bypass_sqlite_initialization()`. This is skipped by calling the unsafe function `rusqlite::bypass_sqlite_initialization()`. This is
technically a breaking change but is unlikely to affect anyone in practice, since prior to this technically a breaking change but is unlikely to affect anyone in practice, since prior to this
version the check that rusqlite was using would cause a segfault if linked against a SQLite version the check that rusqlite was using would cause a segfault if linked against a SQLite
older than 3.7.0. older than 3.7.0.
* rusqlite now performs a one-time check (prior to the first connection attempt) that the runtime * rusqlite now performs a one-time check (prior to the first connection attempt) that the runtime
SQLite version is at least as new as the SQLite version found at buildtime. This check can by SQLite version is at least as new as the SQLite version found at buildtime. This check can be
skipped by calling the unsafe function `rusqlite::bypass_sqlite_version_check()`. skipped by calling the unsafe function `rusqlite::bypass_sqlite_version_check()`.
* Removes the `libc` dependency in favor of using `std::os::raw` * Removes the `libc` dependency in favor of using `std::os::raw`
@ -137,7 +137,7 @@ For version 0.15.0 and above, see [Releases](https://github.com/rusqlite/rusqlit
This behavior is more correct. Previously there were runtime checks to prevent misuse, but This behavior is more correct. Previously there were runtime checks to prevent misuse, but
other changes in this release to reset statements as soon as possible introduced yet another other changes in this release to reset statements as soon as possible introduced yet another
hazard related to the lack of these lifetime connections. We were already recommending the hazard related to the lack of these lifetime connections. We were already recommending the
use of `query_map` and `query_and_then` over raw `query`; both of theose still return handles use of `query_map` and `query_and_then` over raw `query`; both of those still return handles
that implement `Iterator`. that implement `Iterator`.
* BREAKING CHANGE: `Transaction::savepoint()` now returns a `Savepoint` instead of another * BREAKING CHANGE: `Transaction::savepoint()` now returns a `Savepoint` instead of another
`Transaction`. Unlike `Transaction`, `Savepoint`s can be rolled back while keeping the current `Transaction`. Unlike `Transaction`, `Savepoint`s can be rolled back while keeping the current
@ -239,7 +239,7 @@ For version 0.15.0 and above, see [Releases](https://github.com/rusqlite/rusqlit
* Add `column_names()` to `SqliteStatement`. * Add `column_names()` to `SqliteStatement`.
* By default, include `SQLITE_OPEN_NO_MUTEX` and `SQLITE_OPEN_URI` flags when opening a * By default, include `SQLITE_OPEN_NO_MUTEX` and `SQLITE_OPEN_URI` flags when opening a
new conneciton. new connection.
* Fix generated bindings (e.g., `sqlite3_exec` was wrong). * Fix generated bindings (e.g., `sqlite3_exec` was wrong).
* Use now-generated `sqlite3_destructor_type` to define `SQLITE_STATIC` and `SQLITE_TRANSIENT`. * Use now-generated `sqlite3_destructor_type` to define `SQLITE_STATIC` and `SQLITE_TRANSIENT`.

View File

@ -113,8 +113,8 @@ features](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-s
and [`ToSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.ToSql.html) for the and [`ToSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.ToSql.html) for the
`Value` type from the [`serde_json` crate](https://crates.io/crates/serde_json). `Value` type from the [`serde_json` crate](https://crates.io/crates/serde_json).
* `time` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html) * `time` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html)
and [`ToSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.ToSql.html) for the and [`ToSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.ToSql.html) for various
`time::OffsetDateTime` type from the [`time` crate](https://crates.io/crates/time). types from the [`time` crate](https://crates.io/crates/time).
* `url` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html) * `url` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html)
and [`ToSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.ToSql.html) for the and [`ToSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.ToSql.html) for the
`Url` type from the [`url` crate](https://crates.io/crates/url). `Url` type from the [`url` crate](https://crates.io/crates/url).

View File

@ -1,2 +1 @@
doc-valid-idents = ["SQLite", "lang_transaction"] doc-valid-idents = ["SQLite", "lang_transaction"]
msrv = "1.55.0"

View File

@ -44,7 +44,7 @@ winsqlite3 = []
openssl-sys = { version = "0.9", optional = true } openssl-sys = { version = "0.9", optional = true }
[build-dependencies] [build-dependencies]
bindgen = { version = "0.64", optional = true, default-features = false, features = ["runtime"] } bindgen = { version = "0.66", optional = true, default-features = false, features = ["runtime"] }
pkg-config = { version = "0.3.19", optional = true } pkg-config = { version = "0.3.19", optional = true }
cc = { version = "1.0", optional = true } cc = { version = "1.0", optional = true }
vcpkg = { version = "0.2", optional = true } vcpkg = { version = "0.2", optional = true }

View File

@ -26,17 +26,26 @@ fn is_compiler(compiler_name: &str) -> bool {
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)
} }
/// Copy bindgen file from `dir` to `out_path`.
fn copy_bindings<T: AsRef<Path>>(dir: &str, bindgen_name: &str, out_path: T) {
std::fs::copy(format!("{dir}/{bindgen_name}"), out_path)
.expect("Could not copy bindings to output directory");
}
fn main() { fn main() {
let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap();
let out_path = Path::new(&out_dir).join("bindgen.rs"); let out_path = Path::new(&out_dir).join("bindgen.rs");
if cfg!(feature = "in_gecko") { if cfg!(feature = "in_gecko") {
// When inside mozilla-central, we are included into the build with // When inside mozilla-central, we are included into the build with
// sqlite3.o directly, so we don't want to provide any linker arguments. // sqlite3.o directly, so we don't want to provide any linker arguments.
std::fs::copy("sqlite3/bindgen_bundled_version.rs", out_path) copy_bindings("sqlite3", "bindgen_bundled_version.rs", out_path);
.expect("Could not copy bindings to output directory");
return; return;
} }
if cfg!(all(
println!("cargo:rerun-if-env-changed=LIBSQLITE3_SYS_USE_PKG_CONFIG");
if env::var_os("LIBSQLITE3_SYS_USE_PKG_CONFIG").map_or(false, |s| s != "0") {
build_linked::main(&out_dir, &out_path);
} else if cfg!(all(
feature = "sqlcipher", feature = "sqlcipher",
not(feature = "bundled-sqlcipher") not(feature = "bundled-sqlcipher")
)) { )) {
@ -92,17 +101,13 @@ mod build_bundled {
#[cfg(feature = "buildtime_bindgen")] #[cfg(feature = "buildtime_bindgen")]
{ {
use super::{bindings, HeaderLocation}; use super::{bindings, HeaderLocation};
let header = HeaderLocation::FromPath(format!("{}/sqlite3.h", lib_name)); let header = HeaderLocation::FromPath(lib_name.to_owned());
bindings::write_to_out_dir(header, out_path); bindings::write_to_out_dir(header, out_path);
} }
#[cfg(not(feature = "buildtime_bindgen"))] #[cfg(not(feature = "buildtime_bindgen"))]
{ {
use std::fs; super::copy_bindings(lib_name, "bindgen_bundled_version.rs", 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={lib_name}/sqlite3.c"); println!("cargo:rerun-if-changed={lib_name}/sqlite3.c");
println!("cargo:rerun-if-changed=sqlite3/wasm32-wasi-vfs.c"); println!("cargo:rerun-if-changed=sqlite3/wasm32-wasi-vfs.c");
let mut cfg = cc::Build::new(); let mut cfg = cc::Build::new();
@ -236,7 +241,7 @@ mod build_bundled {
cfg.flag("-DHAVE_LOCALTIME_R"); cfg.flag("-DHAVE_LOCALTIME_R");
} }
// Target wasm32-wasi can't compile the default VFS // Target wasm32-wasi can't compile the default VFS
if is_compiler("wasm32-wasi") { if env::var("TARGET").map_or(false, |v| v == "wasm32-wasi") {
cfg.flag("-DSQLITE_OS_OTHER") cfg.flag("-DSQLITE_OS_OTHER")
// https://github.com/rust-lang/rust/issues/74393 // https://github.com/rust-lang/rust/issues/74393
.flag("-DLONGDOUBLE_TYPE=double"); .flag("-DLONGDOUBLE_TYPE=double");
@ -264,6 +269,11 @@ mod build_bundled {
} }
println!("cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH"); println!("cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH");
if let Ok(limit) = env::var("SQLITE_MAX_COLUMN") {
cfg.flag(&format!("-DSQLITE_MAX_COLUMN={limit}"));
}
println!("cargo:rerun-if-env-changed=SQLITE_MAX_COLUMN");
if let Ok(extras) = env::var("LIBSQLITE3_FLAGS") { if let Ok(extras) = env::var("LIBSQLITE3_FLAGS") {
for extra in extras.split_whitespace() { for extra in extras.split_whitespace() {
if extra.starts_with("-D") || extra.starts_with("-U") { if extra.starts_with("-D") || extra.starts_with("-U") {
@ -338,7 +348,7 @@ impl From<HeaderLocation> for String {
header header
} }
HeaderLocation::Wrapper => "wrapper.h".into(), HeaderLocation::Wrapper => "wrapper.h".into(),
HeaderLocation::FromPath(path) => path, HeaderLocation::FromPath(path) => format!("{}/sqlite3.h", path),
} }
} }
} }
@ -365,11 +375,7 @@ mod build_linked {
// on buildtime_bindgen instead, but this is still supported as we // on buildtime_bindgen instead, but this is still supported as we
// have runtime version checks and there are good reasons to not // have runtime version checks and there are good reasons to not
// want to run bindgen. // want to run bindgen.
std::fs::copy( super::copy_bindings(lib_name(), "bindgen_bundled_version.rs", out_path);
format!("{}/bindgen_bundled_version.rs", lib_name()),
out_path,
)
.expect("Could not copy bindings to output directory");
} else { } else {
bindings::write_to_out_dir(header, out_path); bindings::write_to_out_dir(header, out_path);
} }
@ -427,8 +433,7 @@ mod build_linked {
.print_system_libs(false) .print_system_libs(false)
.probe(link_lib) .probe(link_lib)
{ {
if let Some(mut header) = lib.include_paths.pop() { if let Some(header) = lib.include_paths.pop() {
header.push("sqlite3.h");
HeaderLocation::FromPath(header.to_string_lossy().into()) HeaderLocation::FromPath(header.to_string_lossy().into())
} else { } else {
HeaderLocation::Wrapper HeaderLocation::Wrapper
@ -447,8 +452,7 @@ mod build_linked {
if cfg!(feature = "vcpkg") && is_compiler("msvc") { if cfg!(feature = "vcpkg") && is_compiler("msvc") {
// See if vcpkg can find it. // See if vcpkg can find it.
if let Ok(mut lib) = vcpkg::Config::new().probe(lib_name()) { if let Ok(mut lib) = vcpkg::Config::new().probe(lib_name()) {
if let Some(mut header) = lib.include_paths.pop() { if let Some(header) = lib.include_paths.pop() {
header.push("sqlite3.h");
return Some(HeaderLocation::FromPath(header.to_string_lossy().into())); return Some(HeaderLocation::FromPath(header.to_string_lossy().into()));
} }
} }
@ -464,14 +468,13 @@ mod bindings {
#![allow(dead_code)] #![allow(dead_code)]
use super::HeaderLocation; use super::HeaderLocation;
use std::fs;
use std::path::Path; use std::path::Path;
static PREBUILT_BINDGEN_PATHS: &[&str] = &["bindgen-bindings/bindgen_3.14.0.rs"]; static PREBUILT_BINDGENS: &[&str] = &["bindgen_3.14.0.rs"];
pub fn write_to_out_dir(_header: HeaderLocation, out_path: &Path) { pub fn write_to_out_dir(_header: HeaderLocation, out_path: &Path) {
let in_path = PREBUILT_BINDGEN_PATHS[PREBUILT_BINDGEN_PATHS.len() - 1]; let name = PREBUILT_BINDGENS[PREBUILT_BINDGENS.len() - 1];
fs::copy(in_path, out_path).expect("Could not copy bindings to output directory"); super::copy_bindings("bindgen-bindings", name, out_path);
} }
} }
@ -480,8 +483,6 @@ mod bindings {
use super::HeaderLocation; use super::HeaderLocation;
use bindgen::callbacks::{IntKind, ParseCallbacks}; use bindgen::callbacks::{IntKind, ParseCallbacks};
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path; use std::path::Path;
use super::win_target; use super::win_target;
@ -490,19 +491,16 @@ mod bindings {
struct SqliteTypeChooser; struct SqliteTypeChooser;
impl ParseCallbacks for SqliteTypeChooser { impl ParseCallbacks for SqliteTypeChooser {
fn int_macro(&self, _name: &str, value: i64) -> Option<IntKind> { fn int_macro(&self, name: &str, _value: i64) -> Option<IntKind> {
if value >= i32::MIN as i64 && value <= i32::MAX as i64 { if name == "SQLITE_SERIALIZE_NOCOPY"
Some(IntKind::I32) || name.starts_with("SQLITE_DESERIALIZE_")
|| name.starts_with("SQLITE_PREPARE_")
{
Some(IntKind::UInt)
} else { } else {
None None
} }
} }
fn item_name(&self, original_item_name: &str) -> Option<String> {
original_item_name
.strip_prefix("sqlite3_index_info_")
.map(|s| s.to_owned())
}
} }
// Are we generating the bundled bindings? Used to avoid emitting things // Are we generating the bundled bindings? Used to avoid emitting things
@ -519,8 +517,9 @@ mod bindings {
pub fn write_to_out_dir(header: HeaderLocation, out_path: &Path) { pub fn write_to_out_dir(header: HeaderLocation, out_path: &Path) {
let header: String = header.into(); let header: String = header.into();
let mut output = Vec::new();
let mut bindings = bindgen::builder() let mut bindings = bindgen::builder()
.default_macro_constant_type(bindgen::MacroTypeVariation::Signed)
.disable_nested_struct_naming()
.trust_clang_mangling(false) .trust_clang_mangling(false)
.header(header.clone()) .header(header.clone())
.parse_callbacks(Box::new(SqliteTypeChooser)) .parse_callbacks(Box::new(SqliteTypeChooser))
@ -551,8 +550,7 @@ mod bindings {
>, >,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
}"#, }"#,
) );
.rustfmt_bindings(true);
if cfg!(any(feature = "sqlcipher", feature = "bundled-sqlcipher")) { if cfg!(any(feature = "sqlcipher", feature = "bundled-sqlcipher")) {
bindings = bindings.clang_arg("-DSQLITE_HAS_CODEC"); bindings = bindings.clang_arg("-DSQLITE_HAS_CODEC");
@ -620,38 +618,14 @@ mod bindings {
.blocklist_function("sqlite3_vsnprintf") .blocklist_function("sqlite3_vsnprintf")
.blocklist_function("sqlite3_str_vappendf") .blocklist_function("sqlite3_str_vappendf")
.blocklist_type("va_list") .blocklist_type("va_list")
.blocklist_type("__builtin_va_list") .blocklist_item("__.*");
.blocklist_type("__gnuc_va_list")
.blocklist_type("__va_list_tag")
.blocklist_item("__GNUC_VA_LIST");
} }
bindings bindings
.layout_tests(false) .layout_tests(false)
.generate() .generate()
.unwrap_or_else(|_| panic!("could not run bindgen on header {}", header)) .unwrap_or_else(|_| panic!("could not run bindgen on header {}", header))
.write(Box::new(&mut output)) .write_to_file(out_path)
.expect("could not write output of bindgen");
let mut output = String::from_utf8(output).expect("bindgen output was not UTF-8?!");
// rusqlite's functions feature ors in the SQLITE_DETERMINISTIC flag when it
// can. This flag was added in SQLite 3.8.3, but oring it in in prior
// versions of SQLite is harmless. We don't want to not build just
// because this flag is missing (e.g., if we're linking against
// SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's
// output.
if !output.contains("pub const SQLITE_DETERMINISTIC") {
output.push_str("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n");
}
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(out_path)
.unwrap_or_else(|_| panic!("Could not write to {:?}", out_path));
file.write_all(output.as_bytes())
.unwrap_or_else(|_| panic!("Could not write to {:?}", out_path)); .unwrap_or_else(|_| panic!("Could not write to {:?}", out_path));
} }
} }

View File

@ -1,4 +1,4 @@
/* automatically generated by rust-bindgen 0.64.0 */ /* automatically generated by rust-bindgen 0.66.0 */
extern "C" { extern "C" {
pub fn sqlite3_auto_extension( pub fn sqlite3_auto_extension(
@ -11,7 +11,6 @@ extern "C" {
>, >,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" { extern "C" {
pub fn sqlite3_cancel_auto_extension( pub fn sqlite3_cancel_auto_extension(
xEntryPoint: ::std::option::Option< xEntryPoint: ::std::option::Option<
@ -24,10 +23,72 @@ extern "C" {
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_VERSION: &[u8; 7usize] = b"3.41.2\0"; pub const SQLITE_VERSION: &[u8; 7] = b"3.42.0\0";
pub const SQLITE_VERSION_NUMBER: i32 = 3041002; pub const SQLITE_VERSION_NUMBER: i32 = 3042000;
pub const SQLITE_SOURCE_ID: &[u8; 85usize] = pub const SQLITE_SOURCE_ID: &[u8; 85] =
b"2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da\0"; b"2023-05-16 12:36:15 831d0fb2836b71c9bc51067c49fee4b8f18047814f2ff22d817d25195cf350b0\0";
extern "C" {
pub static sqlite3_version: [::std::os::raw::c_char; 0usize];
}
extern "C" {
pub fn sqlite3_libversion() -> *const ::std::os::raw::c_char;
}
extern "C" {
pub fn sqlite3_sourceid() -> *const ::std::os::raw::c_char;
}
extern "C" {
pub fn sqlite3_libversion_number() -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_compileoption_used(
zOptName: *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_compileoption_get(N: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char;
}
extern "C" {
pub fn sqlite3_threadsafe() -> ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct sqlite3 {
_unused: [u8; 0],
}
pub type sqlite_int64 = ::std::os::raw::c_longlong;
pub type sqlite_uint64 = ::std::os::raw::c_ulonglong;
pub type sqlite3_int64 = sqlite_int64;
pub type sqlite3_uint64 = sqlite_uint64;
extern "C" {
pub fn sqlite3_close(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_close_v2(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
}
pub type sqlite3_callback = ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut ::std::os::raw::c_char,
arg4: *mut *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int,
>;
extern "C" {
pub fn sqlite3_exec(
arg1: *mut sqlite3,
sql: *const ::std::os::raw::c_char,
callback: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut ::std::os::raw::c_char,
arg4: *mut *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int,
>,
arg2: *mut ::std::os::raw::c_void,
errmsg: *mut *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
pub const SQLITE_OK: i32 = 0; pub const SQLITE_OK: i32 = 0;
pub const SQLITE_ERROR: i32 = 1; pub const SQLITE_ERROR: i32 = 1;
pub const SQLITE_INTERNAL: i32 = 2; pub const SQLITE_INTERNAL: i32 = 2;
@ -181,389 +242,6 @@ pub const SQLITE_LOCK_EXCLUSIVE: i32 = 4;
pub const SQLITE_SYNC_NORMAL: i32 = 2; pub const SQLITE_SYNC_NORMAL: i32 = 2;
pub const SQLITE_SYNC_FULL: i32 = 3; pub const SQLITE_SYNC_FULL: i32 = 3;
pub const SQLITE_SYNC_DATAONLY: i32 = 16; pub const SQLITE_SYNC_DATAONLY: i32 = 16;
pub const SQLITE_FCNTL_LOCKSTATE: i32 = 1;
pub const SQLITE_FCNTL_GET_LOCKPROXYFILE: i32 = 2;
pub const SQLITE_FCNTL_SET_LOCKPROXYFILE: i32 = 3;
pub const SQLITE_FCNTL_LAST_ERRNO: i32 = 4;
pub const SQLITE_FCNTL_SIZE_HINT: i32 = 5;
pub const SQLITE_FCNTL_CHUNK_SIZE: i32 = 6;
pub const SQLITE_FCNTL_FILE_POINTER: i32 = 7;
pub const SQLITE_FCNTL_SYNC_OMITTED: i32 = 8;
pub const SQLITE_FCNTL_WIN32_AV_RETRY: i32 = 9;
pub const SQLITE_FCNTL_PERSIST_WAL: i32 = 10;
pub const SQLITE_FCNTL_OVERWRITE: i32 = 11;
pub const SQLITE_FCNTL_VFSNAME: i32 = 12;
pub const SQLITE_FCNTL_POWERSAFE_OVERWRITE: i32 = 13;
pub const SQLITE_FCNTL_PRAGMA: i32 = 14;
pub const SQLITE_FCNTL_BUSYHANDLER: i32 = 15;
pub const SQLITE_FCNTL_TEMPFILENAME: i32 = 16;
pub const SQLITE_FCNTL_MMAP_SIZE: i32 = 18;
pub const SQLITE_FCNTL_TRACE: i32 = 19;
pub const SQLITE_FCNTL_HAS_MOVED: i32 = 20;
pub const SQLITE_FCNTL_SYNC: i32 = 21;
pub const SQLITE_FCNTL_COMMIT_PHASETWO: i32 = 22;
pub const SQLITE_FCNTL_WIN32_SET_HANDLE: i32 = 23;
pub const SQLITE_FCNTL_WAL_BLOCK: i32 = 24;
pub const SQLITE_FCNTL_ZIPVFS: i32 = 25;
pub const SQLITE_FCNTL_RBU: i32 = 26;
pub const SQLITE_FCNTL_VFS_POINTER: i32 = 27;
pub const SQLITE_FCNTL_JOURNAL_POINTER: i32 = 28;
pub const SQLITE_FCNTL_WIN32_GET_HANDLE: i32 = 29;
pub const SQLITE_FCNTL_PDB: i32 = 30;
pub const SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: i32 = 31;
pub const SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: i32 = 32;
pub const SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: i32 = 33;
pub const SQLITE_FCNTL_LOCK_TIMEOUT: i32 = 34;
pub const SQLITE_FCNTL_DATA_VERSION: i32 = 35;
pub const SQLITE_FCNTL_SIZE_LIMIT: i32 = 36;
pub const SQLITE_FCNTL_CKPT_DONE: i32 = 37;
pub const SQLITE_FCNTL_RESERVE_BYTES: i32 = 38;
pub const SQLITE_FCNTL_CKPT_START: i32 = 39;
pub const SQLITE_FCNTL_EXTERNAL_READER: i32 = 40;
pub const SQLITE_FCNTL_CKSM_FILE: i32 = 41;
pub const SQLITE_FCNTL_RESET_CACHE: i32 = 42;
pub const SQLITE_GET_LOCKPROXYFILE: i32 = 2;
pub const SQLITE_SET_LOCKPROXYFILE: i32 = 3;
pub const SQLITE_LAST_ERRNO: i32 = 4;
pub const SQLITE_ACCESS_EXISTS: i32 = 0;
pub const SQLITE_ACCESS_READWRITE: i32 = 1;
pub const SQLITE_ACCESS_READ: i32 = 2;
pub const SQLITE_SHM_UNLOCK: i32 = 1;
pub const SQLITE_SHM_LOCK: i32 = 2;
pub const SQLITE_SHM_SHARED: i32 = 4;
pub const SQLITE_SHM_EXCLUSIVE: i32 = 8;
pub const SQLITE_SHM_NLOCK: i32 = 8;
pub const SQLITE_CONFIG_SINGLETHREAD: i32 = 1;
pub const SQLITE_CONFIG_MULTITHREAD: i32 = 2;
pub const SQLITE_CONFIG_SERIALIZED: i32 = 3;
pub const SQLITE_CONFIG_MALLOC: i32 = 4;
pub const SQLITE_CONFIG_GETMALLOC: i32 = 5;
pub const SQLITE_CONFIG_SCRATCH: i32 = 6;
pub const SQLITE_CONFIG_PAGECACHE: i32 = 7;
pub const SQLITE_CONFIG_HEAP: i32 = 8;
pub const SQLITE_CONFIG_MEMSTATUS: i32 = 9;
pub const SQLITE_CONFIG_MUTEX: i32 = 10;
pub const SQLITE_CONFIG_GETMUTEX: i32 = 11;
pub const SQLITE_CONFIG_LOOKASIDE: i32 = 13;
pub const SQLITE_CONFIG_PCACHE: i32 = 14;
pub const SQLITE_CONFIG_GETPCACHE: i32 = 15;
pub const SQLITE_CONFIG_LOG: i32 = 16;
pub const SQLITE_CONFIG_URI: i32 = 17;
pub const SQLITE_CONFIG_PCACHE2: i32 = 18;
pub const SQLITE_CONFIG_GETPCACHE2: i32 = 19;
pub const SQLITE_CONFIG_COVERING_INDEX_SCAN: i32 = 20;
pub const SQLITE_CONFIG_SQLLOG: i32 = 21;
pub const SQLITE_CONFIG_MMAP_SIZE: i32 = 22;
pub const SQLITE_CONFIG_WIN32_HEAPSIZE: i32 = 23;
pub const SQLITE_CONFIG_PCACHE_HDRSZ: i32 = 24;
pub const SQLITE_CONFIG_PMASZ: i32 = 25;
pub const SQLITE_CONFIG_STMTJRNL_SPILL: i32 = 26;
pub const SQLITE_CONFIG_SMALL_MALLOC: i32 = 27;
pub const SQLITE_CONFIG_SORTERREF_SIZE: i32 = 28;
pub const SQLITE_CONFIG_MEMDB_MAXSIZE: i32 = 29;
pub const SQLITE_DBCONFIG_MAINDBNAME: i32 = 1000;
pub const SQLITE_DBCONFIG_LOOKASIDE: i32 = 1001;
pub const SQLITE_DBCONFIG_ENABLE_FKEY: i32 = 1002;
pub const SQLITE_DBCONFIG_ENABLE_TRIGGER: i32 = 1003;
pub const SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: i32 = 1004;
pub const SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: i32 = 1005;
pub const SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: i32 = 1006;
pub const SQLITE_DBCONFIG_ENABLE_QPSG: i32 = 1007;
pub const SQLITE_DBCONFIG_TRIGGER_EQP: i32 = 1008;
pub const SQLITE_DBCONFIG_RESET_DATABASE: i32 = 1009;
pub const SQLITE_DBCONFIG_DEFENSIVE: i32 = 1010;
pub const SQLITE_DBCONFIG_WRITABLE_SCHEMA: i32 = 1011;
pub const SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: i32 = 1012;
pub const SQLITE_DBCONFIG_DQS_DML: i32 = 1013;
pub const SQLITE_DBCONFIG_DQS_DDL: i32 = 1014;
pub const SQLITE_DBCONFIG_ENABLE_VIEW: i32 = 1015;
pub const SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: i32 = 1016;
pub const SQLITE_DBCONFIG_TRUSTED_SCHEMA: i32 = 1017;
pub const SQLITE_DBCONFIG_MAX: i32 = 1017;
pub const SQLITE_DENY: i32 = 1;
pub const SQLITE_IGNORE: i32 = 2;
pub const SQLITE_CREATE_INDEX: i32 = 1;
pub const SQLITE_CREATE_TABLE: i32 = 2;
pub const SQLITE_CREATE_TEMP_INDEX: i32 = 3;
pub const SQLITE_CREATE_TEMP_TABLE: i32 = 4;
pub const SQLITE_CREATE_TEMP_TRIGGER: i32 = 5;
pub const SQLITE_CREATE_TEMP_VIEW: i32 = 6;
pub const SQLITE_CREATE_TRIGGER: i32 = 7;
pub const SQLITE_CREATE_VIEW: i32 = 8;
pub const SQLITE_DELETE: i32 = 9;
pub const SQLITE_DROP_INDEX: i32 = 10;
pub const SQLITE_DROP_TABLE: i32 = 11;
pub const SQLITE_DROP_TEMP_INDEX: i32 = 12;
pub const SQLITE_DROP_TEMP_TABLE: i32 = 13;
pub const SQLITE_DROP_TEMP_TRIGGER: i32 = 14;
pub const SQLITE_DROP_TEMP_VIEW: i32 = 15;
pub const SQLITE_DROP_TRIGGER: i32 = 16;
pub const SQLITE_DROP_VIEW: i32 = 17;
pub const SQLITE_INSERT: i32 = 18;
pub const SQLITE_PRAGMA: i32 = 19;
pub const SQLITE_READ: i32 = 20;
pub const SQLITE_SELECT: i32 = 21;
pub const SQLITE_TRANSACTION: i32 = 22;
pub const SQLITE_UPDATE: i32 = 23;
pub const SQLITE_ATTACH: i32 = 24;
pub const SQLITE_DETACH: i32 = 25;
pub const SQLITE_ALTER_TABLE: i32 = 26;
pub const SQLITE_REINDEX: i32 = 27;
pub const SQLITE_ANALYZE: i32 = 28;
pub const SQLITE_CREATE_VTABLE: i32 = 29;
pub const SQLITE_DROP_VTABLE: i32 = 30;
pub const SQLITE_FUNCTION: i32 = 31;
pub const SQLITE_SAVEPOINT: i32 = 32;
pub const SQLITE_COPY: i32 = 0;
pub const SQLITE_RECURSIVE: i32 = 33;
pub const SQLITE_TRACE_STMT: i32 = 1;
pub const SQLITE_TRACE_PROFILE: i32 = 2;
pub const SQLITE_TRACE_ROW: i32 = 4;
pub const SQLITE_TRACE_CLOSE: i32 = 8;
pub const SQLITE_LIMIT_LENGTH: i32 = 0;
pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1;
pub const SQLITE_LIMIT_COLUMN: i32 = 2;
pub const SQLITE_LIMIT_EXPR_DEPTH: i32 = 3;
pub const SQLITE_LIMIT_COMPOUND_SELECT: i32 = 4;
pub const SQLITE_LIMIT_VDBE_OP: i32 = 5;
pub const SQLITE_LIMIT_FUNCTION_ARG: i32 = 6;
pub const SQLITE_LIMIT_ATTACHED: i32 = 7;
pub const SQLITE_LIMIT_LIKE_PATTERN_LENGTH: i32 = 8;
pub const SQLITE_LIMIT_VARIABLE_NUMBER: i32 = 9;
pub const SQLITE_LIMIT_TRIGGER_DEPTH: i32 = 10;
pub const SQLITE_LIMIT_WORKER_THREADS: i32 = 11;
pub const SQLITE_PREPARE_PERSISTENT: i32 = 1;
pub const SQLITE_PREPARE_NORMALIZE: i32 = 2;
pub const SQLITE_PREPARE_NO_VTAB: i32 = 4;
pub const SQLITE_INTEGER: i32 = 1;
pub const SQLITE_FLOAT: i32 = 2;
pub const SQLITE_BLOB: i32 = 4;
pub const SQLITE_NULL: i32 = 5;
pub const SQLITE_TEXT: i32 = 3;
pub const SQLITE3_TEXT: i32 = 3;
pub const SQLITE_UTF8: i32 = 1;
pub const SQLITE_UTF16LE: i32 = 2;
pub const SQLITE_UTF16BE: i32 = 3;
pub const SQLITE_UTF16: i32 = 4;
pub const SQLITE_ANY: i32 = 5;
pub const SQLITE_UTF16_ALIGNED: i32 = 8;
pub const SQLITE_DETERMINISTIC: i32 = 2048;
pub const SQLITE_DIRECTONLY: i32 = 524288;
pub const SQLITE_SUBTYPE: i32 = 1048576;
pub const SQLITE_INNOCUOUS: i32 = 2097152;
pub const SQLITE_WIN32_DATA_DIRECTORY_TYPE: i32 = 1;
pub const SQLITE_WIN32_TEMP_DIRECTORY_TYPE: i32 = 2;
pub const SQLITE_TXN_NONE: i32 = 0;
pub const SQLITE_TXN_READ: i32 = 1;
pub const SQLITE_TXN_WRITE: i32 = 2;
pub const SQLITE_INDEX_SCAN_UNIQUE: i32 = 1;
pub const SQLITE_INDEX_CONSTRAINT_EQ: i32 = 2;
pub const SQLITE_INDEX_CONSTRAINT_GT: i32 = 4;
pub const SQLITE_INDEX_CONSTRAINT_LE: i32 = 8;
pub const SQLITE_INDEX_CONSTRAINT_LT: i32 = 16;
pub const SQLITE_INDEX_CONSTRAINT_GE: i32 = 32;
pub const SQLITE_INDEX_CONSTRAINT_MATCH: i32 = 64;
pub const SQLITE_INDEX_CONSTRAINT_LIKE: i32 = 65;
pub const SQLITE_INDEX_CONSTRAINT_GLOB: i32 = 66;
pub const SQLITE_INDEX_CONSTRAINT_REGEXP: i32 = 67;
pub const SQLITE_INDEX_CONSTRAINT_NE: i32 = 68;
pub const SQLITE_INDEX_CONSTRAINT_ISNOT: i32 = 69;
pub const SQLITE_INDEX_CONSTRAINT_ISNOTNULL: i32 = 70;
pub const SQLITE_INDEX_CONSTRAINT_ISNULL: i32 = 71;
pub const SQLITE_INDEX_CONSTRAINT_IS: i32 = 72;
pub const SQLITE_INDEX_CONSTRAINT_LIMIT: i32 = 73;
pub const SQLITE_INDEX_CONSTRAINT_OFFSET: i32 = 74;
pub const SQLITE_INDEX_CONSTRAINT_FUNCTION: i32 = 150;
pub const SQLITE_MUTEX_FAST: i32 = 0;
pub const SQLITE_MUTEX_RECURSIVE: i32 = 1;
pub const SQLITE_MUTEX_STATIC_MAIN: i32 = 2;
pub const SQLITE_MUTEX_STATIC_MEM: i32 = 3;
pub const SQLITE_MUTEX_STATIC_MEM2: i32 = 4;
pub const SQLITE_MUTEX_STATIC_OPEN: i32 = 4;
pub const SQLITE_MUTEX_STATIC_PRNG: i32 = 5;
pub const SQLITE_MUTEX_STATIC_LRU: i32 = 6;
pub const SQLITE_MUTEX_STATIC_LRU2: i32 = 7;
pub const SQLITE_MUTEX_STATIC_PMEM: i32 = 7;
pub const SQLITE_MUTEX_STATIC_APP1: i32 = 8;
pub const SQLITE_MUTEX_STATIC_APP2: i32 = 9;
pub const SQLITE_MUTEX_STATIC_APP3: i32 = 10;
pub const SQLITE_MUTEX_STATIC_VFS1: i32 = 11;
pub const SQLITE_MUTEX_STATIC_VFS2: i32 = 12;
pub const SQLITE_MUTEX_STATIC_VFS3: i32 = 13;
pub const SQLITE_MUTEX_STATIC_MASTER: i32 = 2;
pub const SQLITE_TESTCTRL_FIRST: i32 = 5;
pub const SQLITE_TESTCTRL_PRNG_SAVE: i32 = 5;
pub const SQLITE_TESTCTRL_PRNG_RESTORE: i32 = 6;
pub const SQLITE_TESTCTRL_PRNG_RESET: i32 = 7;
pub const SQLITE_TESTCTRL_BITVEC_TEST: i32 = 8;
pub const SQLITE_TESTCTRL_FAULT_INSTALL: i32 = 9;
pub const SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: i32 = 10;
pub const SQLITE_TESTCTRL_PENDING_BYTE: i32 = 11;
pub const SQLITE_TESTCTRL_ASSERT: i32 = 12;
pub const SQLITE_TESTCTRL_ALWAYS: i32 = 13;
pub const SQLITE_TESTCTRL_RESERVE: i32 = 14;
pub const SQLITE_TESTCTRL_OPTIMIZATIONS: i32 = 15;
pub const SQLITE_TESTCTRL_ISKEYWORD: i32 = 16;
pub const SQLITE_TESTCTRL_SCRATCHMALLOC: i32 = 17;
pub const SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: i32 = 17;
pub const SQLITE_TESTCTRL_LOCALTIME_FAULT: i32 = 18;
pub const SQLITE_TESTCTRL_EXPLAIN_STMT: i32 = 19;
pub const SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: i32 = 19;
pub const SQLITE_TESTCTRL_NEVER_CORRUPT: i32 = 20;
pub const SQLITE_TESTCTRL_VDBE_COVERAGE: i32 = 21;
pub const SQLITE_TESTCTRL_BYTEORDER: i32 = 22;
pub const SQLITE_TESTCTRL_ISINIT: i32 = 23;
pub const SQLITE_TESTCTRL_SORTER_MMAP: i32 = 24;
pub const SQLITE_TESTCTRL_IMPOSTER: i32 = 25;
pub const SQLITE_TESTCTRL_PARSER_COVERAGE: i32 = 26;
pub const SQLITE_TESTCTRL_RESULT_INTREAL: i32 = 27;
pub const SQLITE_TESTCTRL_PRNG_SEED: i32 = 28;
pub const SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: i32 = 29;
pub const SQLITE_TESTCTRL_SEEK_COUNT: i32 = 30;
pub const SQLITE_TESTCTRL_TRACEFLAGS: i32 = 31;
pub const SQLITE_TESTCTRL_TUNE: i32 = 32;
pub const SQLITE_TESTCTRL_LOGEST: i32 = 33;
pub const SQLITE_TESTCTRL_LAST: i32 = 33;
pub const SQLITE_STATUS_MEMORY_USED: i32 = 0;
pub const SQLITE_STATUS_PAGECACHE_USED: i32 = 1;
pub const SQLITE_STATUS_PAGECACHE_OVERFLOW: i32 = 2;
pub const SQLITE_STATUS_SCRATCH_USED: i32 = 3;
pub const SQLITE_STATUS_SCRATCH_OVERFLOW: i32 = 4;
pub const SQLITE_STATUS_MALLOC_SIZE: i32 = 5;
pub const SQLITE_STATUS_PARSER_STACK: i32 = 6;
pub const SQLITE_STATUS_PAGECACHE_SIZE: i32 = 7;
pub const SQLITE_STATUS_SCRATCH_SIZE: i32 = 8;
pub const SQLITE_STATUS_MALLOC_COUNT: i32 = 9;
pub const SQLITE_DBSTATUS_LOOKASIDE_USED: i32 = 0;
pub const SQLITE_DBSTATUS_CACHE_USED: i32 = 1;
pub const SQLITE_DBSTATUS_SCHEMA_USED: i32 = 2;
pub const SQLITE_DBSTATUS_STMT_USED: i32 = 3;
pub const SQLITE_DBSTATUS_LOOKASIDE_HIT: i32 = 4;
pub const SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: i32 = 5;
pub const SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: i32 = 6;
pub const SQLITE_DBSTATUS_CACHE_HIT: i32 = 7;
pub const SQLITE_DBSTATUS_CACHE_MISS: i32 = 8;
pub const SQLITE_DBSTATUS_CACHE_WRITE: i32 = 9;
pub const SQLITE_DBSTATUS_DEFERRED_FKS: i32 = 10;
pub const SQLITE_DBSTATUS_CACHE_USED_SHARED: i32 = 11;
pub const SQLITE_DBSTATUS_CACHE_SPILL: i32 = 12;
pub const SQLITE_DBSTATUS_MAX: i32 = 12;
pub const SQLITE_STMTSTATUS_FULLSCAN_STEP: i32 = 1;
pub const SQLITE_STMTSTATUS_SORT: i32 = 2;
pub const SQLITE_STMTSTATUS_AUTOINDEX: i32 = 3;
pub const SQLITE_STMTSTATUS_VM_STEP: i32 = 4;
pub const SQLITE_STMTSTATUS_REPREPARE: i32 = 5;
pub const SQLITE_STMTSTATUS_RUN: i32 = 6;
pub const SQLITE_STMTSTATUS_FILTER_MISS: i32 = 7;
pub const SQLITE_STMTSTATUS_FILTER_HIT: i32 = 8;
pub const SQLITE_STMTSTATUS_MEMUSED: i32 = 99;
pub const SQLITE_CHECKPOINT_PASSIVE: i32 = 0;
pub const SQLITE_CHECKPOINT_FULL: i32 = 1;
pub const SQLITE_CHECKPOINT_RESTART: i32 = 2;
pub const SQLITE_CHECKPOINT_TRUNCATE: i32 = 3;
pub const SQLITE_VTAB_CONSTRAINT_SUPPORT: i32 = 1;
pub const SQLITE_VTAB_INNOCUOUS: i32 = 2;
pub const SQLITE_VTAB_DIRECTONLY: i32 = 3;
pub const SQLITE_ROLLBACK: i32 = 1;
pub const SQLITE_FAIL: i32 = 3;
pub const SQLITE_REPLACE: i32 = 5;
pub const SQLITE_SCANSTAT_NLOOP: i32 = 0;
pub const SQLITE_SCANSTAT_NVISIT: i32 = 1;
pub const SQLITE_SCANSTAT_EST: i32 = 2;
pub const SQLITE_SCANSTAT_NAME: i32 = 3;
pub const SQLITE_SCANSTAT_EXPLAIN: i32 = 4;
pub const SQLITE_SCANSTAT_SELECTID: i32 = 5;
pub const SQLITE_SCANSTAT_PARENTID: i32 = 6;
pub const SQLITE_SCANSTAT_NCYCLE: i32 = 7;
pub const SQLITE_SCANSTAT_COMPLEX: i32 = 1;
pub const SQLITE_SERIALIZE_NOCOPY: i32 = 1;
pub const SQLITE_DESERIALIZE_FREEONCLOSE: i32 = 1;
pub const SQLITE_DESERIALIZE_RESIZEABLE: i32 = 2;
pub const SQLITE_DESERIALIZE_READONLY: i32 = 4;
pub const NOT_WITHIN: i32 = 0;
pub const PARTLY_WITHIN: i32 = 1;
pub const FULLY_WITHIN: i32 = 2;
pub const __SQLITESESSION_H_: i32 = 1;
pub const SQLITE_SESSION_OBJCONFIG_SIZE: i32 = 1;
pub const SQLITE_CHANGESETSTART_INVERT: i32 = 2;
pub const SQLITE_CHANGESETAPPLY_NOSAVEPOINT: i32 = 1;
pub const SQLITE_CHANGESETAPPLY_INVERT: i32 = 2;
pub const SQLITE_CHANGESET_DATA: i32 = 1;
pub const SQLITE_CHANGESET_NOTFOUND: i32 = 2;
pub const SQLITE_CHANGESET_CONFLICT: i32 = 3;
pub const SQLITE_CHANGESET_CONSTRAINT: i32 = 4;
pub const SQLITE_CHANGESET_FOREIGN_KEY: i32 = 5;
pub const SQLITE_CHANGESET_OMIT: i32 = 0;
pub const SQLITE_CHANGESET_REPLACE: i32 = 1;
pub const SQLITE_CHANGESET_ABORT: i32 = 2;
pub const SQLITE_SESSION_CONFIG_STRMSIZE: i32 = 1;
pub const FTS5_TOKENIZE_QUERY: i32 = 1;
pub const FTS5_TOKENIZE_PREFIX: i32 = 2;
pub const FTS5_TOKENIZE_DOCUMENT: i32 = 4;
pub const FTS5_TOKENIZE_AUX: i32 = 8;
pub const FTS5_TOKEN_COLOCATED: i32 = 1;
extern "C" {
pub static sqlite3_version: [::std::os::raw::c_char; 0usize];
}
extern "C" {
pub fn sqlite3_libversion() -> *const ::std::os::raw::c_char;
}
extern "C" {
pub fn sqlite3_sourceid() -> *const ::std::os::raw::c_char;
}
extern "C" {
pub fn sqlite3_libversion_number() -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_compileoption_used(
zOptName: *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_compileoption_get(N: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char;
}
extern "C" {
pub fn sqlite3_threadsafe() -> ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct sqlite3 {
_unused: [u8; 0],
}
pub type sqlite_int64 = ::std::os::raw::c_longlong;
pub type sqlite_uint64 = ::std::os::raw::c_ulonglong;
pub type sqlite3_int64 = sqlite_int64;
pub type sqlite3_uint64 = sqlite_uint64;
extern "C" {
pub fn sqlite3_close(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_close_v2(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
}
pub type sqlite3_callback = ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut ::std::os::raw::c_char,
arg4: *mut *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int,
>;
extern "C" {
pub fn sqlite3_exec(
arg1: *mut sqlite3,
sql: *const ::std::os::raw::c_char,
callback: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut ::std::os::raw::c_char,
arg4: *mut *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int,
>,
arg2: *mut ::std::os::raw::c_void,
errmsg: *mut *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sqlite3_file { pub struct sqlite3_file {
@ -678,6 +356,50 @@ pub struct sqlite3_io_methods {
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
>, >,
} }
pub const SQLITE_FCNTL_LOCKSTATE: i32 = 1;
pub const SQLITE_FCNTL_GET_LOCKPROXYFILE: i32 = 2;
pub const SQLITE_FCNTL_SET_LOCKPROXYFILE: i32 = 3;
pub const SQLITE_FCNTL_LAST_ERRNO: i32 = 4;
pub const SQLITE_FCNTL_SIZE_HINT: i32 = 5;
pub const SQLITE_FCNTL_CHUNK_SIZE: i32 = 6;
pub const SQLITE_FCNTL_FILE_POINTER: i32 = 7;
pub const SQLITE_FCNTL_SYNC_OMITTED: i32 = 8;
pub const SQLITE_FCNTL_WIN32_AV_RETRY: i32 = 9;
pub const SQLITE_FCNTL_PERSIST_WAL: i32 = 10;
pub const SQLITE_FCNTL_OVERWRITE: i32 = 11;
pub const SQLITE_FCNTL_VFSNAME: i32 = 12;
pub const SQLITE_FCNTL_POWERSAFE_OVERWRITE: i32 = 13;
pub const SQLITE_FCNTL_PRAGMA: i32 = 14;
pub const SQLITE_FCNTL_BUSYHANDLER: i32 = 15;
pub const SQLITE_FCNTL_TEMPFILENAME: i32 = 16;
pub const SQLITE_FCNTL_MMAP_SIZE: i32 = 18;
pub const SQLITE_FCNTL_TRACE: i32 = 19;
pub const SQLITE_FCNTL_HAS_MOVED: i32 = 20;
pub const SQLITE_FCNTL_SYNC: i32 = 21;
pub const SQLITE_FCNTL_COMMIT_PHASETWO: i32 = 22;
pub const SQLITE_FCNTL_WIN32_SET_HANDLE: i32 = 23;
pub const SQLITE_FCNTL_WAL_BLOCK: i32 = 24;
pub const SQLITE_FCNTL_ZIPVFS: i32 = 25;
pub const SQLITE_FCNTL_RBU: i32 = 26;
pub const SQLITE_FCNTL_VFS_POINTER: i32 = 27;
pub const SQLITE_FCNTL_JOURNAL_POINTER: i32 = 28;
pub const SQLITE_FCNTL_WIN32_GET_HANDLE: i32 = 29;
pub const SQLITE_FCNTL_PDB: i32 = 30;
pub const SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: i32 = 31;
pub const SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: i32 = 32;
pub const SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: i32 = 33;
pub const SQLITE_FCNTL_LOCK_TIMEOUT: i32 = 34;
pub const SQLITE_FCNTL_DATA_VERSION: i32 = 35;
pub const SQLITE_FCNTL_SIZE_LIMIT: i32 = 36;
pub const SQLITE_FCNTL_CKPT_DONE: i32 = 37;
pub const SQLITE_FCNTL_RESERVE_BYTES: i32 = 38;
pub const SQLITE_FCNTL_CKPT_START: i32 = 39;
pub const SQLITE_FCNTL_EXTERNAL_READER: i32 = 40;
pub const SQLITE_FCNTL_CKSM_FILE: i32 = 41;
pub const SQLITE_FCNTL_RESET_CACHE: i32 = 42;
pub const SQLITE_GET_LOCKPROXYFILE: i32 = 2;
pub const SQLITE_SET_LOCKPROXYFILE: i32 = 3;
pub const SQLITE_LAST_ERRNO: i32 = 4;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sqlite3_mutex { pub struct sqlite3_mutex {
@ -809,6 +531,14 @@ pub struct sqlite3_vfs {
) -> *const ::std::os::raw::c_char, ) -> *const ::std::os::raw::c_char,
>, >,
} }
pub const SQLITE_ACCESS_EXISTS: i32 = 0;
pub const SQLITE_ACCESS_READWRITE: i32 = 1;
pub const SQLITE_ACCESS_READ: i32 = 2;
pub const SQLITE_SHM_UNLOCK: i32 = 1;
pub const SQLITE_SHM_LOCK: i32 = 2;
pub const SQLITE_SHM_SHARED: i32 = 4;
pub const SQLITE_SHM_EXCLUSIVE: i32 = 8;
pub const SQLITE_SHM_NLOCK: i32 = 8;
extern "C" { extern "C" {
pub fn sqlite3_initialize() -> ::std::os::raw::c_int; pub fn sqlite3_initialize() -> ::std::os::raw::c_int;
} }
@ -856,6 +586,55 @@ pub struct sqlite3_mem_methods {
pub xShutdown: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>, pub xShutdown: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
pub pAppData: *mut ::std::os::raw::c_void, pub pAppData: *mut ::std::os::raw::c_void,
} }
pub const SQLITE_CONFIG_SINGLETHREAD: i32 = 1;
pub const SQLITE_CONFIG_MULTITHREAD: i32 = 2;
pub const SQLITE_CONFIG_SERIALIZED: i32 = 3;
pub const SQLITE_CONFIG_MALLOC: i32 = 4;
pub const SQLITE_CONFIG_GETMALLOC: i32 = 5;
pub const SQLITE_CONFIG_SCRATCH: i32 = 6;
pub const SQLITE_CONFIG_PAGECACHE: i32 = 7;
pub const SQLITE_CONFIG_HEAP: i32 = 8;
pub const SQLITE_CONFIG_MEMSTATUS: i32 = 9;
pub const SQLITE_CONFIG_MUTEX: i32 = 10;
pub const SQLITE_CONFIG_GETMUTEX: i32 = 11;
pub const SQLITE_CONFIG_LOOKASIDE: i32 = 13;
pub const SQLITE_CONFIG_PCACHE: i32 = 14;
pub const SQLITE_CONFIG_GETPCACHE: i32 = 15;
pub const SQLITE_CONFIG_LOG: i32 = 16;
pub const SQLITE_CONFIG_URI: i32 = 17;
pub const SQLITE_CONFIG_PCACHE2: i32 = 18;
pub const SQLITE_CONFIG_GETPCACHE2: i32 = 19;
pub const SQLITE_CONFIG_COVERING_INDEX_SCAN: i32 = 20;
pub const SQLITE_CONFIG_SQLLOG: i32 = 21;
pub const SQLITE_CONFIG_MMAP_SIZE: i32 = 22;
pub const SQLITE_CONFIG_WIN32_HEAPSIZE: i32 = 23;
pub const SQLITE_CONFIG_PCACHE_HDRSZ: i32 = 24;
pub const SQLITE_CONFIG_PMASZ: i32 = 25;
pub const SQLITE_CONFIG_STMTJRNL_SPILL: i32 = 26;
pub const SQLITE_CONFIG_SMALL_MALLOC: i32 = 27;
pub const SQLITE_CONFIG_SORTERREF_SIZE: i32 = 28;
pub const SQLITE_CONFIG_MEMDB_MAXSIZE: i32 = 29;
pub const SQLITE_DBCONFIG_MAINDBNAME: i32 = 1000;
pub const SQLITE_DBCONFIG_LOOKASIDE: i32 = 1001;
pub const SQLITE_DBCONFIG_ENABLE_FKEY: i32 = 1002;
pub const SQLITE_DBCONFIG_ENABLE_TRIGGER: i32 = 1003;
pub const SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: i32 = 1004;
pub const SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: i32 = 1005;
pub const SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: i32 = 1006;
pub const SQLITE_DBCONFIG_ENABLE_QPSG: i32 = 1007;
pub const SQLITE_DBCONFIG_TRIGGER_EQP: i32 = 1008;
pub const SQLITE_DBCONFIG_RESET_DATABASE: i32 = 1009;
pub const SQLITE_DBCONFIG_DEFENSIVE: i32 = 1010;
pub const SQLITE_DBCONFIG_WRITABLE_SCHEMA: i32 = 1011;
pub const SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: i32 = 1012;
pub const SQLITE_DBCONFIG_DQS_DML: i32 = 1013;
pub const SQLITE_DBCONFIG_DQS_DDL: i32 = 1014;
pub const SQLITE_DBCONFIG_ENABLE_VIEW: i32 = 1015;
pub const SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: i32 = 1016;
pub const SQLITE_DBCONFIG_TRUSTED_SCHEMA: i32 = 1017;
pub const SQLITE_DBCONFIG_STMT_SCANSTATUS: i32 = 1018;
pub const SQLITE_DBCONFIG_REVERSE_SCANORDER: i32 = 1019;
pub const SQLITE_DBCONFIG_MAX: i32 = 1019;
extern "C" { extern "C" {
pub fn sqlite3_extended_result_codes( pub fn sqlite3_extended_result_codes(
arg1: *mut sqlite3, arg1: *mut sqlite3,
@ -984,6 +763,42 @@ extern "C" {
pUserData: *mut ::std::os::raw::c_void, pUserData: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_DENY: i32 = 1;
pub const SQLITE_IGNORE: i32 = 2;
pub const SQLITE_CREATE_INDEX: i32 = 1;
pub const SQLITE_CREATE_TABLE: i32 = 2;
pub const SQLITE_CREATE_TEMP_INDEX: i32 = 3;
pub const SQLITE_CREATE_TEMP_TABLE: i32 = 4;
pub const SQLITE_CREATE_TEMP_TRIGGER: i32 = 5;
pub const SQLITE_CREATE_TEMP_VIEW: i32 = 6;
pub const SQLITE_CREATE_TRIGGER: i32 = 7;
pub const SQLITE_CREATE_VIEW: i32 = 8;
pub const SQLITE_DELETE: i32 = 9;
pub const SQLITE_DROP_INDEX: i32 = 10;
pub const SQLITE_DROP_TABLE: i32 = 11;
pub const SQLITE_DROP_TEMP_INDEX: i32 = 12;
pub const SQLITE_DROP_TEMP_TABLE: i32 = 13;
pub const SQLITE_DROP_TEMP_TRIGGER: i32 = 14;
pub const SQLITE_DROP_TEMP_VIEW: i32 = 15;
pub const SQLITE_DROP_TRIGGER: i32 = 16;
pub const SQLITE_DROP_VIEW: i32 = 17;
pub const SQLITE_INSERT: i32 = 18;
pub const SQLITE_PRAGMA: i32 = 19;
pub const SQLITE_READ: i32 = 20;
pub const SQLITE_SELECT: i32 = 21;
pub const SQLITE_TRANSACTION: i32 = 22;
pub const SQLITE_UPDATE: i32 = 23;
pub const SQLITE_ATTACH: i32 = 24;
pub const SQLITE_DETACH: i32 = 25;
pub const SQLITE_ALTER_TABLE: i32 = 26;
pub const SQLITE_REINDEX: i32 = 27;
pub const SQLITE_ANALYZE: i32 = 28;
pub const SQLITE_CREATE_VTABLE: i32 = 29;
pub const SQLITE_DROP_VTABLE: i32 = 30;
pub const SQLITE_FUNCTION: i32 = 31;
pub const SQLITE_SAVEPOINT: i32 = 32;
pub const SQLITE_COPY: i32 = 0;
pub const SQLITE_RECURSIVE: i32 = 33;
extern "C" { extern "C" {
pub fn sqlite3_trace( pub fn sqlite3_trace(
arg1: *mut sqlite3, arg1: *mut sqlite3,
@ -1009,6 +824,10 @@ extern "C" {
arg2: *mut ::std::os::raw::c_void, arg2: *mut ::std::os::raw::c_void,
) -> *mut ::std::os::raw::c_void; ) -> *mut ::std::os::raw::c_void;
} }
pub const SQLITE_TRACE_STMT: i32 = 1;
pub const SQLITE_TRACE_PROFILE: i32 = 2;
pub const SQLITE_TRACE_ROW: i32 = 4;
pub const SQLITE_TRACE_CLOSE: i32 = 8;
extern "C" { extern "C" {
pub fn sqlite3_trace_v2( pub fn sqlite3_trace_v2(
arg1: *mut sqlite3, arg1: *mut sqlite3,
@ -1134,6 +953,21 @@ extern "C" {
newVal: ::std::os::raw::c_int, newVal: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_LIMIT_LENGTH: i32 = 0;
pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1;
pub const SQLITE_LIMIT_COLUMN: i32 = 2;
pub const SQLITE_LIMIT_EXPR_DEPTH: i32 = 3;
pub const SQLITE_LIMIT_COMPOUND_SELECT: i32 = 4;
pub const SQLITE_LIMIT_VDBE_OP: i32 = 5;
pub const SQLITE_LIMIT_FUNCTION_ARG: i32 = 6;
pub const SQLITE_LIMIT_ATTACHED: i32 = 7;
pub const SQLITE_LIMIT_LIKE_PATTERN_LENGTH: i32 = 8;
pub const SQLITE_LIMIT_VARIABLE_NUMBER: i32 = 9;
pub const SQLITE_LIMIT_TRIGGER_DEPTH: i32 = 10;
pub const SQLITE_LIMIT_WORKER_THREADS: i32 = 11;
pub const SQLITE_PREPARE_PERSISTENT: ::std::os::raw::c_uint = 1;
pub const SQLITE_PREPARE_NORMALIZE: ::std::os::raw::c_uint = 2;
pub const SQLITE_PREPARE_NO_VTAB: ::std::os::raw::c_uint = 4;
extern "C" { extern "C" {
pub fn sqlite3_prepare( pub fn sqlite3_prepare(
db: *mut sqlite3, db: *mut sqlite3,
@ -1405,6 +1239,12 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_data_count(pStmt: *mut sqlite3_stmt) -> ::std::os::raw::c_int; pub fn sqlite3_data_count(pStmt: *mut sqlite3_stmt) -> ::std::os::raw::c_int;
} }
pub const SQLITE_INTEGER: i32 = 1;
pub const SQLITE_FLOAT: i32 = 2;
pub const SQLITE_BLOB: i32 = 4;
pub const SQLITE_NULL: i32 = 5;
pub const SQLITE_TEXT: i32 = 3;
pub const SQLITE3_TEXT: i32 = 3;
extern "C" { extern "C" {
pub fn sqlite3_column_blob( pub fn sqlite3_column_blob(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
@ -1567,6 +1407,16 @@ extern "C" {
xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>, xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_UTF8: i32 = 1;
pub const SQLITE_UTF16LE: i32 = 2;
pub const SQLITE_UTF16BE: i32 = 3;
pub const SQLITE_UTF16: i32 = 4;
pub const SQLITE_ANY: i32 = 5;
pub const SQLITE_UTF16_ALIGNED: i32 = 8;
pub const SQLITE_DETERMINISTIC: i32 = 2048;
pub const SQLITE_DIRECTONLY: i32 = 524288;
pub const SQLITE_SUBTYPE: i32 = 1048576;
pub const SQLITE_INNOCUOUS: i32 = 2097152;
extern "C" { extern "C" {
pub fn sqlite3_aggregate_count(arg1: *mut sqlite3_context) -> ::std::os::raw::c_int; pub fn sqlite3_aggregate_count(arg1: *mut sqlite3_context) -> ::std::os::raw::c_int;
} }
@ -1908,6 +1758,8 @@ extern "C" {
zValue: *const ::std::os::raw::c_void, zValue: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_WIN32_DATA_DIRECTORY_TYPE: i32 = 1;
pub const SQLITE_WIN32_TEMP_DIRECTORY_TYPE: i32 = 2;
extern "C" { extern "C" {
pub fn sqlite3_get_autocommit(arg1: *mut sqlite3) -> ::std::os::raw::c_int; pub fn sqlite3_get_autocommit(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
} }
@ -1938,6 +1790,9 @@ extern "C" {
zSchema: *const ::std::os::raw::c_char, zSchema: *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_TXN_NONE: i32 = 0;
pub const SQLITE_TXN_READ: i32 = 1;
pub const SQLITE_TXN_WRITE: i32 = 2;
extern "C" { extern "C" {
pub fn sqlite3_next_stmt(pDb: *mut sqlite3, pStmt: *mut sqlite3_stmt) -> *mut sqlite3_stmt; pub fn sqlite3_next_stmt(pDb: *mut sqlite3, pStmt: *mut sqlite3_stmt) -> *mut sqlite3_stmt;
} }
@ -2209,6 +2064,24 @@ pub struct sqlite3_index_constraint_usage {
pub argvIndex: ::std::os::raw::c_int, pub argvIndex: ::std::os::raw::c_int,
pub omit: ::std::os::raw::c_uchar, pub omit: ::std::os::raw::c_uchar,
} }
pub const SQLITE_INDEX_SCAN_UNIQUE: i32 = 1;
pub const SQLITE_INDEX_CONSTRAINT_EQ: i32 = 2;
pub const SQLITE_INDEX_CONSTRAINT_GT: i32 = 4;
pub const SQLITE_INDEX_CONSTRAINT_LE: i32 = 8;
pub const SQLITE_INDEX_CONSTRAINT_LT: i32 = 16;
pub const SQLITE_INDEX_CONSTRAINT_GE: i32 = 32;
pub const SQLITE_INDEX_CONSTRAINT_MATCH: i32 = 64;
pub const SQLITE_INDEX_CONSTRAINT_LIKE: i32 = 65;
pub const SQLITE_INDEX_CONSTRAINT_GLOB: i32 = 66;
pub const SQLITE_INDEX_CONSTRAINT_REGEXP: i32 = 67;
pub const SQLITE_INDEX_CONSTRAINT_NE: i32 = 68;
pub const SQLITE_INDEX_CONSTRAINT_ISNOT: i32 = 69;
pub const SQLITE_INDEX_CONSTRAINT_ISNOTNULL: i32 = 70;
pub const SQLITE_INDEX_CONSTRAINT_ISNULL: i32 = 71;
pub const SQLITE_INDEX_CONSTRAINT_IS: i32 = 72;
pub const SQLITE_INDEX_CONSTRAINT_LIMIT: i32 = 73;
pub const SQLITE_INDEX_CONSTRAINT_OFFSET: i32 = 74;
pub const SQLITE_INDEX_CONSTRAINT_FUNCTION: i32 = 150;
extern "C" { extern "C" {
pub fn sqlite3_create_module( pub fn sqlite3_create_module(
db: *mut sqlite3, db: *mut sqlite3,
@ -2355,6 +2228,23 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_mutex_notheld(arg1: *mut sqlite3_mutex) -> ::std::os::raw::c_int; pub fn sqlite3_mutex_notheld(arg1: *mut sqlite3_mutex) -> ::std::os::raw::c_int;
} }
pub const SQLITE_MUTEX_FAST: i32 = 0;
pub const SQLITE_MUTEX_RECURSIVE: i32 = 1;
pub const SQLITE_MUTEX_STATIC_MAIN: i32 = 2;
pub const SQLITE_MUTEX_STATIC_MEM: i32 = 3;
pub const SQLITE_MUTEX_STATIC_MEM2: i32 = 4;
pub const SQLITE_MUTEX_STATIC_OPEN: i32 = 4;
pub const SQLITE_MUTEX_STATIC_PRNG: i32 = 5;
pub const SQLITE_MUTEX_STATIC_LRU: i32 = 6;
pub const SQLITE_MUTEX_STATIC_LRU2: i32 = 7;
pub const SQLITE_MUTEX_STATIC_PMEM: i32 = 7;
pub const SQLITE_MUTEX_STATIC_APP1: i32 = 8;
pub const SQLITE_MUTEX_STATIC_APP2: i32 = 9;
pub const SQLITE_MUTEX_STATIC_APP3: i32 = 10;
pub const SQLITE_MUTEX_STATIC_VFS1: i32 = 11;
pub const SQLITE_MUTEX_STATIC_VFS2: i32 = 12;
pub const SQLITE_MUTEX_STATIC_VFS3: i32 = 13;
pub const SQLITE_MUTEX_STATIC_MASTER: i32 = 2;
extern "C" { extern "C" {
pub fn sqlite3_db_mutex(arg1: *mut sqlite3) -> *mut sqlite3_mutex; pub fn sqlite3_db_mutex(arg1: *mut sqlite3) -> *mut sqlite3_mutex;
} }
@ -2369,6 +2259,39 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_test_control(op: ::std::os::raw::c_int, ...) -> ::std::os::raw::c_int; pub fn sqlite3_test_control(op: ::std::os::raw::c_int, ...) -> ::std::os::raw::c_int;
} }
pub const SQLITE_TESTCTRL_FIRST: i32 = 5;
pub const SQLITE_TESTCTRL_PRNG_SAVE: i32 = 5;
pub const SQLITE_TESTCTRL_PRNG_RESTORE: i32 = 6;
pub const SQLITE_TESTCTRL_PRNG_RESET: i32 = 7;
pub const SQLITE_TESTCTRL_BITVEC_TEST: i32 = 8;
pub const SQLITE_TESTCTRL_FAULT_INSTALL: i32 = 9;
pub const SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: i32 = 10;
pub const SQLITE_TESTCTRL_PENDING_BYTE: i32 = 11;
pub const SQLITE_TESTCTRL_ASSERT: i32 = 12;
pub const SQLITE_TESTCTRL_ALWAYS: i32 = 13;
pub const SQLITE_TESTCTRL_RESERVE: i32 = 14;
pub const SQLITE_TESTCTRL_OPTIMIZATIONS: i32 = 15;
pub const SQLITE_TESTCTRL_ISKEYWORD: i32 = 16;
pub const SQLITE_TESTCTRL_SCRATCHMALLOC: i32 = 17;
pub const SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: i32 = 17;
pub const SQLITE_TESTCTRL_LOCALTIME_FAULT: i32 = 18;
pub const SQLITE_TESTCTRL_EXPLAIN_STMT: i32 = 19;
pub const SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: i32 = 19;
pub const SQLITE_TESTCTRL_NEVER_CORRUPT: i32 = 20;
pub const SQLITE_TESTCTRL_VDBE_COVERAGE: i32 = 21;
pub const SQLITE_TESTCTRL_BYTEORDER: i32 = 22;
pub const SQLITE_TESTCTRL_ISINIT: i32 = 23;
pub const SQLITE_TESTCTRL_SORTER_MMAP: i32 = 24;
pub const SQLITE_TESTCTRL_IMPOSTER: i32 = 25;
pub const SQLITE_TESTCTRL_PARSER_COVERAGE: i32 = 26;
pub const SQLITE_TESTCTRL_RESULT_INTREAL: i32 = 27;
pub const SQLITE_TESTCTRL_PRNG_SEED: i32 = 28;
pub const SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: i32 = 29;
pub const SQLITE_TESTCTRL_SEEK_COUNT: i32 = 30;
pub const SQLITE_TESTCTRL_TRACEFLAGS: i32 = 31;
pub const SQLITE_TESTCTRL_TUNE: i32 = 32;
pub const SQLITE_TESTCTRL_LOGEST: i32 = 33;
pub const SQLITE_TESTCTRL_LAST: i32 = 33;
extern "C" { extern "C" {
pub fn sqlite3_keyword_count() -> ::std::os::raw::c_int; pub fn sqlite3_keyword_count() -> ::std::os::raw::c_int;
} }
@ -2444,6 +2367,16 @@ extern "C" {
resetFlag: ::std::os::raw::c_int, resetFlag: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_STATUS_MEMORY_USED: i32 = 0;
pub const SQLITE_STATUS_PAGECACHE_USED: i32 = 1;
pub const SQLITE_STATUS_PAGECACHE_OVERFLOW: i32 = 2;
pub const SQLITE_STATUS_SCRATCH_USED: i32 = 3;
pub const SQLITE_STATUS_SCRATCH_OVERFLOW: i32 = 4;
pub const SQLITE_STATUS_MALLOC_SIZE: i32 = 5;
pub const SQLITE_STATUS_PARSER_STACK: i32 = 6;
pub const SQLITE_STATUS_PAGECACHE_SIZE: i32 = 7;
pub const SQLITE_STATUS_SCRATCH_SIZE: i32 = 8;
pub const SQLITE_STATUS_MALLOC_COUNT: i32 = 9;
extern "C" { extern "C" {
pub fn sqlite3_db_status( pub fn sqlite3_db_status(
arg1: *mut sqlite3, arg1: *mut sqlite3,
@ -2453,6 +2386,20 @@ extern "C" {
resetFlg: ::std::os::raw::c_int, resetFlg: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_DBSTATUS_LOOKASIDE_USED: i32 = 0;
pub const SQLITE_DBSTATUS_CACHE_USED: i32 = 1;
pub const SQLITE_DBSTATUS_SCHEMA_USED: i32 = 2;
pub const SQLITE_DBSTATUS_STMT_USED: i32 = 3;
pub const SQLITE_DBSTATUS_LOOKASIDE_HIT: i32 = 4;
pub const SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: i32 = 5;
pub const SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: i32 = 6;
pub const SQLITE_DBSTATUS_CACHE_HIT: i32 = 7;
pub const SQLITE_DBSTATUS_CACHE_MISS: i32 = 8;
pub const SQLITE_DBSTATUS_CACHE_WRITE: i32 = 9;
pub const SQLITE_DBSTATUS_DEFERRED_FKS: i32 = 10;
pub const SQLITE_DBSTATUS_CACHE_USED_SHARED: i32 = 11;
pub const SQLITE_DBSTATUS_CACHE_SPILL: i32 = 12;
pub const SQLITE_DBSTATUS_MAX: i32 = 12;
extern "C" { extern "C" {
pub fn sqlite3_stmt_status( pub fn sqlite3_stmt_status(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
@ -2460,6 +2407,15 @@ extern "C" {
resetFlg: ::std::os::raw::c_int, resetFlg: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_STMTSTATUS_FULLSCAN_STEP: i32 = 1;
pub const SQLITE_STMTSTATUS_SORT: i32 = 2;
pub const SQLITE_STMTSTATUS_AUTOINDEX: i32 = 3;
pub const SQLITE_STMTSTATUS_VM_STEP: i32 = 4;
pub const SQLITE_STMTSTATUS_REPREPARE: i32 = 5;
pub const SQLITE_STMTSTATUS_RUN: i32 = 6;
pub const SQLITE_STMTSTATUS_FILTER_MISS: i32 = 7;
pub const SQLITE_STMTSTATUS_FILTER_HIT: i32 = 8;
pub const SQLITE_STMTSTATUS_MEMUSED: i32 = 99;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sqlite3_pcache { pub struct sqlite3_pcache {
@ -2676,6 +2632,10 @@ extern "C" {
pnCkpt: *mut ::std::os::raw::c_int, pnCkpt: *mut ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_CHECKPOINT_PASSIVE: i32 = 0;
pub const SQLITE_CHECKPOINT_FULL: i32 = 1;
pub const SQLITE_CHECKPOINT_RESTART: i32 = 2;
pub const SQLITE_CHECKPOINT_TRUNCATE: i32 = 3;
extern "C" { extern "C" {
pub fn sqlite3_vtab_config( pub fn sqlite3_vtab_config(
arg1: *mut sqlite3, arg1: *mut sqlite3,
@ -2683,6 +2643,10 @@ extern "C" {
... ...
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_VTAB_CONSTRAINT_SUPPORT: i32 = 1;
pub const SQLITE_VTAB_INNOCUOUS: i32 = 2;
pub const SQLITE_VTAB_DIRECTONLY: i32 = 3;
pub const SQLITE_VTAB_USES_ALL_SCHEMAS: i32 = 4;
extern "C" { extern "C" {
pub fn sqlite3_vtab_on_conflict(arg1: *mut sqlite3) -> ::std::os::raw::c_int; pub fn sqlite3_vtab_on_conflict(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
} }
@ -2724,6 +2688,17 @@ extern "C" {
ppVal: *mut *mut sqlite3_value, ppVal: *mut *mut sqlite3_value,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_ROLLBACK: i32 = 1;
pub const SQLITE_FAIL: i32 = 3;
pub const SQLITE_REPLACE: i32 = 5;
pub const SQLITE_SCANSTAT_NLOOP: i32 = 0;
pub const SQLITE_SCANSTAT_NVISIT: i32 = 1;
pub const SQLITE_SCANSTAT_EST: i32 = 2;
pub const SQLITE_SCANSTAT_NAME: i32 = 3;
pub const SQLITE_SCANSTAT_EXPLAIN: i32 = 4;
pub const SQLITE_SCANSTAT_SELECTID: i32 = 5;
pub const SQLITE_SCANSTAT_PARENTID: i32 = 6;
pub const SQLITE_SCANSTAT_NCYCLE: i32 = 7;
extern "C" { extern "C" {
pub fn sqlite3_stmt_scanstatus( pub fn sqlite3_stmt_scanstatus(
pStmt: *mut sqlite3_stmt, pStmt: *mut sqlite3_stmt,
@ -2741,6 +2716,7 @@ extern "C" {
pOut: *mut ::std::os::raw::c_void, pOut: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_SCANSTAT_COMPLEX: i32 = 1;
extern "C" { extern "C" {
pub fn sqlite3_stmt_scanstatus_reset(arg1: *mut sqlite3_stmt); pub fn sqlite3_stmt_scanstatus_reset(arg1: *mut sqlite3_stmt);
} }
@ -2832,6 +2808,7 @@ extern "C" {
mFlags: ::std::os::raw::c_uint, mFlags: ::std::os::raw::c_uint,
) -> *mut ::std::os::raw::c_uchar; ) -> *mut ::std::os::raw::c_uchar;
} }
pub const SQLITE_SERIALIZE_NOCOPY: ::std::os::raw::c_uint = 1;
extern "C" { extern "C" {
pub fn sqlite3_deserialize( pub fn sqlite3_deserialize(
db: *mut sqlite3, db: *mut sqlite3,
@ -2842,6 +2819,9 @@ extern "C" {
mFlags: ::std::os::raw::c_uint, mFlags: ::std::os::raw::c_uint,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_DESERIALIZE_FREEONCLOSE: ::std::os::raw::c_uint = 1;
pub const SQLITE_DESERIALIZE_RESIZEABLE: ::std::os::raw::c_uint = 2;
pub const SQLITE_DESERIALIZE_READONLY: ::std::os::raw::c_uint = 4;
pub type sqlite3_rtree_dbl = f64; pub type sqlite3_rtree_dbl = f64;
extern "C" { extern "C" {
pub fn sqlite3_rtree_geometry_callback( pub fn sqlite3_rtree_geometry_callback(
@ -2898,6 +2878,9 @@ pub struct sqlite3_rtree_query_info {
pub rScore: sqlite3_rtree_dbl, pub rScore: sqlite3_rtree_dbl,
pub apSqlParam: *mut *mut sqlite3_value, pub apSqlParam: *mut *mut sqlite3_value,
} }
pub const NOT_WITHIN: i32 = 0;
pub const PARTLY_WITHIN: i32 = 1;
pub const FULLY_WITHIN: i32 = 2;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sqlite3_session { pub struct sqlite3_session {
@ -2925,6 +2908,8 @@ extern "C" {
pArg: *mut ::std::os::raw::c_void, pArg: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_SESSION_OBJCONFIG_SIZE: i32 = 1;
pub const SQLITE_SESSION_OBJCONFIG_ROWID: i32 = 2;
extern "C" { extern "C" {
pub fn sqlite3session_enable( pub fn sqlite3session_enable(
pSession: *mut sqlite3_session, pSession: *mut sqlite3_session,
@ -3001,6 +2986,7 @@ extern "C" {
flags: ::std::os::raw::c_int, flags: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_CHANGESETSTART_INVERT: i32 = 2;
extern "C" { extern "C" {
pub fn sqlite3changeset_next(pIter: *mut sqlite3_changeset_iter) -> ::std::os::raw::c_int; pub fn sqlite3changeset_next(pIter: *mut sqlite3_changeset_iter) -> ::std::os::raw::c_int;
} }
@ -3138,6 +3124,17 @@ extern "C" {
flags: ::std::os::raw::c_int, flags: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_CHANGESETAPPLY_NOSAVEPOINT: i32 = 1;
pub const SQLITE_CHANGESETAPPLY_INVERT: i32 = 2;
pub const SQLITE_CHANGESETAPPLY_IGNORENOOP: i32 = 4;
pub const SQLITE_CHANGESET_DATA: i32 = 1;
pub const SQLITE_CHANGESET_NOTFOUND: i32 = 2;
pub const SQLITE_CHANGESET_CONFLICT: i32 = 3;
pub const SQLITE_CHANGESET_CONSTRAINT: i32 = 4;
pub const SQLITE_CHANGESET_FOREIGN_KEY: i32 = 5;
pub const SQLITE_CHANGESET_OMIT: i32 = 0;
pub const SQLITE_CHANGESET_REPLACE: i32 = 1;
pub const SQLITE_CHANGESET_ABORT: i32 = 2;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sqlite3_rebaser { pub struct sqlite3_rebaser {
@ -3376,6 +3373,7 @@ extern "C" {
pArg: *mut ::std::os::raw::c_void, pArg: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
pub const SQLITE_SESSION_CONFIG_STRMSIZE: i32 = 1;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Fts5Context { pub struct Fts5Context {
@ -3575,6 +3573,11 @@ pub struct fts5_tokenizer {
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
>, >,
} }
pub const FTS5_TOKENIZE_QUERY: i32 = 1;
pub const FTS5_TOKENIZE_PREFIX: i32 = 2;
pub const FTS5_TOKENIZE_DOCUMENT: i32 = 4;
pub const FTS5_TOKENIZE_AUX: i32 = 8;
pub const FTS5_TOKEN_COLOCATED: i32 = 1;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct fts5_api { pub struct fts5_api {

File diff suppressed because it is too large Load Diff

View File

@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.41.2" #define SQLITE_VERSION "3.42.0"
#define SQLITE_VERSION_NUMBER 3041002 #define SQLITE_VERSION_NUMBER 3042000
#define SQLITE_SOURCE_ID "2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da" #define SQLITE_SOURCE_ID "2023-05-16 12:36:15 831d0fb2836b71c9bc51067c49fee4b8f18047814f2ff22d817d25195cf350b0"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers
@ -1655,20 +1655,23 @@ SQLITE_API int sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other ** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlite3_config() is running.</b> ** threads while sqlite3_config() is running.</b>
** **
** The sqlite3_config() interface
** may only be invoked prior to library initialization using
** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
** [sqlite3_shutdown()] then it will return SQLITE_MISUSE.
** Note, however, that ^sqlite3_config() can be called as part of the
** implementation of an application-defined [sqlite3_os_init()].
**
** The first argument to sqlite3_config() is an integer ** The first argument to sqlite3_config() is an integer
** [configuration option] that determines ** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments ** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option] ** vary depending on the [configuration option]
** in the first argument. ** in the first argument.
** **
** For most configuration options, the sqlite3_config() interface
** may only be invoked prior to library initialization using
** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
** The exceptional configuration options that may be invoked at any time
** are called "anytime configuration options".
** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
** [sqlite3_shutdown()] with a first argument that is not an anytime
** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE.
** Note, however, that ^sqlite3_config() can be called as part of the
** implementation of an application-defined [sqlite3_os_init()].
**
** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option ** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code]. ** then this routine returns a non-zero [error code].
@ -1776,6 +1779,23 @@ struct sqlite3_mem_methods {
** These constants are the available integer configuration options that ** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface. ** can be passed as the first argument to the [sqlite3_config()] interface.
** **
** Most of the configuration options for sqlite3_config()
** will only work if invoked prior to [sqlite3_initialize()] or after
** [sqlite3_shutdown()]. The few exceptions to this rule are called
** "anytime configuration options".
** ^Calling [sqlite3_config()] with a first argument that is not an
** anytime configuration option in between calls to [sqlite3_initialize()] and
** [sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
**
** The set of anytime configuration options can change (by insertions
** and/or deletions) from one release of SQLite to the next.
** As of SQLite version 3.42.0, the complete set of anytime configuration
** options is:
** <ul>
** <li> SQLITE_CONFIG_LOG
** <li> SQLITE_CONFIG_PCACHE_HDRSZ
** </ul>
**
** New configuration options may be added in future releases of SQLite. ** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications ** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlite3_config()] to make sure that ** should check the return code from [sqlite3_config()] to make sure that
@ -2378,7 +2398,7 @@ struct sqlite3_mem_methods {
** </dd> ** </dd>
** **
** [[SQLITE_DBCONFIG_DQS_DML]] ** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td> ** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates ** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements ** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The ** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@ -2387,7 +2407,7 @@ struct sqlite3_mem_methods {
** </dd> ** </dd>
** **
** [[SQLITE_DBCONFIG_DQS_DDL]] ** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td> ** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates ** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements, ** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The ** such as CREATE TABLE and CREATE INDEX. The
@ -2396,7 +2416,7 @@ struct sqlite3_mem_methods {
** </dd> ** </dd>
** **
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] ** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td> ** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to ** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content. ** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite ** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@ -2416,7 +2436,7 @@ struct sqlite3_mem_methods {
** </dd> ** </dd>
** **
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td> ** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly ** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte ** created database file to have a schema format version number (the 4-byte
@ -2425,7 +2445,7 @@ struct sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions ** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there ** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
** is now scarcely any need to generated database files that are compatible ** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little ** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the ** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version ** ability to generate new database files that are compatible with version
@ -2436,6 +2456,38 @@ struct sqlite3_mem_methods {
** not considered a bug since SQLite versions 3.3.0 and earlier do not support ** not considered a bug since SQLite versions 3.3.0 and earlier do not support
** either generated columns or decending indexes. ** either generated columns or decending indexes.
** </dd> ** </dd>
**
** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
** statistics. For statistics to be collected, the flag must be set on
** the database handle both when the SQL statement is prepared and when it
** is stepped. The flag is set (collection of statistics is enabled)
** by default. This option takes two arguments: an integer and a pointer to
** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
** leave unchanged the statement scanstatus option. If the second argument
** is not NULL, then the value of the statement scanstatus setting after
** processing the first argument is written into the integer that the second
** argument points to.
** </dd>
**
** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
** in which tables and indexes are scanned so that the scans start at the end
** and work toward the beginning rather than starting at the beginning and
** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
** same as setting [PRAGMA reverse_unordered_selects]. This option takes
** two arguments which are an integer and a pointer to an integer. The first
** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
** reverse scan order flag, respectively. If the second argument is not NULL,
** then 0 or 1 is written into the integer that the second argument points to
** depending on if the reverse scan order flag is set after processing the
** first argument.
** </dd>
**
** </dl> ** </dl>
*/ */
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@ -2456,7 +2508,9 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ #define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/* /*
** CAPI3REF: Enable Or Disable Extended Result Codes ** CAPI3REF: Enable Or Disable Extended Result Codes
@ -6201,6 +6255,13 @@ SQLITE_API void sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at ** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlite3_sleep() may deviate from the description ** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs. ** in the previous paragraphs.
**
** If a negative argument is passed to sqlite3_sleep() the results vary by
** VFS and operating system. Some system treat a negative argument as an
** instruction to sleep forever. Others understand it to mean do not sleep
** at all. ^In SQLite version 3.42.0 and later, a negative
** argument passed into sqlite3_sleep() is changed to zero before it is relayed
** down into the xSleep method of the VFS.
*/ */
SQLITE_API int sqlite3_sleep(int); SQLITE_API int sqlite3_sleep(int);
@ -7828,9 +7889,9 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** is undefined if the mutex is not currently entered by the ** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated. ** calling thread or is not currently allocated.
** **
** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or ** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(),
** sqlite3_mutex_leave() is a NULL pointer, then all three routines ** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer,
** behave as no-ops. ** then any of the four routines behaves as a no-op.
** **
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/ */
@ -9564,18 +9625,28 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt> ** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form ** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers ** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the ** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a ** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS ** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary. ** flag unless absolutely necessary.
** </dd> ** </dd>
**
** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** instruct the query planner to begin at least a read transaction on
** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
** virtual table is used.
** </dd>
** </dl> ** </dl>
*/ */
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2 #define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3 #define SQLITE_VTAB_DIRECTONLY 3
#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/* /*
** CAPI3REF: Determine The Virtual Table Conflict Policy ** CAPI3REF: Determine The Virtual Table Conflict Policy
@ -10750,16 +10821,20 @@ SQLITE_API int sqlite3session_create(
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/* /*
** CAPIREF: Conigure a Session Object ** CAPI3REF: Configure a Session Object
** METHOD: sqlite3_session ** METHOD: sqlite3_session
** **
** This method is used to configure a session object after it has been ** This method is used to configure a session object after it has been
** created. At present the only valid value for the second parameter is ** created. At present the only valid values for the second parameter are
** [SQLITE_SESSION_OBJCONFIG_SIZE]. ** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
** **
** Arguments for sqlite3session_object_config() */
SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
/*
** CAPI3REF: Options for sqlite3session_object_config
** **
** The following values may passed as the the 4th parameter to ** The following values may passed as the the 2nd parameter to
** sqlite3session_object_config(). ** sqlite3session_object_config().
** **
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd> ** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@ -10775,12 +10850,21 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
** **
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object. ** the first table has been attached to the session object.
*/ **
SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); ** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
** This option is used to set, clear or query the flag that enables
/* ** collection of data for tables with no explicit PRIMARY KEY.
**
** Normally, tables with no explicit PRIMARY KEY are simply ignored
** by the sessions module. However, if this flag is set, it behaves
** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
** as their leftmost columns.
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
*/ */
#define SQLITE_SESSION_OBJCONFIG_SIZE 1 #define SQLITE_SESSION_OBJCONFIG_SIZE 1
#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/* /*
** CAPI3REF: Enable Or Disable A Session Object ** CAPI3REF: Enable Or Disable A Session Object
@ -11913,9 +11997,23 @@ SQLITE_API int sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting ** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlite3changeset_invert() before applying it. It is ** a changeset using sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset. ** an error to specify this flag with a patchset.
**
** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
** Do not invoke the conflict handler callback for any changes that
** would not actually modify the database even if they were applied.
** Specifically, this means that the conflict handler is not invoked
** for:
** <ul>
** <li>a delete change if the row being deleted cannot be found,
** <li>an update change if the modified fields are already set to
** their new values in the conflicting row, or
** <li>an insert change if all fields of the conflicting row match
** the row being inserted.
** </ul>
*/ */
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002
#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
/* /*
** CAPI3REF: Constants Passed To The Conflict Handler ** CAPI3REF: Constants Passed To The Conflict Handler

View File

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

View File

@ -274,7 +274,6 @@ impl Blob<'_> {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
use std::convert::TryInto;
self.size().try_into().unwrap() self.size().try_into().unwrap()
} }

View File

@ -1,7 +1,7 @@
//! Prepared statements cache for faster execution. //! Prepared statements cache for faster execution.
use crate::raw_statement::RawStatement; use crate::raw_statement::RawStatement;
use crate::{Connection, Result, Statement}; use crate::{Connection, PrepFlags, Result, Statement};
use hashlink::LruCache; use hashlink::LruCache;
use std::cell::RefCell; use std::cell::RefCell;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@ -144,7 +144,7 @@ impl StatementCache {
let mut cache = self.0.borrow_mut(); let mut cache = self.0.borrow_mut();
let stmt = match cache.remove(trimmed) { let stmt = match cache.remove(trimmed) {
Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)), Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
None => conn.prepare(trimmed), None => conn.prepare_with_flags(trimmed, PrepFlags::SQLITE_PREPARE_PERSISTENT),
}; };
stmt.map(|mut stmt| { stmt.map(|mut stmt| {
stmt.stmt.set_statement_cache_key(trimmed); stmt.stmt.set_statement_cache_key(trimmed);

View File

@ -203,7 +203,7 @@ mod test {
assert_eq!(ty, Type::Integer); assert_eq!(ty, Type::Integer);
} }
e => { e => {
panic!("Unexpected error type: {:?}", e); panic!("Unexpected error type: {e:?}");
} }
} }
match row.get::<_, String>("y").unwrap_err() { match row.get::<_, String>("y").unwrap_err() {
@ -213,7 +213,7 @@ mod test {
assert_eq!(ty, Type::Null); assert_eq!(ty, Type::Null);
} }
e => { e => {
panic!("Unexpected error type: {:?}", e); panic!("Unexpected error type: {e:?}");
} }
} }
Ok(()) Ok(())

View File

@ -61,6 +61,13 @@ pub enum DbConfig {
/// sqlite_master tables) are untainted by malicious content. /// sqlite_master tables) are untainted by malicious content.
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017, // 3.31.0 SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017, // 3.31.0
/// Sets or clears a flag that enables collection of the
/// sqlite3_stmt_scanstatus_v2() statistics
#[cfg(feature = "modern_sqlite")]
SQLITE_DBCONFIG_STMT_SCANSTATUS = 1018, // 3.42.0
/// Changes the default order in which tables and indexes are scanned
#[cfg(feature = "modern_sqlite")]
SQLITE_DBCONFIG_REVERSE_SCANORDER = 1019, // 3.42.0
} }
impl Connection { impl Connection {

View File

@ -252,11 +252,7 @@ impl fmt::Display for Error {
), ),
Error::FromSqlConversionFailure(i, ref t, ref err) => { Error::FromSqlConversionFailure(i, ref t, ref err) => {
if i != UNKNOWN_COLUMN { if i != UNKNOWN_COLUMN {
write!( write!(f, "Conversion error from type {t} at index: {i}, {err}")
f,
"Conversion error from type {} at index: {}, {}",
t, i, err
)
} else { } else {
err.fmt(f) err.fmt(f)
} }
@ -278,15 +274,12 @@ impl fmt::Display for Error {
Error::QueryReturnedNoRows => write!(f, "Query returned no rows"), Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"), Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"),
Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"), Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"),
Error::InvalidColumnType(i, ref name, ref t) => write!( Error::InvalidColumnType(i, ref name, ref t) => {
f, write!(f, "Invalid column type {t} at index: {i}, name: {name}")
"Invalid column type {} at index: {}, name: {}", }
t, i, name
),
Error::InvalidParameterCount(i1, n1) => write!( Error::InvalidParameterCount(i1, n1) => write!(
f, f,
"Wrong number of parameters passed to query. Got {}, needed {}", "Wrong number of parameters passed to query. Got {i1}, needed {n1}"
i1, n1
), ),
Error::StatementChangedRows(i) => write!(f, "Query changed {i} rows"), Error::StatementChangedRows(i) => write!(f, "Query changed {i} rows"),
@ -393,7 +386,6 @@ impl Error {
#[cold] #[cold]
pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error { pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
// TODO sqlite3_error_offset // 3.38.0, #1130
Error::SqliteFailure(ffi::Error::new(code), message) Error::SqliteFailure(ffi::Error::new(code), message)
} }
@ -443,3 +435,25 @@ pub fn check(code: c_int) -> Result<()> {
Ok(()) Ok(())
} }
} }
/// Transform Rust error to SQLite error (message and code).
/// # Safety
/// This function is unsafe because it uses raw pointer
pub unsafe fn to_sqlite_error(
e: &Error,
err_msg: *mut *mut std::os::raw::c_char,
) -> std::os::raw::c_int {
use crate::util::alloc;
match e {
Error::SqliteFailure(err, s) => {
if let Some(s) = s {
*err_msg = alloc(s);
}
err.extended_code
}
err => {
*err_msg = alloc(&err.to_string());
ffi::SQLITE_ERROR
}
}
}

View File

@ -71,21 +71,13 @@ use crate::types::{FromSql, FromSqlError, ToSql, ValueRef};
use crate::{str_to_cstring, Connection, Error, InnerConnection, Result}; use crate::{str_to_cstring, Connection, Error, InnerConnection, Result};
unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) { unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) {
// Extended constraint error codes were added in SQLite 3.7.16. We don't have
// an explicit 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.
fn constraint_error_code() -> i32 {
ffi::SQLITE_CONSTRAINT_FUNCTION
}
if let Error::SqliteFailure(ref err, ref s) = *err { if let Error::SqliteFailure(ref err, ref s) = *err {
ffi::sqlite3_result_error_code(ctx, err.extended_code); ffi::sqlite3_result_error_code(ctx, err.extended_code);
if let Some(Ok(cstr)) = s.as_ref().map(|s| str_to_cstring(s)) { if let Some(Ok(cstr)) = s.as_ref().map(|s| str_to_cstring(s)) {
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1); ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
} }
} else { } else {
ffi::sqlite3_result_error_code(ctx, constraint_error_code()); ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_CONSTRAINT_FUNCTION);
if let Ok(cstr) = str_to_cstring(&err.to_string()) { if let Ok(cstr) = str_to_cstring(&err.to_string()) {
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1); ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
} }
@ -847,7 +839,7 @@ mod test {
// This implementation of a regexp scalar function uses SQLite's auxiliary data // This implementation of a regexp scalar function uses SQLite's auxiliary data
// (https://www.sqlite.org/c3ref/get_auxdata.html) to avoid recompiling the regular // (https://www.sqlite.org/c3ref/get_auxdata.html) to avoid recompiling the regular
// expression multiple times within one query. // expression multiple times within one query.
fn regexp_with_auxilliary(ctx: &Context<'_>) -> Result<bool> { fn regexp_with_auxiliary(ctx: &Context<'_>) -> Result<bool> {
assert_eq!(ctx.len(), 2, "called with unexpected number of arguments"); assert_eq!(ctx.len(), 2, "called with unexpected number of arguments");
type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>; type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
let regexp: std::sync::Arc<Regex> = ctx let regexp: std::sync::Arc<Regex> = ctx
@ -868,7 +860,7 @@ mod test {
} }
#[test] #[test]
fn test_function_regexp_with_auxilliary() -> Result<()> { fn test_function_regexp_with_auxiliary() -> Result<()> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch( db.execute_batch(
"BEGIN; "BEGIN;
@ -882,7 +874,7 @@ mod test {
"regexp", "regexp",
2, 2,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
regexp_with_auxilliary, regexp_with_auxiliary,
)?; )?;
let result: bool = db.one_column("SELECT regexp('l.s[aeiouy]', 'lisa')")?; let result: bool = db.one_column("SELECT regexp('l.s[aeiouy]', 'lisa')")?;

View File

@ -656,7 +656,7 @@ unsafe fn free_boxed_hook<F>(p: *mut c_void) {
unsafe fn expect_utf8<'a>(p_str: *const c_char, description: &'static str) -> &'a str { unsafe fn expect_utf8<'a>(p_str: *const c_char, description: &'static str) -> &'a str {
expect_optional_utf8(p_str, description) expect_optional_utf8(p_str, description)
.unwrap_or_else(|| panic!("received empty {}", description)) .unwrap_or_else(|| panic!("received empty {description}"))
} }
unsafe fn expect_optional_utf8<'a>( unsafe fn expect_optional_utf8<'a>(
@ -667,7 +667,7 @@ unsafe fn expect_optional_utf8<'a>(
return None; return None;
} }
std::str::from_utf8(std::ffi::CStr::from_ptr(p_str).to_bytes()) std::str::from_utf8(std::ffi::CStr::from_ptr(p_str).to_bytes())
.unwrap_or_else(|_| panic!("received non-utf8 string as {}", description)) .unwrap_or_else(|_| panic!("received non-utf8 string as {description}"))
.into() .into()
} }

View File

@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex};
use super::ffi; use super::ffi;
use super::str_for_sqlite; use super::str_for_sqlite;
use super::{Connection, InterruptHandle, OpenFlags, Result}; use super::{Connection, InterruptHandle, OpenFlags, PrepFlags, Result};
use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error}; use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error};
use crate::raw_statement::RawStatement; use crate::raw_statement::RawStatement;
use crate::statement::Statement; use crate::statement::Statement;
@ -218,33 +218,24 @@ impl InnerConnection {
unsafe { ffi::sqlite3_last_insert_rowid(self.db()) } unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
} }
pub fn prepare<'a>(&mut self, conn: &'a Connection, sql: &str) -> Result<Statement<'a>> { pub fn prepare<'a>(
let mut c_stmt = ptr::null_mut(); &mut self,
conn: &'a Connection,
sql: &str,
flags: PrepFlags,
) -> Result<Statement<'a>> {
let mut c_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?; let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?;
let mut c_tail = ptr::null(); let mut c_tail: *const c_char = ptr::null();
// TODO sqlite3_prepare_v3 (https://sqlite.org/c3ref/c_prepare_normalize.html) // 3.20.0, #728 // TODO sqlite3_prepare_v3 (https://sqlite.org/c3ref/c_prepare_normalize.html) // 3.20.0, #728
#[cfg(not(feature = "unlock_notify"))] #[cfg(not(feature = "unlock_notify"))]
let r = unsafe { let r = unsafe { self.prepare_(c_sql, len, flags, &mut c_stmt, &mut c_tail) };
ffi::sqlite3_prepare_v2(
self.db(),
c_sql,
len,
&mut c_stmt as *mut *mut ffi::sqlite3_stmt,
&mut c_tail as *mut *const c_char,
)
};
#[cfg(feature = "unlock_notify")] #[cfg(feature = "unlock_notify")]
let r = unsafe { let r = unsafe {
use crate::unlock_notify; use crate::unlock_notify;
let mut rc; let mut rc;
loop { loop {
rc = ffi::sqlite3_prepare_v2( rc = self.prepare_(c_sql, len, flags, &mut c_stmt, &mut c_tail);
self.db(),
c_sql,
len,
&mut c_stmt as *mut *mut ffi::sqlite3_stmt,
&mut c_tail as *mut *const c_char,
);
if !unlock_notify::is_locked(self.db, rc) { if !unlock_notify::is_locked(self.db, rc) {
break; break;
} }
@ -261,8 +252,6 @@ impl InnerConnection {
} }
// If the input text contains no SQL (if the input is an empty string or a // If the input text contains no SQL (if the input is an empty string or a
// comment) then *ppStmt is set to NULL. // comment) then *ppStmt is set to NULL.
let c_stmt: *mut ffi::sqlite3_stmt = c_stmt;
let c_tail: *const c_char = c_tail;
let tail = if c_tail.is_null() { let tail = if c_tail.is_null() {
0 0
} else { } else {
@ -278,6 +267,32 @@ impl InnerConnection {
})) }))
} }
#[inline]
#[cfg(not(feature = "modern_sqlite"))]
unsafe fn prepare_(
&self,
z_sql: *const c_char,
n_byte: c_int,
_: PrepFlags,
pp_stmt: *mut *mut ffi::sqlite3_stmt,
pz_tail: *mut *const c_char,
) -> c_int {
ffi::sqlite3_prepare_v2(self.db(), z_sql, n_byte, pp_stmt, pz_tail)
}
#[inline]
#[cfg(feature = "modern_sqlite")]
unsafe fn prepare_(
&self,
z_sql: *const c_char,
n_byte: c_int,
flags: PrepFlags,
pp_stmt: *mut *mut ffi::sqlite3_stmt,
pz_tail: *mut *const c_char,
) -> c_int {
ffi::sqlite3_prepare_v3(self.db(), z_sql, n_byte, flags.bits(), pp_stmt, pz_tail)
}
#[inline] #[inline]
pub fn changes(&self) -> u64 { pub fn changes(&self) -> u64 {
#[cfg(not(feature = "modern_sqlite"))] #[cfg(not(feature = "modern_sqlite"))]
@ -382,7 +397,7 @@ pub static BYPASS_SQLITE_INIT: AtomicBool = AtomicBool::new(false);
// threading mode checks are not necessary (and do not work) on target // threading mode checks are not necessary (and do not work) on target
// platforms that do not have threading (such as webassembly) // platforms that do not have threading (such as webassembly)
#[cfg(any(target_arch = "wasm32"))] #[cfg(target_arch = "wasm32")]
fn ensure_safe_sqlite_threading_mode() -> Result<()> { fn ensure_safe_sqlite_threading_mode() -> Result<()> {
Ok(()) Ok(())
} }

View File

@ -75,7 +75,7 @@ use crate::types::ValueRef;
pub use crate::cache::CachedStatement; pub use crate::cache::CachedStatement;
pub use crate::column::Column; pub use crate::column::Column;
pub use crate::error::Error; pub use crate::error::{to_sqlite_error, Error};
pub use crate::ffi::ErrorCode; pub use crate::ffi::ErrorCode;
#[cfg(feature = "load_extension")] #[cfg(feature = "load_extension")]
pub use crate::load_extension_guard::LoadExtensionGuard; pub use crate::load_extension_guard::LoadExtensionGuard;
@ -122,6 +122,9 @@ mod params;
mod pragma; mod pragma;
mod raw_statement; mod raw_statement;
mod row; mod row;
#[cfg(feature = "serialize")]
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
pub mod serialize;
#[cfg(feature = "session")] #[cfg(feature = "session")]
#[cfg_attr(docsrs, doc(cfg(feature = "session")))] #[cfg_attr(docsrs, doc(cfg(feature = "session")))]
pub mod session; pub mod session;
@ -759,7 +762,18 @@ impl Connection {
/// or if the underlying SQLite call fails. /// or if the underlying SQLite call fails.
#[inline] #[inline]
pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> { pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
self.db.borrow_mut().prepare(self, sql) self.prepare_with_flags(sql, PrepFlags::default())
}
/// Prepare a SQL statement for execution.
///
/// # Failure
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
#[inline]
pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
self.db.borrow_mut().prepare(self, sql, flags)
} }
/// Close the SQLite connection. /// Close the SQLite connection.
@ -1073,7 +1087,7 @@ impl<'conn> Iterator for Batch<'conn, '_> {
bitflags::bitflags! { bitflags::bitflags! {
/// Flags for opening SQLite database connections. See /// Flags for opening SQLite database connections. See
/// [sqlite3_open_v2](http://www.sqlite.org/c3ref/open.html) for details. /// [sqlite3_open_v2](https://www.sqlite.org/c3ref/open.html) for details.
/// ///
/// The default open flags are `SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE /// The default open flags are `SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE
/// | SQLITE_OPEN_URI | SQLITE_OPEN_NO_MUTEX`. See [`Connection::open`] for /// | SQLITE_OPEN_URI | SQLITE_OPEN_NO_MUTEX`. See [`Connection::open`] for
@ -1155,6 +1169,19 @@ impl Default for OpenFlags {
} }
} }
bitflags::bitflags! {
/// Prepare flags. See
/// [sqlite3_prepare_v3](https://sqlite.org/c3ref/c_prepare_normalize.html) for details.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[repr(C)]
pub struct PrepFlags: ::std::os::raw::c_uint {
/// A hint to the query planner that the prepared statement will be retained for a long time and probably reused many times.
const SQLITE_PREPARE_PERSISTENT = 0x01;
/// Causes the SQL compiler to return an error (error code SQLITE_ERROR) if the statement uses any virtual tables.
const SQLITE_PREPARE_NO_VTAB = 0x04;
}
}
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or /// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or
/// later. If you are running against a SQLite older than that, rusqlite /// later. If you are running against a SQLite older than that, rusqlite
/// attempts to ensure safety by performing configuration and initialization of /// attempts to ensure safety by performing configuration and initialization of
@ -1211,13 +1238,21 @@ mod test {
// this function is never called, but is still type checked; in // this function is never called, but is still type checked; in
// particular, calls with specific instantiations will require // particular, calls with specific instantiations will require
// that those types are `Send`. // that those types are `Send`.
#[allow(dead_code, unconditional_recursion)] #[allow(
dead_code,
unconditional_recursion,
clippy::extra_unused_type_parameters
)]
fn ensure_send<T: Send>() { fn ensure_send<T: Send>() {
ensure_send::<Connection>(); ensure_send::<Connection>();
ensure_send::<InterruptHandle>(); ensure_send::<InterruptHandle>();
} }
#[allow(dead_code, unconditional_recursion)] #[allow(
dead_code,
unconditional_recursion,
clippy::extra_unused_type_parameters
)]
fn ensure_sync<T: Sync>() { fn ensure_sync<T: Sync>() {
ensure_sync::<InterruptHandle>(); ensure_sync::<InterruptHandle>();
} }
@ -1323,9 +1358,7 @@ mod test {
assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code); assert_eq!(ffi::SQLITE_CANTOPEN, e.extended_code);
assert!( assert!(
msg.contains(filename), msg.contains(filename),
"error message '{}' does not contain '{}'", "error message '{msg}' does not contain '{filename}'"
msg,
filename
); );
} else { } else {
panic!("SqliteFailure expected"); panic!("SqliteFailure expected");
@ -1453,8 +1486,7 @@ mod test {
assert_eq!( assert_eq!(
err, err,
Error::ExecuteReturnedResults, Error::ExecuteReturnedResults,
"Unexpected error: {}", "Unexpected error: {err}"
err
); );
} }
@ -1470,7 +1502,7 @@ mod test {
.unwrap_err(); .unwrap_err();
match err { match err {
Error::MultipleStatement => (), Error::MultipleStatement => (),
_ => panic!("Unexpected error: {}", err), _ => panic!("Unexpected error: {err}"),
} }
} }
@ -1581,7 +1613,7 @@ mod test {
let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5"); let result: Result<i64> = db.one_column("SELECT x FROM foo WHERE x > 5");
match result.unwrap_err() { match result.unwrap_err() {
Error::QueryReturnedNoRows => (), Error::QueryReturnedNoRows => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(())); let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
@ -1633,7 +1665,7 @@ mod test {
// > MEMORY or OFF and can not be changed to a different value. An // > MEMORY or OFF and can not be changed to a different value. An
// > attempt to change the journal_mode of an in-memory database to // > attempt to change the journal_mode of an in-memory database to
// > any setting other than MEMORY or OFF is ignored. // > any setting other than MEMORY or OFF is ignored.
assert!(mode == "memory" || mode == "off", "Got mode {:?}", mode); assert!(mode == "memory" || mode == "off", "Got mode {mode:?}");
} }
Ok(()) Ok(())
@ -1720,7 +1752,7 @@ mod test {
assert_eq!(err.code, ErrorCode::ConstraintViolation); assert_eq!(err.code, ErrorCode::ConstraintViolation);
check_extended_code(err.extended_code); check_extended_code(err.extended_code);
} }
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
Ok(()) Ok(())
} }
@ -1912,7 +1944,7 @@ mod test {
match bad_type.unwrap_err() { match bad_type.unwrap_err() {
Error::InvalidColumnType(..) => (), Error::InvalidColumnType(..) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
let bad_idx: Result<Vec<String>> = let bad_idx: Result<Vec<String>> =
@ -1920,7 +1952,7 @@ mod test {
match bad_idx.unwrap_err() { match bad_idx.unwrap_err() {
Error::InvalidColumnIndex(_) => (), Error::InvalidColumnIndex(_) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
Ok(()) Ok(())
} }
@ -1965,7 +1997,7 @@ mod test {
match bad_type.unwrap_err() { match bad_type.unwrap_err() {
CustomError::Sqlite(Error::InvalidColumnType(..)) => (), CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
let bad_idx: CustomResult<Vec<String>> = query let bad_idx: CustomResult<Vec<String>> = query
@ -1974,7 +2006,7 @@ mod test {
match bad_idx.unwrap_err() { match bad_idx.unwrap_err() {
CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (), CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
let non_sqlite_err: CustomResult<Vec<String>> = query let non_sqlite_err: CustomResult<Vec<String>> = query
@ -1983,7 +2015,7 @@ mod test {
match non_sqlite_err.unwrap_err() { match non_sqlite_err.unwrap_err() {
CustomError::SomeError => (), CustomError::SomeError => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
Ok(()) Ok(())
} }
@ -2020,7 +2052,7 @@ mod test {
match bad_type.unwrap_err() { match bad_type.unwrap_err() {
CustomError::Sqlite(Error::InvalidColumnType(..)) => (), CustomError::Sqlite(Error::InvalidColumnType(..)) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
let bad_idx: CustomResult<String> = let bad_idx: CustomResult<String> =
@ -2028,7 +2060,7 @@ mod test {
match bad_idx.unwrap_err() { match bad_idx.unwrap_err() {
CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (), CustomError::Sqlite(Error::InvalidColumnIndex(_)) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
let non_sqlite_err: CustomResult<String> = let non_sqlite_err: CustomResult<String> =
@ -2036,7 +2068,7 @@ mod test {
match non_sqlite_err.unwrap_err() { match non_sqlite_err.unwrap_err() {
CustomError::SomeError => (), CustomError::SomeError => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
Ok(()) Ok(())
} }

View File

@ -405,18 +405,17 @@ mod test {
db.pragma_update_and_check(None, "journal_mode", "OFF", |row| row.get(0))?; db.pragma_update_and_check(None, "journal_mode", "OFF", |row| row.get(0))?;
assert!( assert!(
journal_mode == "off" || journal_mode == "memory", journal_mode == "off" || journal_mode == "memory",
"mode: {:?}", "mode: {journal_mode:?}"
journal_mode,
); );
// Sanity checks to ensure the move to a generic `ToSql` wasn't breaking // Sanity checks to ensure the move to a generic `ToSql` wasn't breaking
let mode = let mode =
db.pragma_update_and_check(None, "journal_mode", "OFF", |row| row.get::<_, String>(0))?; db.pragma_update_and_check(None, "journal_mode", "OFF", |row| row.get::<_, String>(0))?;
assert!(mode == "off" || mode == "memory", "mode: {:?}", mode); assert!(mode == "off" || mode == "memory", "mode: {mode:?}");
let param: &dyn crate::ToSql = &"OFF"; let param: &dyn crate::ToSql = &"OFF";
let mode = let mode =
db.pragma_update_and_check(None, "journal_mode", param, |row| row.get::<_, String>(0))?; db.pragma_update_and_check(None, "journal_mode", param, |row| row.get::<_, String>(0))?;
assert!(mode == "off" || mode == "memory", "mode: {:?}", mode); assert!(mode == "off" || mode == "memory", "mode: {mode:?}");
Ok(()) Ok(())
} }

View File

@ -257,6 +257,7 @@ impl<'stmt> Row<'stmt> {
/// * If the underlying SQLite integral value is outside the range /// * If the underlying SQLite integral value is outside the range
/// representable by `T` /// representable by `T`
/// * If `idx` is outside the range of columns in the returned query /// * If `idx` is outside the range of columns in the returned query
#[track_caller]
pub fn get_unwrap<I: RowIndex, T: FromSql>(&self, idx: I) -> T { pub fn get_unwrap<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
self.get(idx).unwrap() self.get(idx).unwrap()
} }
@ -277,6 +278,7 @@ impl<'stmt> Row<'stmt> {
/// If the result type is i128 (which requires the `i128_blob` feature to be /// If the result type is i128 (which requires the `i128_blob` feature to be
/// enabled), and the underlying SQLite column is a blob whose size is not /// enabled), and the underlying SQLite column is a blob whose size is not
/// 16 bytes, `Error::InvalidColumnType` will also be returned. /// 16 bytes, `Error::InvalidColumnType` will also be returned.
#[track_caller]
pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> { pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
let idx = idx.idx(self.stmt)?; let idx = idx.idx(self.stmt)?;
let value = self.stmt.value_ref(idx); let value = self.stmt.value_ref(idx);
@ -335,6 +337,7 @@ impl<'stmt> Row<'stmt> {
/// ///
/// * If `idx` is outside the range of columns in the returned query. /// * If `idx` is outside the range of columns in the returned query.
/// * If `idx` is not a valid column name for this row. /// * If `idx` is not a valid column name for this row.
#[track_caller]
pub fn get_ref_unwrap<I: RowIndex>(&self, idx: I) -> ValueRef<'_> { pub fn get_ref_unwrap<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
self.get_ref(idx).unwrap() self.get_ref(idx).unwrap()
} }

162
src/serialize.rs Normal file
View File

@ -0,0 +1,162 @@
//! Serialize a database.
use std::convert::TryInto;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::NonNull;
use crate::error::error_from_handle;
use crate::ffi;
use crate::{Connection, DatabaseName, Result};
/// Shared (SQLITE_SERIALIZE_NOCOPY) serialized database
pub struct SharedData<'conn> {
phantom: PhantomData<&'conn Connection>,
ptr: NonNull<u8>,
sz: usize,
}
/// Owned serialized database
pub struct OwnedData {
ptr: NonNull<u8>,
sz: usize,
}
impl OwnedData {
/// SAFETY: Caller must be certain that `ptr` is allocated by
/// `sqlite3_malloc`.
pub unsafe fn from_raw_nonnull(ptr: NonNull<u8>, sz: usize) -> Self {
Self { ptr, sz }
}
fn into_raw(self) -> (*mut u8, usize) {
let raw = (self.ptr.as_ptr(), self.sz);
std::mem::forget(self);
raw
}
}
impl Drop for OwnedData {
fn drop(&mut self) {
unsafe {
ffi::sqlite3_free(self.ptr.as_ptr().cast());
}
}
}
/// Serialized database
pub enum Data<'conn> {
/// Shared (SQLITE_SERIALIZE_NOCOPY) serialized database
Shared(SharedData<'conn>),
/// Owned serialized database
Owned(OwnedData),
}
impl<'conn> Deref for Data<'conn> {
type Target = [u8];
fn deref(&self) -> &[u8] {
let (ptr, sz) = match self {
Data::Owned(OwnedData { ptr, sz }) => (ptr.as_ptr(), *sz),
Data::Shared(SharedData { ptr, sz, .. }) => (ptr.as_ptr(), *sz),
};
unsafe { std::slice::from_raw_parts(ptr, sz) }
}
}
impl Connection {
/// Serialize a database.
pub fn serialize<'conn>(&'conn self, schema: DatabaseName<'_>) -> Result<Data<'conn>> {
let schema = schema.as_cstring()?;
let mut sz = 0;
let mut ptr: *mut u8 = unsafe {
ffi::sqlite3_serialize(
self.handle(),
schema.as_ptr(),
&mut sz,
ffi::SQLITE_SERIALIZE_NOCOPY,
)
};
Ok(if ptr.is_null() {
ptr = unsafe { ffi::sqlite3_serialize(self.handle(), schema.as_ptr(), &mut sz, 0) };
if ptr.is_null() {
return Err(unsafe { error_from_handle(self.handle(), ffi::SQLITE_NOMEM) });
}
Data::Owned(OwnedData {
ptr: NonNull::new(ptr).unwrap(),
sz: sz.try_into().unwrap(),
})
} else {
// shared buffer
Data::Shared(SharedData {
ptr: NonNull::new(ptr).unwrap(),
sz: sz.try_into().unwrap(),
phantom: PhantomData,
})
})
}
/// Deserialize a database.
pub fn deserialize(
&mut self,
schema: DatabaseName<'_>,
data: OwnedData,
read_only: bool,
) -> Result<()> {
let schema = schema.as_cstring()?;
let (data, sz) = data.into_raw();
let sz = sz.try_into().unwrap();
let flags = if read_only {
ffi::SQLITE_DESERIALIZE_FREEONCLOSE | ffi::SQLITE_DESERIALIZE_READONLY
} else {
ffi::SQLITE_DESERIALIZE_FREEONCLOSE | ffi::SQLITE_DESERIALIZE_RESIZEABLE
};
let rc = unsafe {
ffi::sqlite3_deserialize(self.handle(), schema.as_ptr(), data, sz, sz, flags)
};
if rc != ffi::SQLITE_OK {
// TODO sqlite3_free(data) ?
return Err(unsafe { error_from_handle(self.handle(), rc) });
}
/* TODO
if let Some(mxSize) = mxSize {
unsafe {
ffi::sqlite3_file_control(
self.handle(),
schema.as_ptr(),
ffi::SQLITE_FCNTL_SIZE_LIMIT,
&mut mxSize,
)
};
}*/
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{Connection, DatabaseName, Result};
#[test]
fn serialize() -> Result<()> {
let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE x AS SELECT 'data'")?;
let data = db.serialize(DatabaseName::Main)?;
let Data::Owned(data) = data else { panic!("expected OwnedData")};
assert!(data.sz > 0);
Ok(())
}
#[test]
fn deserialize() -> Result<()> {
let src = Connection::open_in_memory()?;
src.execute_batch("CREATE TABLE x AS SELECT 'data'")?;
let data = src.serialize(DatabaseName::Main)?;
let Data::Owned(data) = data else { panic!("expected OwnedData")};
let mut dst = Connection::open_in_memory()?;
dst.deserialize(DatabaseName::Main, data, false)?;
dst.execute("DELETE FROM x", [])?;
Ok(())
}
}

View File

@ -1081,12 +1081,12 @@ mod test {
assert_eq!(stmt.insert([2i32])?, 2); assert_eq!(stmt.insert([2i32])?, 2);
match stmt.insert([1i32]).unwrap_err() { match stmt.insert([1i32]).unwrap_err() {
Error::StatementChangedRows(0) => (), Error::StatementChangedRows(0) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4")?; let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4")?;
match multi.insert([]).unwrap_err() { match multi.insert([]).unwrap_err() {
Error::StatementChangedRows(2) => (), Error::StatementChangedRows(2) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
Ok(()) Ok(())
} }
@ -1349,7 +1349,7 @@ mod test {
assert_eq!(error.code, ErrorCode::Unknown); assert_eq!(error.code, ErrorCode::Unknown);
assert_eq!(offset, 7); assert_eq!(offset, 7);
} }
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {err}"),
} }
Ok(()) Ok(())
} }

View File

@ -91,7 +91,6 @@ pub struct Transaction<'conn> {
pub struct Savepoint<'conn> { pub struct Savepoint<'conn> {
conn: &'conn Connection, conn: &'conn Connection,
name: String, name: String,
depth: u32,
drop_behavior: DropBehavior, drop_behavior: DropBehavior,
committed: bool, committed: bool,
} }
@ -158,13 +157,13 @@ impl Transaction<'_> {
/// ``` /// ```
#[inline] #[inline]
pub fn savepoint(&mut self) -> Result<Savepoint<'_>> { pub fn savepoint(&mut self) -> Result<Savepoint<'_>> {
Savepoint::with_depth(self.conn, 1) Savepoint::new_(self.conn)
} }
/// Create a new savepoint with a custom savepoint name. See `savepoint()`. /// Create a new savepoint with a custom savepoint name. See `savepoint()`.
#[inline] #[inline]
pub fn savepoint_with_name<T: Into<String>>(&mut self, name: T) -> Result<Savepoint<'_>> { pub fn savepoint_with_name<T: Into<String>>(&mut self, name: T) -> Result<Savepoint<'_>> {
Savepoint::with_depth_and_name(self.conn, 1, name) Savepoint::with_name_(self.conn, name)
} }
/// Get the current setting for what happens to the transaction when it is /// Get the current setting for what happens to the transaction when it is
@ -249,50 +248,44 @@ impl Drop for Transaction<'_> {
impl Savepoint<'_> { impl Savepoint<'_> {
#[inline] #[inline]
fn with_depth_and_name<T: Into<String>>( fn with_name_<T: Into<String>>(conn: &Connection, name: T) -> Result<Savepoint<'_>> {
conn: &Connection,
depth: u32,
name: T,
) -> Result<Savepoint<'_>> {
let name = name.into(); let name = name.into();
conn.execute_batch(&format!("SAVEPOINT {name}")) conn.execute_batch(&format!("SAVEPOINT {name}"))
.map(|_| Savepoint { .map(|_| Savepoint {
conn, conn,
name, name,
depth,
drop_behavior: DropBehavior::Rollback, drop_behavior: DropBehavior::Rollback,
committed: false, committed: false,
}) })
} }
#[inline] #[inline]
fn with_depth(conn: &Connection, depth: u32) -> Result<Savepoint<'_>> { fn new_(conn: &Connection) -> Result<Savepoint<'_>> {
let name = format!("_rusqlite_sp_{depth}"); Savepoint::with_name_(conn, "_rusqlite_sp")
Savepoint::with_depth_and_name(conn, depth, name)
} }
/// Begin a new savepoint. Can be nested. /// Begin a new savepoint. Can be nested.
#[inline] #[inline]
pub fn new(conn: &mut Connection) -> Result<Savepoint<'_>> { pub fn new(conn: &mut Connection) -> Result<Savepoint<'_>> {
Savepoint::with_depth(conn, 0) Savepoint::new_(conn)
} }
/// Begin a new savepoint with a user-provided savepoint name. /// Begin a new savepoint with a user-provided savepoint name.
#[inline] #[inline]
pub fn with_name<T: Into<String>>(conn: &mut Connection, name: T) -> Result<Savepoint<'_>> { pub fn with_name<T: Into<String>>(conn: &mut Connection, name: T) -> Result<Savepoint<'_>> {
Savepoint::with_depth_and_name(conn, 0, name) Savepoint::with_name_(conn, name)
} }
/// Begin a nested savepoint. /// Begin a nested savepoint.
#[inline] #[inline]
pub fn savepoint(&mut self) -> Result<Savepoint<'_>> { pub fn savepoint(&mut self) -> Result<Savepoint<'_>> {
Savepoint::with_depth(self.conn, self.depth + 1) Savepoint::new_(self.conn)
} }
/// Begin a nested savepoint with a user-provided savepoint name. /// Begin a nested savepoint with a user-provided savepoint name.
#[inline] #[inline]
pub fn savepoint_with_name<T: Into<String>>(&mut self, name: T) -> Result<Savepoint<'_>> { pub fn savepoint_with_name<T: Into<String>>(&mut self, name: T) -> Result<Savepoint<'_>> {
Savepoint::with_depth_and_name(self.conn, self.depth + 1, name) Savepoint::with_name_(self.conn, name)
} }
/// Get the current setting for what happens to the savepoint when it is /// Get the current setting for what happens to the savepoint when it is
@ -351,8 +344,10 @@ impl Savepoint<'_> {
return Ok(()); return Ok(());
} }
match self.drop_behavior() { match self.drop_behavior() {
DropBehavior::Commit => self.commit_().or_else(|_| self.rollback()), DropBehavior::Commit => self
DropBehavior::Rollback => self.rollback(), .commit_()
.or_else(|_| self.rollback().and_then(|_| self.commit_())),
DropBehavior::Rollback => self.rollback().and_then(|_| self.commit_()),
DropBehavior::Ignore => Ok(()), DropBehavior::Ignore => Ok(()),
DropBehavior::Panic => panic!("Savepoint dropped unexpectedly."), DropBehavior::Panic => panic!("Savepoint dropped unexpectedly."),
} }
@ -563,7 +558,7 @@ mod test {
assert_eq!(e.code, crate::ErrorCode::Unknown); assert_eq!(e.code, crate::ErrorCode::Unknown);
assert!(m.contains("transaction")); assert!(m.contains("transaction"));
} else { } else {
panic!("Unexpected error type: {:?}", e); panic!("Unexpected error type: {e:?}");
} }
} }
@ -675,6 +670,40 @@ mod test {
Ok(()) Ok(())
} }
#[test]
fn test_savepoint_drop_behavior_releases() -> Result<()> {
let mut db = checked_memory_handle()?;
{
let mut sp = db.savepoint()?;
sp.set_drop_behavior(DropBehavior::Commit);
}
assert!(db.is_autocommit());
{
let mut sp = db.savepoint()?;
sp.set_drop_behavior(DropBehavior::Rollback);
}
assert!(db.is_autocommit());
Ok(())
}
#[test]
fn test_savepoint_release_error() -> Result<()> {
let mut db = checked_memory_handle()?;
db.pragma_update(None, "foreign_keys", true)?;
db.execute_batch("CREATE TABLE r(n INTEGER PRIMARY KEY NOT NULL); CREATE TABLE f(n REFERENCES r(n) DEFERRABLE INITIALLY DEFERRED);")?;
{
let mut sp = db.savepoint()?;
sp.execute("INSERT INTO f VALUES (0)", [])?;
sp.set_drop_behavior(DropBehavior::Commit);
}
assert!(db.is_autocommit());
Ok(())
}
#[test] #[test]
fn test_savepoint_names() -> Result<()> { fn test_savepoint_names() -> Result<()> {
let mut db = checked_memory_handle()?; let mut db = checked_memory_handle()?;

View File

@ -59,8 +59,7 @@ impl fmt::Display for FromSqlError {
} => { } => {
write!( write!(
f, f,
"Cannot read {} byte value out of {} byte blob", "Cannot read {expected_size} byte value out of {blob_size} byte blob"
expected_size, blob_size
) )
} }
FromSqlError::Other(ref err) => err.fmt(f), FromSqlError::Other(ref err) => err.fmt(f),
@ -96,6 +95,15 @@ macro_rules! from_sql_integral(
i.try_into().map_err(|_| FromSqlError::OutOfRange(i)) i.try_into().map_err(|_| FromSqlError::OutOfRange(i))
} }
} }
);
(non_zero $nz:ty, $z:ty) => (
impl FromSql for $nz {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let i = <$z>::column_result(value)?;
<$nz>::new(i).ok_or(FromSqlError::OutOfRange(0))
}
}
) )
); );
@ -110,6 +118,22 @@ from_sql_integral!(u32);
from_sql_integral!(u64); from_sql_integral!(u64);
from_sql_integral!(usize); from_sql_integral!(usize);
from_sql_integral!(non_zero std::num::NonZeroIsize, isize);
from_sql_integral!(non_zero std::num::NonZeroI8, i8);
from_sql_integral!(non_zero std::num::NonZeroI16, i16);
from_sql_integral!(non_zero std::num::NonZeroI32, i32);
from_sql_integral!(non_zero std::num::NonZeroI64, i64);
#[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
from_sql_integral!(non_zero std::num::NonZeroI128, i128);
from_sql_integral!(non_zero std::num::NonZeroUsize, usize);
from_sql_integral!(non_zero std::num::NonZeroU8, u8);
from_sql_integral!(non_zero std::num::NonZeroU16, u16);
from_sql_integral!(non_zero std::num::NonZeroU32, u32);
from_sql_integral!(non_zero std::num::NonZeroU64, u64);
// std::num::NonZeroU128 is not supported since u128 isn't either
impl FromSql for i64 { impl FromSql for i64 {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
@ -248,7 +272,7 @@ mod test {
.unwrap_err(); .unwrap_err();
match err { match err {
Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value), Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
_ => panic!("unexpected error: {}", err), _ => panic!("unexpected error: {err}"),
} }
} }
for n in in_range { for n in in_range {
@ -273,4 +297,70 @@ mod test {
check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]); check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
Ok(()) Ok(())
} }
#[test]
fn test_nonzero_ranges() -> Result<()> {
let db = Connection::open_in_memory()?;
macro_rules! check_ranges {
($nz:ty, $out_of_range:expr, $in_range:expr) => {
for &n in $out_of_range {
assert_eq!(
db.query_row("SELECT ?1", [n], |r| r.get::<_, $nz>(0)),
Err(Error::IntegralValueOutOfRange(0, n)),
"{}",
std::any::type_name::<$nz>()
);
}
for &n in $in_range {
let non_zero = <$nz>::new(n).unwrap();
assert_eq!(
Ok(non_zero),
db.query_row("SELECT ?1", [non_zero], |r| r.get::<_, $nz>(0))
);
}
};
}
check_ranges!(std::num::NonZeroI8, &[0, -129, 128], &[-128, 1, 127]);
check_ranges!(
std::num::NonZeroI16,
&[0, -32769, 32768],
&[-32768, -1, 1, 32767]
);
check_ranges!(
std::num::NonZeroI32,
&[0, -2_147_483_649, 2_147_483_648],
&[-2_147_483_648, -1, 1, 2_147_483_647]
);
check_ranges!(
std::num::NonZeroI64,
&[0],
&[-2_147_483_648, -1, 1, 2_147_483_647, i64::MAX, i64::MIN]
);
check_ranges!(
std::num::NonZeroIsize,
&[0],
&[-2_147_483_648, -1, 1, 2_147_483_647]
);
check_ranges!(std::num::NonZeroU8, &[0, -2, -1, 256], &[1, 255]);
check_ranges!(std::num::NonZeroU16, &[0, -2, -1, 65536], &[1, 65535]);
check_ranges!(
std::num::NonZeroU32,
&[0, -2, -1, 4_294_967_296],
&[1, 4_294_967_295]
);
check_ranges!(
std::num::NonZeroU64,
&[0, -2, -1, -4_294_967_296],
&[1, 4_294_967_295, i64::MAX as u64]
);
check_ranges!(
std::num::NonZeroUsize,
&[0, -2, -1, -4_294_967_296],
&[1, 4_294_967_295]
);
Ok(())
}
} }

View File

@ -26,7 +26,8 @@
//! [`ToSql`] always succeeds except when storing a `u64` or `usize` value that //! [`ToSql`] always succeeds except when storing a `u64` or `usize` value that
//! cannot fit in an `INTEGER` (`i64`). Also note that SQLite ignores column //! cannot fit in an `INTEGER` (`i64`). Also note that SQLite ignores column
//! types, so if you store an `i64` in a column with type `REAL` it will be //! types, so if you store an `i64` in a column with type `REAL` it will be
//! stored as an `INTEGER`, not a `REAL`. //! stored as an `INTEGER`, not a `REAL` (unless the column is part of a
//! [STRICT table](https://www.sqlite.org/stricttables.html)).
//! //!
//! If the `time` feature is enabled, implementations are //! If the `time` feature is enabled, implementations are
//! provided for `time::OffsetDateTime` that use the RFC 3339 date/time format, //! provided for `time::OffsetDateTime` that use the RFC 3339 date/time format,
@ -210,10 +211,10 @@ mod test {
fn test_option() -> Result<()> { fn test_option() -> Result<()> {
let db = checked_memory_handle()?; let db = checked_memory_handle()?;
let s = Some("hello, world!"); let s = "hello, world!";
let b = Some(vec![1u8, 2, 3, 4]); let b = Some(vec![1u8, 2, 3, 4]);
db.execute("INSERT INTO foo(t) VALUES (?1)", [&s])?; db.execute("INSERT INTO foo(t) VALUES (?1)", [Some(s)])?;
db.execute("INSERT INTO foo(b) VALUES (?1)", [&b])?; db.execute("INSERT INTO foo(b) VALUES (?1)", [&b])?;
let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC")?; let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC")?;
@ -223,7 +224,7 @@ mod test {
let row1 = rows.next()?.unwrap(); let row1 = rows.next()?.unwrap();
let s1: Option<String> = row1.get_unwrap(0); let s1: Option<String> = row1.get_unwrap(0);
let b1: Option<Vec<u8>> = row1.get_unwrap(1); let b1: Option<Vec<u8>> = row1.get_unwrap(1);
assert_eq!(s.unwrap(), s1.unwrap()); assert_eq!(s, s1.unwrap());
assert!(b1.is_none()); assert!(b1.is_none());
} }
@ -352,7 +353,7 @@ mod test {
assert_eq!(Value::Integer(1), row.get::<_, Value>(2)?); assert_eq!(Value::Integer(1), row.get::<_, Value>(2)?);
match row.get::<_, Value>(3)? { match row.get::<_, Value>(3)? {
Value::Real(val) => assert!((1.5 - val).abs() < f64::EPSILON), Value::Real(val) => assert!((1.5 - val).abs() < f64::EPSILON),
x => panic!("Invalid Value {:?}", x), x => panic!("Invalid Value {x:?}"),
} }
assert_eq!(Value::Null, row.get::<_, Value>(4)?); assert_eq!(Value::Null, row.get::<_, Value>(4)?);
Ok(()) Ok(())

View File

@ -1,81 +1,174 @@
//! Convert formats 1-10 in [Time Values](https://sqlite.org/lang_datefunc.html#time_values) to time types.
//! [`ToSql`] and [`FromSql`] implementation for [`time::OffsetDateTime`]. //! [`ToSql`] and [`FromSql`] implementation for [`time::OffsetDateTime`].
//! [`ToSql`] and [`FromSql`] implementation for [`time::PrimitiveDateTime`].
//! [`ToSql`] and [`FromSql`] implementation for [`time::Date`].
//! [`ToSql`] and [`FromSql`] implementation for [`time::Time`].
//! Time Strings in:
//! - Format 2: "YYYY-MM-DD HH:MM"
//! - Format 5: "YYYY-MM-DDTHH:MM"
//! - Format 8: "HH:MM"
//! without an explicit second value will assume 0 seconds.
//! Time String that contain an optional timezone without an explicit date are unsupported.
//! All other assumptions described in [Time Values](https://sqlite.org/lang_datefunc.html#time_values) section are unsupported.
use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
use crate::{Error, Result}; use crate::{Error, Result};
use time::format_description::well_known::Rfc3339;
use time::format_description::FormatItem; use time::format_description::FormatItem;
use time::macros::format_description; use time::macros::format_description;
use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset}; use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
const PRIMITIVE_SHORT_DATE_TIME_FORMAT: &[FormatItem<'_>] = const OFFSET_DATE_TIME_ENCODING: &[FormatItem<'_>] = format_description!(
format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"); version = 2,
const PRIMITIVE_DATE_TIME_FORMAT: &[FormatItem<'_>] =
format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]");
const PRIMITIVE_DATE_TIME_Z_FORMAT: &[FormatItem<'_>] =
format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]Z");
const OFFSET_SHORT_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!(
"[year]-[month]-[day] [hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]"
);
const OFFSET_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!(
"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour sign:mandatory]:[offset_minute]" "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour sign:mandatory]:[offset_minute]"
); );
const PRIMITIVE_DATE_TIME_ENCODING: &[FormatItem<'_>] = format_description!(
version = 2,
"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]"
);
const TIME_ENCODING: &[FormatItem<'_>] =
format_description!(version = 2, "[hour]:[minute]:[second].[subsecond]");
const DATE_FORMAT: &[FormatItem<'_>] = format_description!(version = 2, "[year]-[month]-[day]");
const TIME_FORMAT: &[FormatItem<'_>] = format_description!(
version = 2,
"[hour]:[minute][optional [:[second][optional [.[subsecond]]]]]"
);
const PRIMITIVE_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!(
version = 2,
"[year]-[month]-[day][first [ ][T]][hour]:[minute][optional [:[second][optional [.[subsecond]]]]]"
);
const UTC_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!(
version = 2,
"[year]-[month]-[day][first [ ][T]][hour]:[minute][optional [:[second][optional [.[subsecond]]]]][optional [Z]]"
);
const OFFSET_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!(
version = 2,
"[year]-[month]-[day][first [ ][T]][hour]:[minute][optional [:[second][optional [.[subsecond]]]]][offset_hour sign:mandatory]:[offset_minute]"
);
const LEGACY_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!( const LEGACY_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!(
version = 2,
"[year]-[month]-[day] [hour]:[minute]:[second]:[subsecond] [offset_hour sign:mandatory]:[offset_minute]" "[year]-[month]-[day] [hour]:[minute]:[second]:[subsecond] [offset_hour sign:mandatory]:[offset_minute]"
); );
/// OffsetDatetime => RFC3339 format ("YYYY-MM-DD HH:MM:SS.SSS[+-]HH:MM")
impl ToSql for OffsetDateTime { impl ToSql for OffsetDateTime {
#[inline] #[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> { fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
// FIXME keep original offset
let time_string = self let time_string = self
.to_offset(UtcOffset::UTC) .format(&OFFSET_DATE_TIME_ENCODING)
.format(&PRIMITIVE_DATE_TIME_Z_FORMAT)
.map_err(|err| Error::ToSqlConversionFailure(err.into()))?; .map_err(|err| Error::ToSqlConversionFailure(err.into()))?;
Ok(ToSqlOutput::from(time_string)) Ok(ToSqlOutput::from(time_string))
} }
} }
// Supports parsing formats 2-7 from https://www.sqlite.org/lang_datefunc.html
// Formats 2-7 without a timezone assumes UTC
impl FromSql for OffsetDateTime { impl FromSql for OffsetDateTime {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| { value.as_str().and_then(|s| {
if s.len() > 10 && s.as_bytes()[10] == b'T' { if let Some(b' ') = s.as_bytes().get(23) {
// YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM // legacy
return OffsetDateTime::parse(s, &Rfc3339) return OffsetDateTime::parse(s, &LEGACY_DATE_TIME_FORMAT)
.map_err(|err| FromSqlError::Other(Box::new(err))); .map_err(|err| FromSqlError::Other(Box::new(err)));
} }
let s = s.strip_suffix('Z').unwrap_or(s); if s[8..].contains('+') || s[8..].contains('-') {
match s.len() { // Formats 2-7 with timezone
len if len <= 19 => { return OffsetDateTime::parse(s, &OFFSET_DATE_TIME_FORMAT)
// TODO YYYY-MM-DDTHH:MM:SS .map_err(|err| FromSqlError::Other(Box::new(err)));
PrimitiveDateTime::parse(s, &PRIMITIVE_SHORT_DATE_TIME_FORMAT)
.map(PrimitiveDateTime::assume_utc)
}
_ if s.as_bytes()[19] == b':' => {
// legacy
OffsetDateTime::parse(s, &LEGACY_DATE_TIME_FORMAT)
}
_ if s.as_bytes()[19] == b'.' => OffsetDateTime::parse(s, &OFFSET_DATE_TIME_FORMAT)
.or_else(|err| {
PrimitiveDateTime::parse(s, &PRIMITIVE_DATE_TIME_FORMAT)
.map(PrimitiveDateTime::assume_utc)
.map_err(|_| err)
}),
_ => OffsetDateTime::parse(s, &OFFSET_SHORT_DATE_TIME_FORMAT),
} }
// Formats 2-7 without timezone
PrimitiveDateTime::parse(s, &UTC_DATE_TIME_FORMAT)
.map(|p| p.assume_utc())
.map_err(|err| FromSqlError::Other(Box::new(err))) .map_err(|err| FromSqlError::Other(Box::new(err)))
}) })
} }
} }
/// ISO 8601 calendar date without timezone => "YYYY-MM-DD"
impl ToSql for Date {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let date_str = self
.format(&DATE_FORMAT)
.map_err(|err| Error::ToSqlConversionFailure(err.into()))?;
Ok(ToSqlOutput::from(date_str))
}
}
/// "YYYY-MM-DD" => ISO 8601 calendar date without timezone.
impl FromSql for Date {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| {
Date::parse(s, &DATE_FORMAT).map_err(|err| FromSqlError::Other(err.into()))
})
}
}
/// ISO 8601 time without timezone => "HH:MM:SS.SSS"
impl ToSql for Time {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let time_str = self
.format(&TIME_ENCODING)
.map_err(|err| Error::ToSqlConversionFailure(err.into()))?;
Ok(ToSqlOutput::from(time_str))
}
}
/// "HH:MM"/"HH:MM:SS"/"HH:MM:SS.SSS" => ISO 8601 time without timezone.
impl FromSql for Time {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| {
Time::parse(s, &TIME_FORMAT).map_err(|err| FromSqlError::Other(err.into()))
})
}
}
/// ISO 8601 combined date and time without timezone => "YYYY-MM-DD HH:MM:SS.SSS"
impl ToSql for PrimitiveDateTime {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let date_time_str = self
.format(&PRIMITIVE_DATE_TIME_ENCODING)
.map_err(|err| Error::ToSqlConversionFailure(err.into()))?;
Ok(ToSqlOutput::from(date_time_str))
}
}
/// YYYY-MM-DD HH:MM
/// YYYY-MM-DDTHH:MM
/// YYYY-MM-DD HH:MM:SS
/// YYYY-MM-DDTHH:MM:SS
/// YYYY-MM-DD HH:MM:SS.SSS
/// YYYY-MM-DDTHH:MM:SS.SSS
/// => ISO 8601 combined date and time with timezone
impl FromSql for PrimitiveDateTime {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| {
PrimitiveDateTime::parse(s, &PRIMITIVE_DATE_TIME_FORMAT)
.map_err(|err| FromSqlError::Other(err.into()))
})
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{Connection, Result}; use crate::{Connection, Result};
use time::format_description::well_known::Rfc3339; use time::macros::{date, datetime, time};
use time::OffsetDateTime; use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT, b BLOB)")?;
Ok(db)
}
#[test] #[test]
fn test_offset_date_time() -> Result<()> { fn test_offset_date_time() -> Result<()> {
let db = Connection::open_in_memory()?; let db = checked_memory_handle()?;
db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT)")?;
let mut ts_vec = vec![]; let mut ts_vec = vec![];
@ -103,47 +196,163 @@ mod test {
} }
#[test] #[test]
fn test_string_values() -> Result<()> { fn test_offset_date_time_parsing() -> Result<()> {
let db = Connection::open_in_memory()?; let db = checked_memory_handle()?;
for (s, t) in vec![ let tests = vec![
// Rfc3339
( (
"2013-10-07 08:23:19", "2013-10-07T08:23:19.123456789Z",
Ok(OffsetDateTime::parse("2013-10-07T08:23:19Z", &Rfc3339).unwrap()), datetime!(2013-10-07 8:23:19.123456789 UTC),
), ),
( (
"2013-10-07 08:23:19Z", "2013-10-07 08:23:19.123456789Z",
Ok(OffsetDateTime::parse("2013-10-07T08:23:19Z", &Rfc3339).unwrap()), datetime!(2013-10-07 8:23:19.123456789 UTC),
),
// Format 2
("2013-10-07 08:23", datetime!(2013-10-07 8:23 UTC)),
("2013-10-07 08:23Z", datetime!(2013-10-07 8:23 UTC)),
("2013-10-07 08:23+04:00", datetime!(2013-10-07 8:23 +4)),
// Format 3
("2013-10-07 08:23:19", datetime!(2013-10-07 8:23:19 UTC)),
("2013-10-07 08:23:19Z", datetime!(2013-10-07 8:23:19 UTC)),
(
"2013-10-07 08:23:19+04:00",
datetime!(2013-10-07 8:23:19 +4),
),
// Format 4
(
"2013-10-07 08:23:19.123",
datetime!(2013-10-07 8:23:19.123 UTC),
), ),
( (
"2013-10-07T08:23:19Z", "2013-10-07 08:23:19.123Z",
Ok(OffsetDateTime::parse("2013-10-07T08:23:19Z", &Rfc3339).unwrap()), datetime!(2013-10-07 8:23:19.123 UTC),
), ),
( (
"2013-10-07 08:23:19.120", "2013-10-07 08:23:19.123+04:00",
Ok(OffsetDateTime::parse("2013-10-07T08:23:19.120Z", &Rfc3339).unwrap()), datetime!(2013-10-07 8:23:19.123 +4),
),
// Format 5
("2013-10-07T08:23", datetime!(2013-10-07 8:23 UTC)),
("2013-10-07T08:23Z", datetime!(2013-10-07 8:23 UTC)),
("2013-10-07T08:23+04:00", datetime!(2013-10-07 8:23 +4)),
// Format 6
("2013-10-07T08:23:19", datetime!(2013-10-07 8:23:19 UTC)),
("2013-10-07T08:23:19Z", datetime!(2013-10-07 8:23:19 UTC)),
(
"2013-10-07T08:23:19+04:00",
datetime!(2013-10-07 8:23:19 +4),
),
// Format 7
(
"2013-10-07T08:23:19.123",
datetime!(2013-10-07 8:23:19.123 UTC),
), ),
( (
"2013-10-07 08:23:19.120Z", "2013-10-07T08:23:19.123Z",
Ok(OffsetDateTime::parse("2013-10-07T08:23:19.120Z", &Rfc3339).unwrap()), datetime!(2013-10-07 8:23:19.123 UTC),
), ),
( (
"2013-10-07T08:23:19.120Z", "2013-10-07T08:23:19.123+04:00",
Ok(OffsetDateTime::parse("2013-10-07T08:23:19.120Z", &Rfc3339).unwrap()), datetime!(2013-10-07 8:23:19.123 +4),
), ),
// Legacy
( (
"2013-10-07 04:23:19-04:00", "2013-10-07 08:23:12:987 -07:00",
Ok(OffsetDateTime::parse("2013-10-07T04:23:19-04:00", &Rfc3339).unwrap()), datetime!(2013-10-07 8:23:12.987 -7),
), ),
( ];
"2013-10-07 04:23:19.120-04:00",
Ok(OffsetDateTime::parse("2013-10-07T04:23:19.120-04:00", &Rfc3339).unwrap()), for (s, t) in tests {
), let result: OffsetDateTime = db.query_row("SELECT ?1", [s], |r| r.get(0))?;
( assert_eq!(result, t);
"2013-10-07T04:23:19.120-04:00", }
Ok(OffsetDateTime::parse("2013-10-07T04:23:19.120-04:00", &Rfc3339).unwrap()), Ok(())
), }
] {
let result: Result<OffsetDateTime> = db.query_row("SELECT ?1", [s], |r| r.get(0)); #[test]
fn test_date() -> Result<()> {
let db = checked_memory_handle()?;
let date = date!(2016 - 02 - 23);
db.execute("INSERT INTO foo (t) VALUES (?1)", [date])?;
let s: String = db.one_column("SELECT t FROM foo")?;
assert_eq!("2016-02-23", s);
let t: Date = db.one_column("SELECT t FROM foo")?;
assert_eq!(date, t);
Ok(())
}
#[test]
fn test_time() -> Result<()> {
let db = checked_memory_handle()?;
let time = time!(23:56:04.00001);
db.execute("INSERT INTO foo (t) VALUES (?1)", [time])?;
let s: String = db.one_column("SELECT t FROM foo")?;
assert_eq!("23:56:04.00001", s);
let v: Time = db.one_column("SELECT t FROM foo")?;
assert_eq!(time, v);
Ok(())
}
#[test]
fn test_primitive_date_time() -> Result<()> {
let db = checked_memory_handle()?;
let dt = date!(2016 - 02 - 23).with_time(time!(23:56:04));
db.execute("INSERT INTO foo (t) VALUES (?1)", [dt])?;
let s: String = db.one_column("SELECT t FROM foo")?;
assert_eq!("2016-02-23 23:56:04.0", s);
let v: PrimitiveDateTime = db.one_column("SELECT t FROM foo")?;
assert_eq!(dt, v);
db.execute("UPDATE foo set b = datetime(t)", [])?; // "YYYY-MM-DD HH:MM:SS"
let hms: PrimitiveDateTime = db.one_column("SELECT b FROM foo")?;
assert_eq!(dt, hms);
Ok(())
}
#[test]
fn test_date_parsing() -> Result<()> {
let db = checked_memory_handle()?;
let result: Date = db.query_row("SELECT ?1", ["2013-10-07"], |r| r.get(0))?;
assert_eq!(result, date!(2013 - 10 - 07));
Ok(())
}
#[test]
fn test_time_parsing() -> Result<()> {
let db = checked_memory_handle()?;
let tests = vec![
("08:23", time!(08:23)),
("08:23:19", time!(08:23:19)),
("08:23:19.111", time!(08:23:19.111)),
];
for (s, t) in tests {
let result: Time = db.query_row("SELECT ?1", [s], |r| r.get(0))?;
assert_eq!(result, t);
}
Ok(())
}
#[test]
fn test_primitive_date_time_parsing() -> Result<()> {
let db = checked_memory_handle()?;
let tests = vec![
("2013-10-07T08:23", datetime!(2013-10-07 8:23)),
("2013-10-07T08:23:19", datetime!(2013-10-07 8:23:19)),
("2013-10-07T08:23:19.111", datetime!(2013-10-07 8:23:19.111)),
("2013-10-07 08:23", datetime!(2013-10-07 8:23)),
("2013-10-07 08:23:19", datetime!(2013-10-07 8:23:19)),
("2013-10-07 08:23:19.111", datetime!(2013-10-07 8:23:19.111)),
];
for (s, t) in tests {
let result: PrimitiveDateTime = db.query_row("SELECT ?1", [s], |r| r.get(0))?;
assert_eq!(result, t); assert_eq!(result, t);
} }
Ok(()) Ok(())
@ -151,16 +360,66 @@ mod test {
#[test] #[test]
fn test_sqlite_functions() -> Result<()> { fn test_sqlite_functions() -> Result<()> {
let db = Connection::open_in_memory()?; let db = checked_memory_handle()?;
let result: Result<OffsetDateTime> = db.one_column("SELECT CURRENT_TIMESTAMP"); db.one_column::<Time>("SELECT CURRENT_TIME").unwrap();
db.one_column::<Date>("SELECT CURRENT_DATE").unwrap();
db.one_column::<PrimitiveDateTime>("SELECT CURRENT_TIMESTAMP")
.unwrap();
db.one_column::<OffsetDateTime>("SELECT CURRENT_TIMESTAMP")
.unwrap();
Ok(())
}
#[test]
fn test_time_param() -> Result<()> {
let db = checked_memory_handle()?;
let now = OffsetDateTime::now_utc().time();
let result: Result<bool> = db.query_row(
"SELECT 1 WHERE ?1 BETWEEN time('now', '-1 minute') AND time('now', '+1 minute')",
[now],
|r| r.get(0),
);
result.unwrap(); result.unwrap();
Ok(()) Ok(())
} }
#[test] #[test]
fn test_param() -> Result<()> { fn test_date_param() -> Result<()> {
let db = Connection::open_in_memory()?; let db = checked_memory_handle()?;
let result: Result<bool> = db.query_row("SELECT 1 WHERE ?1 BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [OffsetDateTime::now_utc()], |r| r.get(0)); let now = OffsetDateTime::now_utc().date();
let result: Result<bool> = db.query_row(
"SELECT 1 WHERE ?1 BETWEEN date('now', '-1 day') AND date('now', '+1 day')",
[now],
|r| r.get(0),
);
result.unwrap();
Ok(())
}
#[test]
fn test_primitive_date_time_param() -> Result<()> {
let db = checked_memory_handle()?;
let now = PrimitiveDateTime::new(
OffsetDateTime::now_utc().date(),
OffsetDateTime::now_utc().time(),
);
let result: Result<bool> = db.query_row(
"SELECT 1 WHERE ?1 BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')",
[now],
|r| r.get(0),
);
result.unwrap();
Ok(())
}
#[test]
fn test_offset_date_time_param() -> Result<()> {
let db = checked_memory_handle()?;
let result: Result<bool> = db.query_row(
"SELECT 1 WHERE ?1 BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')",
[OffsetDateTime::now_utc()],
|r| r.get(0),
);
result.unwrap(); result.unwrap();
Ok(()) Ok(())
} }

View File

@ -51,6 +51,12 @@ macro_rules! from_value(
#[inline] #[inline]
fn from(t: $t) -> Self { ToSqlOutput::Owned(t.into())} fn from(t: $t) -> Self { ToSqlOutput::Owned(t.into())}
} }
);
(non_zero $t:ty) => (
impl From<$t> for ToSqlOutput<'_> {
#[inline]
fn from(t: $t) -> Self { ToSqlOutput::Owned(t.get().into())}
}
) )
); );
from_value!(String); from_value!(String);
@ -68,6 +74,15 @@ from_value!(f32);
from_value!(f64); from_value!(f64);
from_value!(Vec<u8>); from_value!(Vec<u8>);
from_value!(non_zero std::num::NonZeroI8);
from_value!(non_zero std::num::NonZeroI16);
from_value!(non_zero std::num::NonZeroI32);
from_value!(non_zero std::num::NonZeroI64);
from_value!(non_zero std::num::NonZeroIsize);
from_value!(non_zero std::num::NonZeroU8);
from_value!(non_zero std::num::NonZeroU16);
from_value!(non_zero std::num::NonZeroU32);
// It would be nice if we could avoid the heap allocation (of the `Vec`) that // It would be nice if we could avoid the heap allocation (of the `Vec`) that
// `i128` needs in `Into<Value>`, but it's probably fine for the moment, and not // `i128` needs in `Into<Value>`, but it's probably fine for the moment, and not
// worth adding another case to Value. // worth adding another case to Value.
@ -75,6 +90,10 @@ from_value!(Vec<u8>);
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))] #[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
from_value!(i128); from_value!(i128);
#[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
from_value!(non_zero std::num::NonZeroI128);
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))] #[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
from_value!(uuid::Uuid); from_value!(uuid::Uuid);
@ -165,10 +184,23 @@ to_sql_self!(u32);
to_sql_self!(f32); to_sql_self!(f32);
to_sql_self!(f64); to_sql_self!(f64);
to_sql_self!(std::num::NonZeroI8);
to_sql_self!(std::num::NonZeroI16);
to_sql_self!(std::num::NonZeroI32);
to_sql_self!(std::num::NonZeroI64);
to_sql_self!(std::num::NonZeroIsize);
to_sql_self!(std::num::NonZeroU8);
to_sql_self!(std::num::NonZeroU16);
to_sql_self!(std::num::NonZeroU32);
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))] #[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
to_sql_self!(i128); to_sql_self!(i128);
#[cfg(feature = "i128_blob")]
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
to_sql_self!(std::num::NonZeroI128);
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))] #[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
to_sql_self!(uuid::Uuid); to_sql_self!(uuid::Uuid);
@ -186,12 +218,27 @@ macro_rules! to_sql_self_fallible(
))) )))
} }
} }
);
(non_zero $t:ty) => (
impl ToSql for $t {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::Owned(Value::Integer(
i64::try_from(self.get()).map_err(
// TODO: Include the values in the error message.
|err| Error::ToSqlConversionFailure(err.into())
)?
)))
}
}
) )
); );
// Special implementations for usize and u64 because these conversions can fail. // Special implementations for usize and u64 because these conversions can fail.
to_sql_self_fallible!(u64); to_sql_self_fallible!(u64);
to_sql_self_fallible!(usize); to_sql_self_fallible!(usize);
to_sql_self_fallible!(non_zero std::num::NonZeroU64);
to_sql_self_fallible!(non_zero std::num::NonZeroUsize);
impl<T: ?Sized> ToSql for &'_ T impl<T: ?Sized> ToSql for &'_ T
where where
@ -267,9 +314,26 @@ mod test {
is_to_sql::<i16>(); is_to_sql::<i16>();
is_to_sql::<i32>(); is_to_sql::<i32>();
is_to_sql::<i64>(); is_to_sql::<i64>();
is_to_sql::<isize>();
is_to_sql::<u8>(); is_to_sql::<u8>();
is_to_sql::<u16>(); is_to_sql::<u16>();
is_to_sql::<u32>(); is_to_sql::<u32>();
is_to_sql::<u64>();
is_to_sql::<usize>();
}
#[test]
fn test_nonzero_types() {
is_to_sql::<std::num::NonZeroI8>();
is_to_sql::<std::num::NonZeroI16>();
is_to_sql::<std::num::NonZeroI32>();
is_to_sql::<std::num::NonZeroI64>();
is_to_sql::<std::num::NonZeroIsize>();
is_to_sql::<std::num::NonZeroU8>();
is_to_sql::<std::num::NonZeroU16>();
is_to_sql::<std::num::NonZeroU32>();
is_to_sql::<std::num::NonZeroU64>();
is_to_sql::<std::num::NonZeroUsize>();
} }
#[test] #[test]
@ -398,6 +462,54 @@ mod test {
Ok(()) Ok(())
} }
#[cfg(feature = "i128_blob")]
#[test]
fn test_non_zero_i128() -> crate::Result<()> {
use std::num::NonZeroI128;
macro_rules! nz {
($x:expr) => {
NonZeroI128::new($x).unwrap()
};
}
let db = crate::Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (i128 BLOB, desc TEXT)")?;
db.execute(
"INSERT INTO foo(i128, desc) VALUES
(?1, 'neg one'), (?2, 'neg two'),
(?3, 'pos one'), (?4, 'pos two'),
(?5, 'min'), (?6, 'max')",
[
nz!(-1),
nz!(-2),
nz!(1),
nz!(2),
nz!(i128::MIN),
nz!(i128::MAX),
],
)?;
let mut stmt = db.prepare("SELECT i128, desc FROM foo ORDER BY i128 ASC")?;
let res = stmt
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
.collect::<Result<Vec<(NonZeroI128, String)>, _>>()?;
assert_eq!(
res,
&[
(nz!(i128::MIN), "min".to_owned()),
(nz!(-2), "neg two".to_owned()),
(nz!(-1), "neg one".to_owned()),
(nz!(1), "pos one".to_owned()),
(nz!(2), "pos two".to_owned()),
(nz!(i128::MAX), "max".to_owned()),
]
);
let err = db.query_row("SELECT ?1", [0i128], |row| row.get::<_, NonZeroI128>(0));
assert_eq!(err, Err(crate::Error::IntegralValueOutOfRange(0, 0)));
Ok(())
}
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[test] #[test]
fn test_uuid() -> crate::Result<()> { fn test_uuid() -> crate::Result<()> {

View File

@ -74,7 +74,7 @@ mod test {
); );
} }
e => { e => {
panic!("Expected conversion failure, got {}", e); panic!("Expected conversion failure, got {e}");
} }
} }
Ok(()) Ok(())

View File

@ -158,6 +158,7 @@ impl<'a> ValueRef<'a> {
impl From<ValueRef<'_>> for Value { impl From<ValueRef<'_>> for Value {
#[inline] #[inline]
#[track_caller]
fn from(borrowed: ValueRef<'_>) -> Value { fn from(borrowed: ValueRef<'_>) -> Value {
match borrowed { match borrowed {
ValueRef::Null => Value::Null, ValueRef::Null => Value::Null,

View File

@ -6,4 +6,4 @@ pub(crate) use small_cstr::SmallCString;
// Doesn't use any modern features or vtab stuff, but is only used by them. // Doesn't use any modern features or vtab stuff, but is only used by them.
mod sqlite_string; mod sqlite_string;
pub(crate) use sqlite_string::SqliteMallocString; pub(crate) use sqlite_string::{alloc, SqliteMallocString};

View File

@ -7,6 +7,12 @@ use std::marker::PhantomData;
use std::os::raw::{c_char, c_int}; use std::os::raw::{c_char, c_int};
use std::ptr::NonNull; use std::ptr::NonNull;
// Space to hold this string must be obtained
// from an SQLite memory allocation function
pub(crate) fn alloc(s: &str) -> *mut c_char {
SqliteMallocString::from_str(s).into_raw()
}
/// A string we own that's allocated on the SQLite heap. Automatically calls /// A string we own that's allocated on the SQLite heap. Automatically calls
/// `sqlite3_free` when dropped, unless `into_raw` (or `into_inner`) is called /// `sqlite3_free` when dropped, unless `into_raw` (or `into_inner`) is called
/// on it. If constructed from a rust string, `sqlite3_malloc` is used. /// on it. If constructed from a rust string, `sqlite3_malloc` is used.
@ -100,7 +106,6 @@ impl SqliteMallocString {
/// This means it's safe to use in extern "C" functions even outside of /// This means it's safe to use in extern "C" functions even outside of
/// `catch_unwind`. /// `catch_unwind`.
pub(crate) fn from_str(s: &str) -> Self { pub(crate) fn from_str(s: &str) -> Self {
use std::convert::TryFrom;
let s = if s.as_bytes().contains(&0) { let s = if s.as_bytes().contains(&0) {
std::borrow::Cow::Owned(make_nonnull(s)) std::borrow::Cow::Owned(make_nonnull(s))
} else { } else {

View File

@ -113,10 +113,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
match param { match param {
"filename" => { "filename" => {
if !Path::new(value).exists() { if !Path::new(value).exists() {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!("file '{value}' does not exist")));
"file '{}' does not exist",
value
)));
} }
vtab.filename = value.to_owned(); vtab.filename = value.to_owned();
} }
@ -137,8 +134,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
n_col = Some(n); n_col = Some(n);
} else { } else {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"unrecognized argument to 'columns': {}", "unrecognized argument to 'columns': {value}"
value
))); )));
} }
} }
@ -147,8 +143,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
vtab.has_headers = b; vtab.has_headers = b;
} else { } else {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"unrecognized argument to 'header': {}", "unrecognized argument to 'header': {value}"
value
))); )));
} }
} }
@ -157,8 +152,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
vtab.delimiter = b; vtab.delimiter = b;
} else { } else {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"unrecognized argument to 'delimiter': {}", "unrecognized argument to 'delimiter': {value}"
value
))); )));
} }
} }
@ -171,15 +165,13 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
} }
} else { } else {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"unrecognized argument to 'quote': {}", "unrecognized argument to 'quote': {value}"
value
))); )));
} }
} }
_ => { _ => {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"unrecognized parameter '{}'", "unrecognized parameter '{param}'"
param
))); )));
} }
} }
@ -326,8 +318,7 @@ unsafe impl VTabCursor for CsvTabCursor<'_> {
fn column(&self, ctx: &mut Context, col: c_int) -> Result<()> { fn column(&self, ctx: &mut Context, col: c_int) -> Result<()> {
if col < 0 || col as usize >= self.cols.len() { if col < 0 || col as usize >= self.cols.len() {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"column index out of bounds: {}", "column index out of bounds: {col}"
col
))); )));
} }
if self.cols.is_empty() { if self.cols.is_empty() {

View File

@ -17,10 +17,11 @@ use std::ptr;
use std::slice; use std::slice;
use crate::context::set_result; use crate::context::set_result;
use crate::error::error_from_sqlite_code; use crate::error::{error_from_sqlite_code, to_sqlite_error};
use crate::ffi; use crate::ffi;
pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor}; pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor};
use crate::types::{FromSql, FromSqlError, ToSql, ValueRef}; use crate::types::{FromSql, FromSqlError, ToSql, ValueRef};
use crate::util::alloc;
use crate::{str_to_cstring, Connection, Error, InnerConnection, Result}; use crate::{str_to_cstring, Connection, Error, InnerConnection, Result};
// let conn: Connection = ...; // let conn: Connection = ...;
@ -195,6 +196,8 @@ pub enum VTabConfig {
Innocuous = 2, Innocuous = 2,
/// Equivalent to SQLITE_VTAB_DIRECTONLY /// Equivalent to SQLITE_VTAB_DIRECTONLY
DirectOnly = 3, DirectOnly = 3,
/// Equivalent to SQLITE_VTAB_USES_ALL_SCHEMAS
UsesAllSchemas = 4,
} }
/// `feature = "vtab"` /// `feature = "vtab"`
@ -882,7 +885,7 @@ pub fn dequote(s: &str) -> &str {
return s; return s;
} }
match s.bytes().next() { match s.bytes().next() {
Some(b) if b == b'"' || b == b'\'' => match s.bytes().rev().next() { Some(b) if b == b'"' || b == b'\'' => match s.bytes().next_back() {
Some(e) if e == b => &s[1..s.len() - 1], // FIXME handle inner escaped quote(s) Some(e) if e == b => &s[1..s.len() - 1], // FIXME handle inner escaped quote(s)
_ => s, _ => s,
}, },
@ -962,8 +965,7 @@ where
ffi::SQLITE_OK ffi::SQLITE_OK
} else { } else {
let err = error_from_sqlite_code(rc, None); let err = error_from_sqlite_code(rc, None);
*err_msg = alloc(&err.to_string()); to_sqlite_error(&err, err_msg)
rc
} }
} }
Err(err) => { Err(err) => {
@ -971,16 +973,7 @@ where
ffi::SQLITE_ERROR ffi::SQLITE_ERROR
} }
}, },
Err(Error::SqliteFailure(err, s)) => { Err(err) => to_sqlite_error(&err, err_msg),
if let Some(s) = s {
*err_msg = alloc(&s);
}
err.extended_code
}
Err(err) => {
*err_msg = alloc(&err.to_string());
ffi::SQLITE_ERROR
}
} }
} }
@ -1014,8 +1007,7 @@ where
ffi::SQLITE_OK ffi::SQLITE_OK
} else { } else {
let err = error_from_sqlite_code(rc, None); let err = error_from_sqlite_code(rc, None);
*err_msg = alloc(&err.to_string()); to_sqlite_error(&err, err_msg)
rc
} }
} }
Err(err) => { Err(err) => {
@ -1023,16 +1015,7 @@ where
ffi::SQLITE_ERROR ffi::SQLITE_ERROR
} }
}, },
Err(Error::SqliteFailure(err, s)) => { Err(err) => to_sqlite_error(&err, err_msg),
if let Some(s) = s {
*err_msg = alloc(&s);
}
err.extended_code
}
Err(err) => {
*err_msg = alloc(&err.to_string());
ffi::SQLITE_ERROR
}
} }
} }
@ -1309,12 +1292,6 @@ unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) ->
} }
} }
// Space to hold this string must be obtained
// from an SQLite memory allocation function
fn alloc(s: &str) -> *mut c_char {
crate::util::SqliteMallocString::from_str(s).into_raw()
}
#[cfg(feature = "array")] #[cfg(feature = "array")]
#[cfg_attr(docsrs, doc(cfg(feature = "array")))] #[cfg_attr(docsrs, doc(cfg(feature = "array")))]
pub mod array; pub mod array;

View File

@ -200,19 +200,19 @@ unsafe impl VTabCursor for SeriesTabCursor<'_> {
let mut idx_num = QueryPlanFlags::from_bits_truncate(idx_num); let mut idx_num = QueryPlanFlags::from_bits_truncate(idx_num);
let mut i = 0; let mut i = 0;
if idx_num.contains(QueryPlanFlags::START) { if idx_num.contains(QueryPlanFlags::START) {
self.min_value = args.get(i)?; self.min_value = args.get::<Option<_>>(i)?.unwrap_or_default();
i += 1; i += 1;
} else { } else {
self.min_value = 0; self.min_value = 0;
} }
if idx_num.contains(QueryPlanFlags::STOP) { if idx_num.contains(QueryPlanFlags::STOP) {
self.max_value = args.get(i)?; self.max_value = args.get::<Option<_>>(i)?.unwrap_or_default();
i += 1; i += 1;
} else { } else {
self.max_value = 0xffff_ffff; self.max_value = 0xffff_ffff;
} }
if idx_num.contains(QueryPlanFlags::STEP) { if idx_num.contains(QueryPlanFlags::STEP) {
self.step = args.get(i)?; self.step = args.get::<Option<_>>(i)?.unwrap_or_default();
if self.step == 0 { if self.step == 0 {
self.step = 1; self.step = 1;
} else if self.step < 0 { } else if self.step < 0 {
@ -316,6 +316,26 @@ mod test {
let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?; let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?;
assert_eq!(vec![30, 25, 20, 15, 10, 5, 0], series); assert_eq!(vec![30, 25, 20, 15, 10, 5, 0], series);
let mut s = db.prepare("SELECT * FROM generate_series(NULL)")?;
let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?;
let empty = Vec::<i32>::new();
assert_eq!(empty, series);
let mut s = db.prepare("SELECT * FROM generate_series(5,NULL)")?;
let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?;
assert_eq!(empty, series);
let mut s = db.prepare("SELECT * FROM generate_series(5,10,NULL)")?;
let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?;
assert_eq!(empty, series);
let mut s = db.prepare("SELECT * FROM generate_series(NULL,10,2)")?;
let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?;
assert_eq!(empty, series);
let mut s = db.prepare("SELECT * FROM generate_series(5,NULL,2)")?;
let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?;
assert_eq!(empty, series);
let mut s = db.prepare("SELECT * FROM generate_series(NULL) ORDER BY value DESC")?;
let series: Vec<i32> = s.query([])?.map(|r| r.get(0)).collect()?;
assert_eq!(empty, series);
Ok(()) Ok(())
} }
} }

View File

@ -56,8 +56,7 @@ impl VTabLog {
"schema" => { "schema" => {
if schema.is_some() { if schema.is_some() {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"more than one '{}' parameter", "more than one '{param}' parameter"
param
))); )));
} }
schema = Some(value.to_owned()) schema = Some(value.to_owned())
@ -65,8 +64,7 @@ impl VTabLog {
"rows" => { "rows" => {
if n_row.is_some() { if n_row.is_some() {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"more than one '{}' parameter", "more than one '{param}' parameter"
param
))); )));
} }
if let Ok(n) = i64::from_str(value) { if let Ok(n) = i64::from_str(value) {
@ -75,8 +73,7 @@ impl VTabLog {
} }
_ => { _ => {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
"unrecognized parameter '{}'", "unrecognized parameter '{param}'"
param
))); )));
} }
} }