mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-25 02:21:37 +08:00
Merge remote-tracking branch 'upstream/master' into captured_identifiers
This commit is contained in:
commit
a927ce1bb6
9
.github/dependabot.yml
vendored
Normal file
9
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "cargo"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
76
.github/workflows/main.yml
vendored
76
.github/workflows/main.yml
vendored
@ -17,6 +17,9 @@ env:
|
||||
# smaller. (TODO: use -Cdebuginfo=0 if it doesn't make backtraces useless)
|
||||
RUSTFLAGS: -Cdebuginfo=1
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test ${{ matrix.target }}
|
||||
@ -36,7 +39,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
# This has a matcher for test panics, so we use it even though elsewhere
|
||||
# we use actions-rs/toolchain.
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
@ -48,7 +51,7 @@ jobs:
|
||||
# complete" that needs to do the complete build (that is, including
|
||||
# `--features 'bundled-full session buildtime_bindgen`), which is very
|
||||
# slow, and has several deps.
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with: { sharedKey: fullBuild }
|
||||
|
||||
- run: cargo build --features bundled --workspace --all-targets --verbose
|
||||
@ -80,14 +83,14 @@ jobs:
|
||||
# TODO: find a way to test this on windows :(
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
# This has a matcher for test panics, so we use it even though elsewhere
|
||||
# we use actions-rs/toolchain.
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
with:
|
||||
rust-version: stable${{ matrix.host }}
|
||||
targets: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with: { sharedKey: fullBuild }
|
||||
|
||||
- run: cargo test --features 'bundled-sqlcipher' --workspace --all-targets --verbose
|
||||
@ -113,9 +116,9 @@ jobs:
|
||||
name: Test with winsqlite3
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
# TODO: Should this test GNU toolchain? What about +crt-static?
|
||||
# TODO: Is it worth testing other features?
|
||||
- run: cargo build --features winsqlite3 --workspace --all-targets --verbose
|
||||
@ -125,9 +128,9 @@ jobs:
|
||||
name: Test with sqlcipher
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: sudo apt-get install sqlcipher libsqlcipher-dev
|
||||
- run: sqlcipher --version
|
||||
# TODO: Is it worth testing other features?
|
||||
@ -138,13 +141,13 @@ jobs:
|
||||
name: Address Sanitizer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
# Need nightly rust.
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
with:
|
||||
rust-version: nightly
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Tests with asan
|
||||
env:
|
||||
RUSTFLAGS: -Zsanitizer=address -Cdebuginfo=0
|
||||
@ -162,11 +165,11 @@ jobs:
|
||||
name: Clippy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
with:
|
||||
components: clippy
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: cargo clippy --all-targets --workspace --features bundled -- -D warnings
|
||||
# Clippy with all non-conflicting features
|
||||
- run: cargo clippy --all-targets --workspace --features 'bundled-full session buildtime_bindgen' -- -D warnings
|
||||
@ -176,7 +179,7 @@ jobs:
|
||||
name: Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
with:
|
||||
components: rustfmt
|
||||
@ -187,9 +190,9 @@ jobs:
|
||||
name: Docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with: { sharedKey: fullBuild }
|
||||
- run: cargo doc --features 'bundled-full session buildtime_bindgen' --no-deps
|
||||
env: { RUSTDOCFLAGS: -Dwarnings }
|
||||
@ -198,15 +201,38 @@ jobs:
|
||||
name: Generate code coverage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
# TODO: we don't use caching here because it's unclear if it will cause
|
||||
# the coverage to get less accurate (this is the case for some coverage
|
||||
# tools, although possibly not tarpaulin?)
|
||||
- name: Run cargo-tarpaulin
|
||||
uses: actions-rs/tarpaulin@v0.1
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
args: '--features "bundled-full session buildtime_bindgen"'
|
||||
|
||||
components: 'llvm-tools-preview'
|
||||
- uses: taiki-e/install-action@main
|
||||
with:
|
||||
tool: grcov
|
||||
- name: Run tests for coverage
|
||||
run: |
|
||||
cargo test --verbose
|
||||
cargo test --features="bundled-full" --verbose
|
||||
cargo test --features="bundled-full session buildtime_bindgen" --verbose
|
||||
cargo test --features="bundled-sqlcipher-vendored-openssl" --verbose
|
||||
env:
|
||||
RUSTFLAGS: -Cinstrument-coverage
|
||||
RUSTDOCFLAGS: -Cinstrument-coverage
|
||||
LLVM_PROFILE_FILE: rusqlite-%p-%m.profraw
|
||||
- name: Produce coverage info
|
||||
run: |
|
||||
grcov $(find . -name "rusqlite-*.profraw" -print) \
|
||||
-s . \
|
||||
--branch \
|
||||
--ignore-not-existing \
|
||||
--ignore='target/*' \
|
||||
--ignore='benches/*' \
|
||||
--ignore='/*' \
|
||||
--binary-path ./target/debug/ \
|
||||
--excl-line='#\[derive' \
|
||||
-t lcov \
|
||||
-o lcov.info
|
||||
- name: Upload to codecov.io
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: lcov.info
|
||||
fail_ci_if_error: true
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "rusqlite"
|
||||
# Note: Update version in README.md when you change this.
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
authors = ["The rusqlite developers"]
|
||||
edition = "2018"
|
||||
description = "Ergonomic wrapper for SQLite"
|
||||
@ -112,13 +112,12 @@ bundled-full = ["modern-full", "bundled"]
|
||||
|
||||
[dependencies]
|
||||
time = { version = "0.3.0", features = ["formatting", "macros", "parsing"], optional = true }
|
||||
bitflags = "1.2"
|
||||
bitflags = "2.0"
|
||||
hashlink = "0.8"
|
||||
chrono = { version = "0.4", optional = true, default-features = false, features = ["clock"] }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
csv = { version = "1.1", optional = true }
|
||||
url = { version = "2.1", optional = true }
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
fallible-iterator = "0.2"
|
||||
fallible-streaming-iterator = "0.1"
|
||||
uuid = { version = "1.0", optional = true }
|
||||
@ -137,7 +136,7 @@ bencher = "0.1"
|
||||
|
||||
[dependencies.libsqlite3-sys]
|
||||
path = "libsqlite3-sys"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
|
||||
# FIXME optional
|
||||
[dependencies.rusqlite-macros]
|
||||
|
@ -27,7 +27,7 @@ In your Cargo.toml:
|
||||
# That said, it's not ideal for all scenarios and in particular, generic
|
||||
# libraries built around `rusqlite` should probably not enable it, which
|
||||
# is why it is not a default feature -- it could become hard to disable.
|
||||
rusqlite = { version = "0.28.0", features = ["bundled"] }
|
||||
rusqlite = { version = "0.29.0", features = ["bundled"] }
|
||||
```
|
||||
|
||||
Simple example usage:
|
||||
@ -149,11 +149,11 @@ You can adjust this behavior in a number of ways:
|
||||
* If you use the `bundled`, `bundled-sqlcipher`, or `bundled-sqlcipher-vendored-openssl` features, `libsqlite3-sys` will use the
|
||||
[cc](https://crates.io/crates/cc) crate to compile SQLite or SQLCipher from source and
|
||||
link against that. This source is embedded in the `libsqlite3-sys` crate and
|
||||
is currently SQLite 3.39.0 (as of `rusqlite` 0.28.0 / `libsqlite3-sys`
|
||||
0.25.0). This is probably the simplest solution to any build problems. You can enable this by adding the following in your `Cargo.toml` file:
|
||||
is currently SQLite 3.41.2 (as of `rusqlite` 0.29.0 / `libsqlite3-sys`
|
||||
0.26.0). This is probably the simplest solution to any build problems. You can enable this by adding the following in your `Cargo.toml` file:
|
||||
```toml
|
||||
[dependencies.rusqlite]
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
features = ["bundled"]
|
||||
```
|
||||
* When using any of the `bundled` features, the build script will honor `SQLITE_MAX_VARIABLE_NUMBER` and `SQLITE_MAX_EXPR_DEPTH` variables. It will also honor a `LIBSQLITE3_FLAGS` variable, which can have a format like `"-USQLITE_ALPHA -DSQLITE_BETA SQLITE_GAMMA ..."`. That would disable the `SQLITE_ALPHA` flag, and set the `SQLITE_BETA` and `SQLITE_GAMMA` flags. (The initial `-D` can be omitted, as on the last one.)
|
||||
|
@ -1 +1,2 @@
|
||||
doc-valid-idents = ["SQLite", "lang_transaction"]
|
||||
msrv = "1.55.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.25.2"
|
||||
version = "0.26.0"
|
||||
authors = ["The rusqlite developers"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/rusqlite/rusqlite"
|
||||
@ -44,7 +44,7 @@ winsqlite3 = []
|
||||
openssl-sys = { version = "0.9", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = { version = "0.62", optional = true, default-features = false, features = ["runtime"] }
|
||||
bindgen = { version = "0.64", optional = true, default-features = false, features = ["runtime"] }
|
||||
pkg-config = { version = "0.3.19", optional = true }
|
||||
cc = { version = "1.0", optional = true }
|
||||
vcpkg = { version = "0.2", optional = true }
|
||||
|
@ -1,5 +1,29 @@
|
||||
/* automatically generated by rust-bindgen 0.60.1 */
|
||||
|
||||
extern "C" {
|
||||
pub fn sqlite3_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::std::os::raw::c_int,
|
||||
>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn sqlite3_cancel_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::std::os::raw::c_int,
|
||||
>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
|
||||
pub const SQLITE_VERSION: &[u8; 7usize] = b"3.14.0\0";
|
||||
pub const SQLITE_VERSION_NUMBER: i32 = 3014000;
|
||||
pub const SQLITE_SOURCE_ID: &[u8; 61usize] =
|
||||
@ -1729,16 +1753,6 @@ extern "C" {
|
||||
onoff: ::std::os::raw::c_int,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<unsafe extern "C" fn()>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_cancel_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<unsafe extern "C" fn()>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_reset_auto_extension();
|
||||
}
|
||||
@ -1879,10 +1893,10 @@ pub struct sqlite3_module {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info {
|
||||
pub nConstraint: ::std::os::raw::c_int,
|
||||
pub aConstraint: *mut sqlite3_index_info_sqlite3_index_constraint,
|
||||
pub aConstraint: *mut sqlite3_index_constraint,
|
||||
pub nOrderBy: ::std::os::raw::c_int,
|
||||
pub aOrderBy: *mut sqlite3_index_info_sqlite3_index_orderby,
|
||||
pub aConstraintUsage: *mut sqlite3_index_info_sqlite3_index_constraint_usage,
|
||||
pub aOrderBy: *mut sqlite3_index_orderby,
|
||||
pub aConstraintUsage: *mut sqlite3_index_constraint_usage,
|
||||
pub idxNum: ::std::os::raw::c_int,
|
||||
pub idxStr: *mut ::std::os::raw::c_char,
|
||||
pub needToFreeIdxStr: ::std::os::raw::c_int,
|
||||
@ -1894,7 +1908,7 @@ pub struct sqlite3_index_info {
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_constraint {
|
||||
pub struct sqlite3_index_constraint {
|
||||
pub iColumn: ::std::os::raw::c_int,
|
||||
pub op: ::std::os::raw::c_uchar,
|
||||
pub usable: ::std::os::raw::c_uchar,
|
||||
@ -1902,13 +1916,13 @@ pub struct sqlite3_index_info_sqlite3_index_constraint {
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_orderby {
|
||||
pub struct sqlite3_index_orderby {
|
||||
pub iColumn: ::std::os::raw::c_int,
|
||||
pub desc: ::std::os::raw::c_uchar,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_constraint_usage {
|
||||
pub struct sqlite3_index_constraint_usage {
|
||||
pub argvIndex: ::std::os::raw::c_int,
|
||||
pub omit: ::std::os::raw::c_uchar,
|
||||
}
|
||||
|
@ -181,16 +181,10 @@ mod build_bundled {
|
||||
cfg.include(env::var("DEP_OPENSSL_INCLUDE").unwrap());
|
||||
// cargo will resolve downstream to the static lib in
|
||||
// openssl-sys
|
||||
} else if is_windows {
|
||||
// Windows without `-vendored-openssl` takes this to link against a prebuilt
|
||||
// OpenSSL lib
|
||||
cfg.include(inc_dir.to_string_lossy().as_ref());
|
||||
let lib = lib_dir.join("libcrypto.lib");
|
||||
cfg.flag(lib.to_string_lossy().as_ref());
|
||||
} else if use_openssl {
|
||||
cfg.include(inc_dir.to_string_lossy().as_ref());
|
||||
// branch not taken on Windows, just `crypto` is fine.
|
||||
println!("cargo:rustc-link-lib=dylib=crypto");
|
||||
let lib_name = if is_windows { "libcrypto" } else { "crypto" };
|
||||
println!("cargo:rustc-link-lib=dylib={}", lib_name);
|
||||
println!("cargo:rustc-link-search={}", lib_dir.to_string_lossy());
|
||||
} else if is_apple {
|
||||
cfg.flag("-DSQLCIPHER_CRYPTO_CC");
|
||||
@ -503,6 +497,11 @@ mod bindings {
|
||||
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
|
||||
@ -524,6 +523,34 @@ mod bindings {
|
||||
.trust_clang_mangling(false)
|
||||
.header(header.clone())
|
||||
.parse_callbacks(Box::new(SqliteTypeChooser))
|
||||
.blocklist_function("sqlite3_auto_extension")
|
||||
.raw_line(
|
||||
r#"extern "C" {
|
||||
pub fn sqlite3_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::std::os::raw::c_int,
|
||||
>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}"#,
|
||||
)
|
||||
.blocklist_function("sqlite3_cancel_auto_extension")
|
||||
.raw_line(
|
||||
r#"extern "C" {
|
||||
pub fn sqlite3_cancel_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::std::os::raw::c_int,
|
||||
>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}"#,
|
||||
)
|
||||
.rustfmt_bindings(true);
|
||||
|
||||
if cfg!(any(feature = "sqlcipher", feature = "bundled-sqlcipher")) {
|
||||
|
@ -1,9 +1,33 @@
|
||||
/* automatically generated by rust-bindgen 0.61.0 */
|
||||
/* automatically generated by rust-bindgen 0.63.0 */
|
||||
|
||||
pub const SQLITE_VERSION: &[u8; 7usize] = b"3.39.2\0";
|
||||
pub const SQLITE_VERSION_NUMBER: i32 = 3039002;
|
||||
extern "C" {
|
||||
pub fn sqlite3_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::std::os::raw::c_int,
|
||||
>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn sqlite3_cancel_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::std::os::raw::c_int,
|
||||
>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
|
||||
pub const SQLITE_VERSION: &[u8; 7usize] = b"3.39.4\0";
|
||||
pub const SQLITE_VERSION_NUMBER: i32 = 3039004;
|
||||
pub const SQLITE_SOURCE_ID: &[u8; 85usize] =
|
||||
b"2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668ealt1\0";
|
||||
b"2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26alt1\0";
|
||||
pub const SQLITE_OK: i32 = 0;
|
||||
pub const SQLITE_ERROR: i32 = 1;
|
||||
pub const SQLITE_INTERNAL: i32 = 2;
|
||||
@ -2036,16 +2060,6 @@ extern "C" {
|
||||
onoff: ::std::os::raw::c_int,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<unsafe extern "C" fn()>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_cancel_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<unsafe extern "C" fn()>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_reset_auto_extension();
|
||||
}
|
||||
@ -2189,10 +2203,10 @@ pub struct sqlite3_module {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info {
|
||||
pub nConstraint: ::std::os::raw::c_int,
|
||||
pub aConstraint: *mut sqlite3_index_info_sqlite3_index_constraint,
|
||||
pub aConstraint: *mut sqlite3_index_constraint,
|
||||
pub nOrderBy: ::std::os::raw::c_int,
|
||||
pub aOrderBy: *mut sqlite3_index_info_sqlite3_index_orderby,
|
||||
pub aConstraintUsage: *mut sqlite3_index_info_sqlite3_index_constraint_usage,
|
||||
pub aOrderBy: *mut sqlite3_index_orderby,
|
||||
pub aConstraintUsage: *mut sqlite3_index_constraint_usage,
|
||||
pub idxNum: ::std::os::raw::c_int,
|
||||
pub idxStr: *mut ::std::os::raw::c_char,
|
||||
pub needToFreeIdxStr: ::std::os::raw::c_int,
|
||||
@ -2204,7 +2218,7 @@ pub struct sqlite3_index_info {
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_constraint {
|
||||
pub struct sqlite3_index_constraint {
|
||||
pub iColumn: ::std::os::raw::c_int,
|
||||
pub op: ::std::os::raw::c_uchar,
|
||||
pub usable: ::std::os::raw::c_uchar,
|
||||
@ -2212,13 +2226,13 @@ pub struct sqlite3_index_info_sqlite3_index_constraint {
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_orderby {
|
||||
pub struct sqlite3_index_orderby {
|
||||
pub iColumn: ::std::os::raw::c_int,
|
||||
pub desc: ::std::os::raw::c_uchar,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_constraint_usage {
|
||||
pub struct sqlite3_index_constraint_usage {
|
||||
pub argvIndex: ::std::os::raw::c_int,
|
||||
pub omit: ::std::os::raw::c_uchar,
|
||||
}
|
||||
|
309
libsqlite3-sys/sqlcipher/sqlite3.c
vendored
309
libsqlite3-sys/sqlcipher/sqlite3.c
vendored
@ -1,6 +1,6 @@
|
||||
/******************************************************************************
|
||||
** This file is an amalgamation of many separate C source files from SQLite
|
||||
** version 3.39.2. By combining all the individual C code files into this
|
||||
** version 3.39.4. By combining all the individual C code files into this
|
||||
** single large file, the entire code can be compiled as a single translation
|
||||
** unit. This allows many compilers to do optimizations that would not be
|
||||
** possible if the files were compiled separately. Performance improvements
|
||||
@ -452,9 +452,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.39.2"
|
||||
#define SQLITE_VERSION_NUMBER 3039002
|
||||
#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668ealt1"
|
||||
#define SQLITE_VERSION "3.39.4"
|
||||
#define SQLITE_VERSION_NUMBER 3039004
|
||||
#define SQLITE_SOURCE_ID "2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26alt1"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@ -13204,6 +13204,11 @@ struct fts5_api {
|
||||
/************** End of sqlite3.h *********************************************/
|
||||
/************** Continuing where we left off in sqliteInt.h ******************/
|
||||
|
||||
/*
|
||||
** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory.
|
||||
*/
|
||||
#define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1
|
||||
|
||||
/*
|
||||
** Include the configuration header output by 'configure' if we're using the
|
||||
** autoconf-based build
|
||||
@ -29665,8 +29670,13 @@ SQLITE_PRIVATE void *sqlite3OomFault(sqlite3 *db){
|
||||
}
|
||||
DisableLookaside;
|
||||
if( db->pParse ){
|
||||
Parse *pParse;
|
||||
sqlite3ErrorMsg(db->pParse, "out of memory");
|
||||
db->pParse->rc = SQLITE_NOMEM_BKPT;
|
||||
for(pParse=db->pParse->pOuterParse; pParse; pParse = pParse->pOuterParse){
|
||||
pParse->nErr++;
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -33561,7 +33571,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( db!=0 );
|
||||
assert( db->pParse==pParse );
|
||||
assert( db->pParse==pParse || db->pParse->pToplevel==pParse );
|
||||
db->errByteOffset = -2;
|
||||
va_start(ap, zFormat);
|
||||
zMsg = sqlite3VMPrintf(db, zFormat, ap);
|
||||
@ -41424,6 +41434,7 @@ static const char *unixTempFileDir(void){
|
||||
static int unixGetTempname(int nBuf, char *zBuf){
|
||||
const char *zDir;
|
||||
int iLimit = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
/* It's odd to simulate an io-error here, but really this is just
|
||||
** using the io-error infrastructure to test that SQLite handles this
|
||||
@ -41432,18 +41443,26 @@ static int unixGetTempname(int nBuf, char *zBuf){
|
||||
zBuf[0] = 0;
|
||||
SimulateIOError( return SQLITE_IOERR );
|
||||
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
zDir = unixTempFileDir();
|
||||
if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
|
||||
do{
|
||||
u64 r;
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
assert( nBuf>2 );
|
||||
zBuf[nBuf-2] = 0;
|
||||
sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
|
||||
zDir, r, 0);
|
||||
if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR;
|
||||
}while( osAccess(zBuf,0)==0 );
|
||||
return SQLITE_OK;
|
||||
if( zDir==0 ){
|
||||
rc = SQLITE_IOERR_GETTEMPPATH;
|
||||
}else{
|
||||
do{
|
||||
u64 r;
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
assert( nBuf>2 );
|
||||
zBuf[nBuf-2] = 0;
|
||||
sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
|
||||
zDir, r, 0);
|
||||
if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ){
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
}while( osAccess(zBuf,0)==0 );
|
||||
}
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
|
||||
@ -45582,10 +45601,12 @@ SQLITE_API int sqlite3_win32_set_directory8(
|
||||
const char *zValue /* New value for directory being set or reset */
|
||||
){
|
||||
char **ppDirectory = 0;
|
||||
int rc;
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
int rc = sqlite3_initialize();
|
||||
rc = sqlite3_initialize();
|
||||
if( rc ) return rc;
|
||||
#endif
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
|
||||
ppDirectory = &sqlite3_data_directory;
|
||||
}else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
|
||||
@ -45600,14 +45621,19 @@ SQLITE_API int sqlite3_win32_set_directory8(
|
||||
if( zValue && zValue[0] ){
|
||||
zCopy = sqlite3_mprintf("%s", zValue);
|
||||
if ( zCopy==0 ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto set_directory8_done;
|
||||
}
|
||||
}
|
||||
sqlite3_free(*ppDirectory);
|
||||
*ppDirectory = zCopy;
|
||||
return SQLITE_OK;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
set_directory8_done:
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -48381,6 +48407,18 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** If sqlite3_temp_directory is not, take the mutex and return true.
|
||||
**
|
||||
** If sqlite3_temp_directory is NULL, omit the mutex and return false.
|
||||
*/
|
||||
static int winTempDirDefined(void){
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
if( sqlite3_temp_directory!=0 ) return 1;
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a temporary file name and store the resulting pointer into pzBuf.
|
||||
** The pointer returned in pzBuf must be freed via sqlite3_free().
|
||||
@ -48417,20 +48455,23 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
||||
*/
|
||||
nDir = nMax - (nPre + 15);
|
||||
assert( nDir>0 );
|
||||
if( sqlite3_temp_directory ){
|
||||
if( winTempDirDefined() ){
|
||||
int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
|
||||
if( nDirLen>0 ){
|
||||
if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
|
||||
nDirLen++;
|
||||
}
|
||||
if( nDirLen>nDir ){
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
sqlite3_free(zBuf);
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
|
||||
return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
|
||||
}
|
||||
sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
|
||||
}
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
}
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
else{
|
||||
static const char *azDirs[] = {
|
||||
@ -49219,7 +49260,7 @@ static BOOL winIsVerbatimPathname(
|
||||
** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
|
||||
** bytes in size.
|
||||
*/
|
||||
static int winFullPathname(
|
||||
static int winFullPathnameNoMutex(
|
||||
sqlite3_vfs *pVfs, /* Pointer to vfs object */
|
||||
const char *zRelative, /* Possibly relative input path */
|
||||
int nFull, /* Size of output buffer in bytes */
|
||||
@ -49398,6 +49439,19 @@ static int winFullPathname(
|
||||
}
|
||||
#endif
|
||||
}
|
||||
static int winFullPathname(
|
||||
sqlite3_vfs *pVfs, /* Pointer to vfs object */
|
||||
const char *zRelative, /* Possibly relative input path */
|
||||
int nFull, /* Size of output buffer in bytes */
|
||||
char *zFull /* Output buffer */
|
||||
){
|
||||
int rc;
|
||||
sqlite3_mutex *pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR);
|
||||
sqlite3_mutex_enter(pMutex);
|
||||
rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
|
||||
sqlite3_mutex_leave(pMutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
/*
|
||||
@ -51742,14 +51796,24 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
|
||||
*/
|
||||
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
|
||||
PCache *pCache = p->pCache;
|
||||
sqlite3_pcache_page *pOther;
|
||||
assert( p->nRef>0 );
|
||||
assert( newPgno>0 );
|
||||
assert( sqlite3PcachePageSanity(p) );
|
||||
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
|
||||
pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
|
||||
if( pOther ){
|
||||
PgHdr *pXPage = (PgHdr*)pOther->pExtra;
|
||||
assert( pXPage->nRef==0 );
|
||||
pXPage->nRef++;
|
||||
pCache->nRefSum++;
|
||||
sqlite3PcacheDrop(pXPage);
|
||||
}
|
||||
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
|
||||
p->pgno = newPgno;
|
||||
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
|
||||
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
|
||||
assert( sqlite3PcachePageSanity(p) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -53131,23 +53195,26 @@ static void pcache1Rekey(
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PgHdr1 *pPage = (PgHdr1 *)pPg;
|
||||
PgHdr1 **pp;
|
||||
unsigned int h;
|
||||
unsigned int hOld, hNew;
|
||||
assert( pPage->iKey==iOld );
|
||||
assert( pPage->pCache==pCache );
|
||||
assert( iOld!=iNew ); /* The page number really is changing */
|
||||
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
|
||||
h = iOld%pCache->nHash;
|
||||
pp = &pCache->apHash[h];
|
||||
assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */
|
||||
hOld = iOld%pCache->nHash;
|
||||
pp = &pCache->apHash[hOld];
|
||||
while( (*pp)!=pPage ){
|
||||
pp = &(*pp)->pNext;
|
||||
}
|
||||
*pp = pPage->pNext;
|
||||
|
||||
h = iNew%pCache->nHash;
|
||||
assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */
|
||||
hNew = iNew%pCache->nHash;
|
||||
pPage->iKey = iNew;
|
||||
pPage->pNext = pCache->apHash[h];
|
||||
pCache->apHash[h] = pPage;
|
||||
pPage->pNext = pCache->apHash[hNew];
|
||||
pCache->apHash[hNew] = pPage;
|
||||
if( iNew>pCache->iMaxKey ){
|
||||
pCache->iMaxKey = iNew;
|
||||
}
|
||||
@ -59905,6 +59972,7 @@ static int pager_open_journal(Pager *pPager){
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3BitvecDestroy(pPager->pInJournal);
|
||||
pPager->pInJournal = 0;
|
||||
pPager->journalOff = 0;
|
||||
}else{
|
||||
assert( pPager->eState==PAGER_WRITER_LOCKED );
|
||||
pPager->eState = PAGER_WRITER_CACHEMOD;
|
||||
@ -61503,7 +61571,7 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
|
||||
SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
|
||||
assert( assert_pager_state(pPager) );
|
||||
if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0;
|
||||
if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
|
||||
if( isOpen(pPager->jfd) && pPager->journalOff>0 ) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -68647,7 +68715,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
|
||||
sz += sz2;
|
||||
}else if( NEVER(iFree+sz>usableSize) ){
|
||||
}else if( iFree+sz>usableSize ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
|
||||
@ -75003,8 +75071,6 @@ static int balance_nonroot(
|
||||
Pgno pgno; /* Temp var to store a page number in */
|
||||
u8 abDone[NB+2]; /* True after i'th new page is populated */
|
||||
Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
|
||||
Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
|
||||
u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
|
||||
CellArray b; /* Parsed information on cells being balanced */
|
||||
|
||||
memset(abDone, 0, sizeof(abDone));
|
||||
@ -75428,42 +75494,39 @@ static int balance_nonroot(
|
||||
** of the table is closer to a linear scan through the file. That in turn
|
||||
** helps the operating system to deliver pages from the disk more rapidly.
|
||||
**
|
||||
** An O(n^2) insertion sort algorithm is used, but since n is never more
|
||||
** than (NB+2) (a small constant), that should not be a problem.
|
||||
** An O(N*N) sort algorithm is used, but since N is never more than NB+2
|
||||
** (5), that is not a performance concern.
|
||||
**
|
||||
** When NB==3, this one optimization makes the database about 25% faster
|
||||
** for large insertions and deletions.
|
||||
*/
|
||||
for(i=0; i<nNew; i++){
|
||||
aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
|
||||
aPgFlags[i] = apNew[i]->pDbPage->flags;
|
||||
for(j=0; j<i; j++){
|
||||
if( NEVER(aPgno[j]==aPgno[i]) ){
|
||||
/* This branch is taken if the set of sibling pages somehow contains
|
||||
** duplicate entries. This can happen if the database is corrupt.
|
||||
** It would be simpler to detect this as part of the loop below, but
|
||||
** we do the detection here in order to avoid populating the pager
|
||||
** cache with two separate objects associated with the same
|
||||
** page number. */
|
||||
assert( CORRUPT_DB );
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto balance_cleanup;
|
||||
}
|
||||
}
|
||||
aPgno[i] = apNew[i]->pgno;
|
||||
assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE );
|
||||
assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY );
|
||||
}
|
||||
for(i=0; i<nNew; i++){
|
||||
int iBest = 0; /* aPgno[] index of page number to use */
|
||||
for(j=1; j<nNew; j++){
|
||||
if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j;
|
||||
for(i=0; i<nNew-1; i++){
|
||||
int iB = i;
|
||||
for(j=i+1; j<nNew; j++){
|
||||
if( apNew[j]->pgno < apNew[iB]->pgno ) iB = j;
|
||||
}
|
||||
pgno = aPgOrder[iBest];
|
||||
aPgOrder[iBest] = 0xffffffff;
|
||||
if( iBest!=i ){
|
||||
if( iBest>i ){
|
||||
sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0);
|
||||
}
|
||||
sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]);
|
||||
apNew[i]->pgno = pgno;
|
||||
|
||||
/* If apNew[i] has a page number that is bigger than any of the
|
||||
** subsequence apNew[i] entries, then swap apNew[i] with the subsequent
|
||||
** entry that has the smallest page number (which we know to be
|
||||
** entry apNew[iB]).
|
||||
*/
|
||||
if( iB!=i ){
|
||||
Pgno pgnoA = apNew[i]->pgno;
|
||||
Pgno pgnoB = apNew[iB]->pgno;
|
||||
Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1;
|
||||
u16 fgA = apNew[i]->pDbPage->flags;
|
||||
u16 fgB = apNew[iB]->pDbPage->flags;
|
||||
sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB);
|
||||
sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA);
|
||||
sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB);
|
||||
apNew[i]->pgno = pgnoB;
|
||||
apNew[iB]->pgno = pgnoA;
|
||||
}
|
||||
}
|
||||
|
||||
@ -81395,6 +81458,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(
|
||||
addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
|
||||
p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
|
||||
sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
|
||||
sqlite3MayAbort(pParse);
|
||||
return addr;
|
||||
}
|
||||
|
||||
@ -81730,6 +81794,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
|| opcode==OP_VDestroy
|
||||
|| opcode==OP_VCreate
|
||||
|| opcode==OP_ParseSchema
|
||||
|| opcode==OP_Function || opcode==OP_PureFunc
|
||||
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
||||
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
|
||||
){
|
||||
@ -101783,7 +101848,7 @@ SQLITE_API void sqlite3pager_reset(Pager *pPager);
|
||||
#define CIPHER_STR(s) #s
|
||||
|
||||
#ifndef CIPHER_VERSION_NUMBER
|
||||
#define CIPHER_VERSION_NUMBER 4.5.2
|
||||
#define CIPHER_VERSION_NUMBER 4.5.3
|
||||
#endif
|
||||
|
||||
#ifndef CIPHER_VERSION_BUILD
|
||||
@ -138008,6 +138073,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
||||
**
|
||||
*/
|
||||
case PragTyp_TEMP_STORE_DIRECTORY: {
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
if( !zRight ){
|
||||
returnSingleText(v, sqlite3_temp_directory);
|
||||
}else{
|
||||
@ -138017,6 +138083,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
||||
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
|
||||
if( rc!=SQLITE_OK || res==0 ){
|
||||
sqlite3ErrorMsg(pParse, "not a writable directory");
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
goto pragma_out;
|
||||
}
|
||||
}
|
||||
@ -138034,6 +138101,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WSD */
|
||||
}
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -138052,6 +138120,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
||||
**
|
||||
*/
|
||||
case PragTyp_DATA_STORE_DIRECTORY: {
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
if( !zRight ){
|
||||
returnSingleText(v, sqlite3_data_directory);
|
||||
}else{
|
||||
@ -138061,6 +138130,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
||||
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
|
||||
if( rc!=SQLITE_OK || res==0 ){
|
||||
sqlite3ErrorMsg(pParse, "not a writable directory");
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
goto pragma_out;
|
||||
}
|
||||
}
|
||||
@ -138072,6 +138142,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WSD */
|
||||
}
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -142560,7 +142631,7 @@ static void generateSortTail(
|
||||
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
|
||||
VdbeCoverage(v);
|
||||
codeOffset(v, p->iOffset, addrContinue);
|
||||
assert( p->iLimit==0 && p->iOffset==0 );
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
|
||||
bSeq = 0;
|
||||
}else{
|
||||
@ -142568,6 +142639,9 @@ static void generateSortTail(
|
||||
codeOffset(v, p->iOffset, addrContinue);
|
||||
iSortTab = iTab;
|
||||
bSeq = 1;
|
||||
if( p->iOffset>0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
|
||||
}
|
||||
}
|
||||
for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){
|
||||
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
||||
@ -144560,10 +144634,11 @@ static int multiSelectOrderBy(
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, labelEnd);
|
||||
|
||||
/* Reassembly the compound query so that it will be freed correctly
|
||||
/* Reassemble the compound query so that it will be freed correctly
|
||||
** by the calling function */
|
||||
if( pSplit->pPrior ){
|
||||
sqlite3SelectDelete(db, pSplit->pPrior);
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
|
||||
}
|
||||
pSplit->pPrior = pPrior;
|
||||
pPrior->pNext = pSplit;
|
||||
@ -146082,6 +146157,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
||||
|| p->pSrc->nSrc!=1
|
||||
|| p->pSrc->a[0].pSelect
|
||||
|| pAggInfo->nFunc!=1
|
||||
|| p->pHaving
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
@ -149319,6 +149395,23 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
|
||||
Vdbe *v;
|
||||
char *z;
|
||||
|
||||
/* If this is a new CREATE TABLE statement, and if shadow tables
|
||||
** are read-only, and the trigger makes a change to a shadow table,
|
||||
** then raise an error - do not allow the trigger to be created. */
|
||||
if( sqlite3ReadOnlyShadowTables(db) ){
|
||||
TriggerStep *pStep;
|
||||
for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget!=0
|
||||
&& sqlite3ShadowTableName(db, pStep->zTarget)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"trigger \"%s\" may not write to shadow table \"%s\"",
|
||||
pTrig->zName, pStep->zTarget);
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make an entry in the sqlite_schema table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
@ -155143,7 +155236,8 @@ static int codeEqualityTerm(
|
||||
}
|
||||
sqlite3ExprDelete(db, pX);
|
||||
}else{
|
||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
||||
int n = sqlite3ExprVectorSize(pX->pLeft);
|
||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
|
||||
}
|
||||
pX = pExpr;
|
||||
@ -182345,7 +182439,7 @@ struct Fts3MultiSegReader {
|
||||
int nAdvance; /* How many seg-readers to advance */
|
||||
Fts3SegFilter *pFilter; /* Pointer to filter object */
|
||||
char *aBuffer; /* Buffer to merge doclists in */
|
||||
int nBuffer; /* Allocated size of aBuffer[] in bytes */
|
||||
i64 nBuffer; /* Allocated size of aBuffer[] in bytes */
|
||||
|
||||
int iColFilter; /* If >=0, filter for this column */
|
||||
int bRestart;
|
||||
@ -185041,7 +185135,7 @@ static int fts3TermSelectMerge(
|
||||
**
|
||||
** Similar padding is added in the fts3DoclistOrMerge() function.
|
||||
*/
|
||||
pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
|
||||
pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1);
|
||||
pTS->anOutput[0] = nDoclist;
|
||||
if( pTS->aaOutput[0] ){
|
||||
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
|
||||
@ -186529,7 +186623,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
||||
nDistance = iPrev - nMaxUndeferred;
|
||||
}
|
||||
|
||||
aOut = (char *)sqlite3_malloc(nPoslist+8);
|
||||
aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
|
||||
if( !aOut ){
|
||||
sqlite3_free(aPoslist);
|
||||
return SQLITE_NOMEM;
|
||||
@ -186898,7 +186992,7 @@ static int fts3EvalIncrPhraseNext(
|
||||
if( bEof==0 ){
|
||||
int nList = 0;
|
||||
int nByte = a[p->nToken-1].nList;
|
||||
char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
|
||||
char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING);
|
||||
if( !aDoclist ) return SQLITE_NOMEM;
|
||||
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
|
||||
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
|
||||
@ -191134,7 +191228,7 @@ static int porterNext(
|
||||
if( n>c->nAllocated ){
|
||||
char *pNew;
|
||||
c->nAllocated = n+20;
|
||||
pNew = sqlite3_realloc(c->zToken, c->nAllocated);
|
||||
pNew = sqlite3_realloc64(c->zToken, c->nAllocated);
|
||||
if( !pNew ) return SQLITE_NOMEM;
|
||||
c->zToken = pNew;
|
||||
}
|
||||
@ -191886,7 +191980,7 @@ static int simpleNext(
|
||||
if( n>c->nTokenAllocated ){
|
||||
char *pNew;
|
||||
c->nTokenAllocated = n+20;
|
||||
pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
|
||||
pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated);
|
||||
if( !pNew ) return SQLITE_NOMEM;
|
||||
c->pToken = pNew;
|
||||
}
|
||||
@ -193048,7 +193142,7 @@ static int fts3PendingListAppendVarint(
|
||||
|
||||
/* Allocate or grow the PendingList as required. */
|
||||
if( !p ){
|
||||
p = sqlite3_malloc(sizeof(*p) + 100);
|
||||
p = sqlite3_malloc64(sizeof(*p) + 100);
|
||||
if( !p ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -193057,14 +193151,14 @@ static int fts3PendingListAppendVarint(
|
||||
p->nData = 0;
|
||||
}
|
||||
else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){
|
||||
int nNew = p->nSpace * 2;
|
||||
p = sqlite3_realloc(p, sizeof(*p) + nNew);
|
||||
i64 nNew = p->nSpace * 2;
|
||||
p = sqlite3_realloc64(p, sizeof(*p) + nNew);
|
||||
if( !p ){
|
||||
sqlite3_free(*pp);
|
||||
*pp = 0;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
p->nSpace = nNew;
|
||||
p->nSpace = (int)nNew;
|
||||
p->aData = (char *)&p[1];
|
||||
}
|
||||
|
||||
@ -193621,7 +193715,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
|
||||
int nByte = sqlite3_blob_bytes(p->pSegments);
|
||||
*pnBlob = nByte;
|
||||
if( paBlob ){
|
||||
char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
|
||||
char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING);
|
||||
if( !aByte ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@ -193738,7 +193832,7 @@ static int fts3SegReaderNext(
|
||||
int nTerm = fts3HashKeysize(pElem);
|
||||
if( (nTerm+1)>pReader->nTermAlloc ){
|
||||
sqlite3_free(pReader->zTerm);
|
||||
pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2);
|
||||
pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2);
|
||||
if( !pReader->zTerm ) return SQLITE_NOMEM;
|
||||
pReader->nTermAlloc = (nTerm+1)*2;
|
||||
}
|
||||
@ -193746,7 +193840,7 @@ static int fts3SegReaderNext(
|
||||
pReader->zTerm[nTerm] = '\0';
|
||||
pReader->nTerm = nTerm;
|
||||
|
||||
aCopy = (char*)sqlite3_malloc(nCopy);
|
||||
aCopy = (char*)sqlite3_malloc64(nCopy);
|
||||
if( !aCopy ) return SQLITE_NOMEM;
|
||||
memcpy(aCopy, pList->aData, nCopy);
|
||||
pReader->nNode = pReader->nDoclist = nCopy;
|
||||
@ -194033,7 +194127,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
|
||||
nExtra = nRoot + FTS3_NODE_PADDING;
|
||||
}
|
||||
|
||||
pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
|
||||
pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra);
|
||||
if( !pReader ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -194125,7 +194219,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
|
||||
if( nElem==nAlloc ){
|
||||
Fts3HashElem **aElem2;
|
||||
nAlloc += 16;
|
||||
aElem2 = (Fts3HashElem **)sqlite3_realloc(
|
||||
aElem2 = (Fts3HashElem **)sqlite3_realloc64(
|
||||
aElem, nAlloc*sizeof(Fts3HashElem *)
|
||||
);
|
||||
if( !aElem2 ){
|
||||
@ -194459,7 +194553,7 @@ static int fts3NodeAddTerm(
|
||||
** this is not expected to be a serious problem.
|
||||
*/
|
||||
assert( pTree->aData==(char *)&pTree[1] );
|
||||
pTree->aData = (char *)sqlite3_malloc(nReq);
|
||||
pTree->aData = (char *)sqlite3_malloc64(nReq);
|
||||
if( !pTree->aData ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -194477,7 +194571,7 @@ static int fts3NodeAddTerm(
|
||||
|
||||
if( isCopyTerm ){
|
||||
if( pTree->nMalloc<nTerm ){
|
||||
char *zNew = sqlite3_realloc(pTree->zMalloc, nTerm*2);
|
||||
char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -194503,7 +194597,7 @@ static int fts3NodeAddTerm(
|
||||
** now. Instead, the term is inserted into the parent of pTree. If pTree
|
||||
** has no parent, one is created here.
|
||||
*/
|
||||
pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize);
|
||||
pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize);
|
||||
if( !pNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -194641,7 +194735,7 @@ static int fts3SegWriterAdd(
|
||||
){
|
||||
int nPrefix; /* Size of term prefix in bytes */
|
||||
int nSuffix; /* Size of term suffix in bytes */
|
||||
int nReq; /* Number of bytes required on leaf page */
|
||||
i64 nReq; /* Number of bytes required on leaf page */
|
||||
int nData;
|
||||
SegmentWriter *pWriter = *ppWriter;
|
||||
|
||||
@ -194650,13 +194744,13 @@ static int fts3SegWriterAdd(
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
/* Allocate the SegmentWriter structure */
|
||||
pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter));
|
||||
pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter));
|
||||
if( !pWriter ) return SQLITE_NOMEM;
|
||||
memset(pWriter, 0, sizeof(SegmentWriter));
|
||||
*ppWriter = pWriter;
|
||||
|
||||
/* Allocate a buffer in which to accumulate data */
|
||||
pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize);
|
||||
pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize);
|
||||
if( !pWriter->aData ) return SQLITE_NOMEM;
|
||||
pWriter->nSize = p->nNodeSize;
|
||||
|
||||
@ -194731,7 +194825,7 @@ static int fts3SegWriterAdd(
|
||||
** the buffer to make it large enough.
|
||||
*/
|
||||
if( nReq>pWriter->nSize ){
|
||||
char *aNew = sqlite3_realloc(pWriter->aData, nReq);
|
||||
char *aNew = sqlite3_realloc64(pWriter->aData, nReq);
|
||||
if( !aNew ) return SQLITE_NOMEM;
|
||||
pWriter->aData = aNew;
|
||||
pWriter->nSize = nReq;
|
||||
@ -194756,7 +194850,7 @@ static int fts3SegWriterAdd(
|
||||
*/
|
||||
if( isCopyTerm ){
|
||||
if( nTerm>pWriter->nMalloc ){
|
||||
char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2);
|
||||
char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -195064,12 +195158,12 @@ static void fts3ColumnFilter(
|
||||
static int fts3MsrBufferData(
|
||||
Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */
|
||||
char *pList,
|
||||
int nList
|
||||
i64 nList
|
||||
){
|
||||
if( nList>pMsr->nBuffer ){
|
||||
char *pNew;
|
||||
pMsr->nBuffer = nList*2;
|
||||
pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer);
|
||||
pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
|
||||
if( !pNew ) return SQLITE_NOMEM;
|
||||
pMsr->aBuffer = pNew;
|
||||
}
|
||||
@ -195125,7 +195219,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
|
||||
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
|
||||
|
||||
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
|
||||
rc = fts3MsrBufferData(pMsr, pList, nList+1);
|
||||
rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
|
||||
pList = pMsr->aBuffer;
|
||||
@ -195262,11 +195356,11 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
|
||||
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){
|
||||
if( nReq>pCsr->nBuffer ){
|
||||
char *aNew;
|
||||
pCsr->nBuffer = nReq*2;
|
||||
aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
|
||||
aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer);
|
||||
if( !aNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -195357,7 +195451,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
||||
){
|
||||
pCsr->nDoclist = apSegment[0]->nDoclist;
|
||||
if( fts3SegReaderIsPending(apSegment[0]) ){
|
||||
rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
|
||||
rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist,
|
||||
(i64)pCsr->nDoclist);
|
||||
pCsr->aDoclist = pCsr->aBuffer;
|
||||
}else{
|
||||
pCsr->aDoclist = apSegment[0]->aDoclist;
|
||||
@ -195410,7 +195505,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
||||
|
||||
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
|
||||
|
||||
rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING);
|
||||
rc = fts3GrowSegReaderBuffer(pCsr,
|
||||
(i64)nByte+nDoclist+FTS3_NODE_PADDING);
|
||||
if( rc ) return rc;
|
||||
|
||||
if( isFirst ){
|
||||
@ -195436,7 +195532,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
||||
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
|
||||
}
|
||||
if( nDoclist>0 ){
|
||||
rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
|
||||
rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING);
|
||||
if( rc ) return rc;
|
||||
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
|
||||
pCsr->aDoclist = pCsr->aBuffer;
|
||||
@ -196149,7 +196245,7 @@ struct NodeReader {
|
||||
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
|
||||
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
|
||||
int nAlloc = nMin;
|
||||
char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc);
|
||||
char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc);
|
||||
if( a ){
|
||||
pBlob->nAlloc = nAlloc;
|
||||
pBlob->a = a;
|
||||
@ -196946,7 +197042,7 @@ static int fts3RepackSegdirLevel(
|
||||
if( nIdx>=nAlloc ){
|
||||
int *aNew;
|
||||
nAlloc += 16;
|
||||
aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int));
|
||||
aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int));
|
||||
if( !aNew ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
@ -197320,7 +197416,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
|
||||
/* Allocate space for the cursor, filter and writer objects */
|
||||
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
|
||||
pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
|
||||
pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc);
|
||||
if( !pWriter ) return SQLITE_NOMEM;
|
||||
pFilter = (Fts3SegFilter *)&pWriter[1];
|
||||
pCsr = (Fts3MultiSegReader *)&pFilter[1];
|
||||
@ -197956,7 +198052,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
pRet = (char *)sqlite3_malloc(p->pList->nData);
|
||||
pRet = (char *)sqlite3_malloc64(p->pList->nData);
|
||||
if( !pRet ) return SQLITE_NOMEM;
|
||||
|
||||
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
|
||||
@ -197976,7 +198072,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
|
||||
int iCol /* Column that token must appear in (or -1) */
|
||||
){
|
||||
Fts3DeferredToken *pDeferred;
|
||||
pDeferred = sqlite3_malloc(sizeof(*pDeferred));
|
||||
pDeferred = sqlite3_malloc64(sizeof(*pDeferred));
|
||||
if( !pDeferred ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -209555,7 +209651,7 @@ static int geopolyUpdate(
|
||||
sqlite3_free(p);
|
||||
nChange = 1;
|
||||
}
|
||||
for(jj=1; jj<pRtree->nAux; jj++){
|
||||
for(jj=1; jj<nData-2; jj++){
|
||||
nChange++;
|
||||
sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
|
||||
}
|
||||
@ -210158,8 +210254,9 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
||||
|
||||
if( U_SUCCESS(status) ){
|
||||
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
|
||||
}else{
|
||||
assert(!pExpr);
|
||||
pExpr = sqlite3_get_auxdata(p, 0);
|
||||
}
|
||||
if( !pExpr ){
|
||||
icuFunctionError(p, "uregex_open", status);
|
||||
return;
|
||||
}
|
||||
@ -242045,7 +242142,7 @@ static void fts5SourceIdFunc(
|
||||
){
|
||||
assert( nArg==0 );
|
||||
UNUSED_PARAM2(nArg, apUnused);
|
||||
sqlite3_result_text(pCtx, "fts5: 2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603", -1, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(pCtx, "fts5: 2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26b309", -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
6
libsqlite3-sys/sqlcipher/sqlite3.h
vendored
6
libsqlite3-sys/sqlcipher/sqlite3.h
vendored
@ -146,9 +146,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.39.2"
|
||||
#define SQLITE_VERSION_NUMBER 3039002
|
||||
#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668ealt1"
|
||||
#define SQLITE_VERSION "3.39.4"
|
||||
#define SQLITE_VERSION_NUMBER 3039004
|
||||
#define SQLITE_SOURCE_ID "2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26alt1"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
|
@ -1,9 +1,33 @@
|
||||
/* automatically generated by rust-bindgen 0.62.0 */
|
||||
/* automatically generated by rust-bindgen 0.64.0 */
|
||||
|
||||
pub const SQLITE_VERSION: &[u8; 7usize] = b"3.40.0\0";
|
||||
pub const SQLITE_VERSION_NUMBER: i32 = 3040000;
|
||||
extern "C" {
|
||||
pub fn sqlite3_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::std::os::raw::c_int,
|
||||
>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn sqlite3_cancel_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
db: *mut sqlite3,
|
||||
pzErrMsg: *mut *const ::std::os::raw::c_char,
|
||||
pThunk: *const sqlite3_api_routines,
|
||||
) -> ::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_NUMBER: i32 = 3041002;
|
||||
pub const SQLITE_SOURCE_ID: &[u8; 85usize] =
|
||||
b"2022-11-16 12:10:08 89c459e766ea7e9165d0beeb124708b955a4950d0f4792f457465d71b158d318\0";
|
||||
b"2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da\0";
|
||||
pub const SQLITE_OK: i32 = 0;
|
||||
pub const SQLITE_ERROR: i32 = 1;
|
||||
pub const SQLITE_INTERNAL: i32 = 2;
|
||||
@ -106,6 +130,7 @@ pub const SQLITE_CONSTRAINT_PINNED: i32 = 2835;
|
||||
pub const SQLITE_CONSTRAINT_DATATYPE: i32 = 3091;
|
||||
pub const SQLITE_NOTICE_RECOVER_WAL: i32 = 283;
|
||||
pub const SQLITE_NOTICE_RECOVER_ROLLBACK: i32 = 539;
|
||||
pub const SQLITE_NOTICE_RBU: i32 = 795;
|
||||
pub const SQLITE_WARNING_AUTOINDEX: i32 = 284;
|
||||
pub const SQLITE_AUTH_USER: i32 = 279;
|
||||
pub const SQLITE_OK_LOAD_PERMANENTLY: i32 = 256;
|
||||
@ -196,6 +221,7 @@ 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;
|
||||
@ -447,6 +473,9 @@ 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;
|
||||
@ -854,6 +883,9 @@ extern "C" {
|
||||
extern "C" {
|
||||
pub fn sqlite3_interrupt(arg1: *mut sqlite3);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_is_interrupted(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_complete(sql: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
|
||||
}
|
||||
@ -2001,16 +2033,6 @@ extern "C" {
|
||||
onoff: ::std::os::raw::c_int,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<unsafe extern "C" fn()>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_cancel_auto_extension(
|
||||
xEntryPoint: ::std::option::Option<unsafe extern "C" fn()>,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_reset_auto_extension();
|
||||
}
|
||||
@ -2154,10 +2176,10 @@ pub struct sqlite3_module {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info {
|
||||
pub nConstraint: ::std::os::raw::c_int,
|
||||
pub aConstraint: *mut sqlite3_index_info_sqlite3_index_constraint,
|
||||
pub aConstraint: *mut sqlite3_index_constraint,
|
||||
pub nOrderBy: ::std::os::raw::c_int,
|
||||
pub aOrderBy: *mut sqlite3_index_info_sqlite3_index_orderby,
|
||||
pub aConstraintUsage: *mut sqlite3_index_info_sqlite3_index_constraint_usage,
|
||||
pub aOrderBy: *mut sqlite3_index_orderby,
|
||||
pub aConstraintUsage: *mut sqlite3_index_constraint_usage,
|
||||
pub idxNum: ::std::os::raw::c_int,
|
||||
pub idxStr: *mut ::std::os::raw::c_char,
|
||||
pub needToFreeIdxStr: ::std::os::raw::c_int,
|
||||
@ -2169,7 +2191,7 @@ pub struct sqlite3_index_info {
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_constraint {
|
||||
pub struct sqlite3_index_constraint {
|
||||
pub iColumn: ::std::os::raw::c_int,
|
||||
pub op: ::std::os::raw::c_uchar,
|
||||
pub usable: ::std::os::raw::c_uchar,
|
||||
@ -2177,13 +2199,13 @@ pub struct sqlite3_index_info_sqlite3_index_constraint {
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_orderby {
|
||||
pub struct sqlite3_index_orderby {
|
||||
pub iColumn: ::std::os::raw::c_int,
|
||||
pub desc: ::std::os::raw::c_uchar,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct sqlite3_index_info_sqlite3_index_constraint_usage {
|
||||
pub struct sqlite3_index_constraint_usage {
|
||||
pub argvIndex: ::std::os::raw::c_int,
|
||||
pub omit: ::std::os::raw::c_uchar,
|
||||
}
|
||||
@ -2710,6 +2732,15 @@ extern "C" {
|
||||
pOut: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_stmt_scanstatus_v2(
|
||||
pStmt: *mut sqlite3_stmt,
|
||||
idx: ::std::os::raw::c_int,
|
||||
iScanStatusOp: ::std::os::raw::c_int,
|
||||
flags: ::std::os::raw::c_int,
|
||||
pOut: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sqlite3_stmt_scanstatus_reset(arg1: *mut sqlite3_stmt);
|
||||
}
|
||||
|
4448
libsqlite3-sys/sqlite3/sqlite3.c
vendored
4448
libsqlite3-sys/sqlite3/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
237
libsqlite3-sys/sqlite3/sqlite3.h
vendored
237
libsqlite3-sys/sqlite3/sqlite3.h
vendored
@ -146,9 +146,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.40.0"
|
||||
#define SQLITE_VERSION_NUMBER 3040000
|
||||
#define SQLITE_SOURCE_ID "2022-11-16 12:10:08 89c459e766ea7e9165d0beeb124708b955a4950d0f4792f457465d71b158d318"
|
||||
#define SQLITE_VERSION "3.41.2"
|
||||
#define SQLITE_VERSION_NUMBER 3041002
|
||||
#define SQLITE_SOURCE_ID "2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@ -563,6 +563,7 @@ SQLITE_API int sqlite3_exec(
|
||||
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
|
||||
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
||||
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
||||
#define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8))
|
||||
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
|
||||
@ -1175,7 +1176,6 @@ struct sqlite3_io_methods {
|
||||
** in wal mode after the client has finished copying pages from the wal
|
||||
** file to the database file, but before the *-shm file is updated to
|
||||
** record the fact that the pages have been checkpointed.
|
||||
** </ul>
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
|
||||
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
|
||||
@ -1188,10 +1188,16 @@ struct sqlite3_io_methods {
|
||||
** the database is not a wal-mode db, or if there is no such connection in any
|
||||
** other process. This opcode cannot be used to detect transactions opened
|
||||
** by clients within the current process, only within other processes.
|
||||
** </ul>
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
|
||||
** Used by the cksmvfs VFS module only.
|
||||
** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
|
||||
** [checksum VFS shim] only.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_RESET_CACHE]]
|
||||
** If there is currently no transaction open on the database, and the
|
||||
** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
|
||||
** purges the contents of the in-memory page cache. If there is an open
|
||||
** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
@ -1234,6 +1240,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_CKPT_START 39
|
||||
#define SQLITE_FCNTL_EXTERNAL_READER 40
|
||||
#define SQLITE_FCNTL_CKSM_FILE 41
|
||||
#define SQLITE_FCNTL_RESET_CACHE 42
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@ -2177,7 +2184,7 @@ struct sqlite3_mem_methods {
|
||||
** configuration for a database connection can only be changed when that
|
||||
** connection is not currently using lookaside memory, or in other words
|
||||
** when the "current value" returned by
|
||||
** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
|
||||
** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
|
||||
** Any attempt to change the lookaside memory configuration when lookaside
|
||||
** memory is in use leaves the configuration unchanged and returns
|
||||
** [SQLITE_BUSY].)^</dd>
|
||||
@ -2327,8 +2334,12 @@ struct sqlite3_mem_methods {
|
||||
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
|
||||
** </ol>
|
||||
** Because resetting a database is destructive and irreversible, the
|
||||
** process requires the use of this obscure API and multiple steps to help
|
||||
** ensure that it does not happen by accident.
|
||||
** process requires the use of this obscure API and multiple steps to
|
||||
** help ensure that it does not happen by accident. Because this
|
||||
** feature must be capable of resetting corrupt databases, and
|
||||
** shutting down virtual tables may require access to that corrupt
|
||||
** storage, the library must abandon any installed virtual tables
|
||||
** without calling their xDestroy() methods.
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
|
||||
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
|
||||
@ -2667,8 +2678,12 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
|
||||
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
|
||||
** SQL statements is a no-op and has no effect on SQL statements
|
||||
** that are started after the sqlite3_interrupt() call returns.
|
||||
**
|
||||
** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
|
||||
** or not an interrupt is currently in effect for [database connection] D.
|
||||
*/
|
||||
SQLITE_API void sqlite3_interrupt(sqlite3*);
|
||||
SQLITE_API int sqlite3_is_interrupted(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If An SQL Statement Is Complete
|
||||
@ -3286,8 +3301,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
|
||||
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
|
||||
** information as is provided by the [sqlite3_profile()] callback.
|
||||
** ^The P argument is a pointer to the [prepared statement] and the
|
||||
** X argument points to a 64-bit integer which is the estimated of
|
||||
** the number of nanosecond that the prepared statement took to run.
|
||||
** X argument points to a 64-bit integer which is approximately
|
||||
** the number of nanoseconds that the prepared statement took to run.
|
||||
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
|
||||
**
|
||||
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
|
||||
@ -3350,7 +3365,7 @@ SQLITE_API int sqlite3_trace_v2(
|
||||
**
|
||||
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
|
||||
** function X to be invoked periodically during long running calls to
|
||||
** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
|
||||
** [sqlite3_step()] and [sqlite3_prepare()] and similar for
|
||||
** database connection D. An example use for this
|
||||
** interface is to keep a GUI updated during a large query.
|
||||
**
|
||||
@ -3375,6 +3390,13 @@ SQLITE_API int sqlite3_trace_v2(
|
||||
** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
|
||||
** database connections for the meaning of "modify" in this paragraph.
|
||||
**
|
||||
** The progress handler callback would originally only be invoked from the
|
||||
** bytecode engine. It still might be invoked during [sqlite3_prepare()]
|
||||
** and similar because those routines might force a reparse of the schema
|
||||
** which involves running the bytecode engine. However, beginning with
|
||||
** SQLite version 3.41.0, the progress handler callback might also be
|
||||
** invoked directly from [sqlite3_prepare()] while analyzing and generating
|
||||
** code for complex queries.
|
||||
*/
|
||||
SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
|
||||
@ -3411,13 +3433,18 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
**
|
||||
** <dl>
|
||||
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
|
||||
** <dd>The database is opened in read-only mode. If the database does not
|
||||
** already exist, an error is returned.</dd>)^
|
||||
** <dd>The database is opened in read-only mode. If the database does
|
||||
** not already exist, an error is returned.</dd>)^
|
||||
**
|
||||
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
|
||||
** <dd>The database is opened for reading and writing if possible, or reading
|
||||
** only if the file is write protected by the operating system. In either
|
||||
** case the database must already exist, otherwise an error is returned.</dd>)^
|
||||
** <dd>The database is opened for reading and writing if possible, or
|
||||
** reading only if the file is write protected by the operating
|
||||
** system. In either case the database must already exist, otherwise
|
||||
** an error is returned. For historical reasons, if opening in
|
||||
** read-write mode fails due to OS-level permissions, an attempt is
|
||||
** made to open it in read-only mode. [sqlite3_db_readonly()] can be
|
||||
** used to determine whether the database is actually
|
||||
** read-write.</dd>)^
|
||||
**
|
||||
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
|
||||
** <dd>The database is opened for reading and writing, and is created if
|
||||
@ -5398,10 +5425,21 @@ SQLITE_API int sqlite3_create_window_function(
|
||||
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
|
||||
** schema structures such as [CHECK constraints], [DEFAULT clauses],
|
||||
** [expression indexes], [partial indexes], or [generated columns].
|
||||
** The SQLITE_DIRECTONLY flags is a security feature which is recommended
|
||||
** for all [application-defined SQL functions], and especially for functions
|
||||
** that have side-effects or that could potentially leak sensitive
|
||||
** information.
|
||||
** <p>
|
||||
** The SQLITE_DIRECTONLY flag is recommended for any
|
||||
** [application-defined SQL function]
|
||||
** that has side-effects or that could potentially leak sensitive information.
|
||||
** This will prevent attacks in which an application is tricked
|
||||
** into using a database file that has had its schema surreptiously
|
||||
** modified to invoke the application-defined function in ways that are
|
||||
** harmful.
|
||||
** <p>
|
||||
** Some people say it is good practice to set SQLITE_DIRECTONLY on all
|
||||
** [application-defined SQL functions], regardless of whether or not they
|
||||
** are security sensitive, as doing so prevents those functions from being used
|
||||
** inside of the database schema, and thus ensures that the database
|
||||
** can be inspected and modified using generic tools (such as the [CLI])
|
||||
** that do not have access to the application-defined functions.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
|
||||
@ -5542,16 +5580,6 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
|
||||
** then the conversion is performed. Otherwise no conversion occurs.
|
||||
** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
|
||||
**
|
||||
** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
|
||||
** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current encoding
|
||||
** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
|
||||
** returns something other than SQLITE_TEXT, then the return value from
|
||||
** sqlite3_value_encoding(X) is meaningless. ^Calls to
|
||||
** sqlite3_value_text(X), sqlite3_value_text16(X), sqlite3_value_text16be(X),
|
||||
** sqlite3_value_text16le(X), sqlite3_value_bytes(X), or
|
||||
** sqlite3_value_bytes16(X) might change the encoding of the value X and
|
||||
** thus change the return from subsequent calls to sqlite3_value_encoding(X).
|
||||
**
|
||||
** ^Within the [xUpdate] method of a [virtual table], the
|
||||
** sqlite3_value_nochange(X) interface returns true if and only if
|
||||
** the column corresponding to X is unchanged by the UPDATE operation
|
||||
@ -5616,6 +5644,27 @@ SQLITE_API int sqlite3_value_type(sqlite3_value*);
|
||||
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
|
||||
SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
|
||||
SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Report the internal text encoding state of an sqlite3_value object
|
||||
** METHOD: sqlite3_value
|
||||
**
|
||||
** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
|
||||
** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding
|
||||
** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
|
||||
** returns something other than SQLITE_TEXT, then the return value from
|
||||
** sqlite3_value_encoding(X) is meaningless. ^Calls to
|
||||
** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)],
|
||||
** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or
|
||||
** [sqlite3_value_bytes16(X)] might change the encoding of the value X and
|
||||
** thus change the return from subsequent calls to sqlite3_value_encoding(X).
|
||||
**
|
||||
** This routine is intended for used by applications that test and validate
|
||||
** the SQLite implementation. This routine is inquiring about the opaque
|
||||
** internal state of an [sqlite3_value] object. Ordinary applications should
|
||||
** not need to know what the internal state of an sqlite3_value object is and
|
||||
** hence should not need to use this interface.
|
||||
*/
|
||||
SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
|
||||
|
||||
/*
|
||||
@ -6996,15 +7045,6 @@ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
|
||||
*/
|
||||
SQLITE_API void sqlite3_reset_auto_extension(void);
|
||||
|
||||
/*
|
||||
** The interface to the virtual-table mechanism is currently considered
|
||||
** to be experimental. The interface might change in incompatible ways.
|
||||
** If this is a problem for you, do not use the interface at this time.
|
||||
**
|
||||
** When the virtual-table mechanism stabilizes, we will declare the
|
||||
** interface fixed, support it indefinitely, and remove this comment.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Structures used by the virtual table interface
|
||||
*/
|
||||
@ -7123,10 +7163,10 @@ struct sqlite3_module {
|
||||
** when the omit flag is true there is no guarantee that the constraint will
|
||||
** not be checked again using byte code.)^
|
||||
**
|
||||
** ^The idxNum and idxPtr values are recorded and passed into the
|
||||
** ^The idxNum and idxStr values are recorded and passed into the
|
||||
** [xFilter] method.
|
||||
** ^[sqlite3_free()] is used to free idxPtr if and only if
|
||||
** needToFreeIdxPtr is true.
|
||||
** ^[sqlite3_free()] is used to free idxStr if and only if
|
||||
** needToFreeIdxStr is true.
|
||||
**
|
||||
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
|
||||
** the correct order to satisfy the ORDER BY clause so that no separate
|
||||
@ -7246,7 +7286,7 @@ struct sqlite3_index_info {
|
||||
** the [sqlite3_vtab_collation()] interface. For most real-world virtual
|
||||
** tables, the collating sequence of constraints does not matter (for example
|
||||
** because the constraints are numeric) and so the sqlite3_vtab_collation()
|
||||
** interface is no commonly needed.
|
||||
** interface is not commonly needed.
|
||||
*/
|
||||
#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
||||
#define SQLITE_INDEX_CONSTRAINT_GT 4
|
||||
@ -7405,16 +7445,6 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
||||
*/
|
||||
SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
|
||||
|
||||
/*
|
||||
** The interface to the virtual-table mechanism defined above (back up
|
||||
** to a comment remarkably similar to this one) is currently considered
|
||||
** to be experimental. The interface might change in incompatible ways.
|
||||
** If this is a problem for you, do not use the interface at this time.
|
||||
**
|
||||
** When the virtual-table mechanism stabilizes, we will declare the
|
||||
** interface fixed, support it indefinitely, and remove this comment.
|
||||
*/
|
||||
|
||||
/*
|
||||
** CAPI3REF: A Handle To An Open BLOB
|
||||
** KEYWORDS: {BLOB handle} {BLOB handles}
|
||||
@ -9618,7 +9648,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
|
||||
** <li><p> Otherwise, "BINARY" is returned.
|
||||
** </ol>
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine if a virtual table query is DISTINCT
|
||||
@ -9775,21 +9805,20 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
|
||||
** is undefined and probably harmful.
|
||||
**
|
||||
** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
|
||||
** sqlite3_vtab_in_next(X,P) must be one of the parameters to the
|
||||
** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
|
||||
** xFilter method which invokes these routines, and specifically
|
||||
** a parameter that was previously selected for all-at-once IN constraint
|
||||
** processing use the [sqlite3_vtab_in()] interface in the
|
||||
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
||||
** an xFilter argument that was selected for all-at-once IN constraint
|
||||
** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
|
||||
** exhibit some other undefined or harmful behavior.
|
||||
** processing, then these routines return [SQLITE_ERROR].)^
|
||||
**
|
||||
** ^(Use these routines to access all values on the right-hand side
|
||||
** of the IN constraint using code like the following:
|
||||
**
|
||||
** <blockquote><pre>
|
||||
** for(rc=sqlite3_vtab_in_first(pList, &pVal);
|
||||
** rc==SQLITE_OK && pVal
|
||||
** rc==SQLITE_OK && pVal;
|
||||
** rc=sqlite3_vtab_in_next(pList, &pVal)
|
||||
** ){
|
||||
** // do something with pVal
|
||||
@ -9887,6 +9916,10 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
|
||||
** managed by the prepared statement S and will be automatically freed when
|
||||
** S is finalized.
|
||||
**
|
||||
** Not all values are available for all query elements. When a value is
|
||||
** not available, the output variable is set to -1 if the value is numeric,
|
||||
** or to NULL if it is a string (SQLITE_SCANSTAT_NAME).
|
||||
**
|
||||
** <dl>
|
||||
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
|
||||
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
|
||||
@ -9914,12 +9947,24 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
|
||||
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
|
||||
** description for the X-th loop.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
|
||||
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
|
||||
** <dd>^The "int" variable pointed to by the V parameter will be set to the
|
||||
** "select-id" for the X-th loop. The select-id identifies which query or
|
||||
** subquery the loop is part of. The main query has a select-id of zero.
|
||||
** The select-id is the same value as is output in the first column
|
||||
** of an [EXPLAIN QUERY PLAN] query.
|
||||
** id for the X-th query plan element. The id value is unique within the
|
||||
** statement. The select-id is the same value as is output in the first
|
||||
** column of an [EXPLAIN QUERY PLAN] query.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
|
||||
** <dd>The "int" variable pointed to by the V parameter will be set to the
|
||||
** the id of the parent of the current query element, if applicable, or
|
||||
** to zero if the query element has no parent. This is the same value as
|
||||
** returned in the second column of an [EXPLAIN QUERY PLAN] query.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
|
||||
** <dd>The sqlite3_int64 output value is set to the number of cycles,
|
||||
** according to the processor time-stamp counter, that elapsed while the
|
||||
** query element was being processed. This value is not available for
|
||||
** all query elements - if it is unavailable the output variable is
|
||||
** set to -1.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_SCANSTAT_NLOOP 0
|
||||
@ -9928,12 +9973,14 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
|
||||
#define SQLITE_SCANSTAT_NAME 3
|
||||
#define SQLITE_SCANSTAT_EXPLAIN 4
|
||||
#define SQLITE_SCANSTAT_SELECTID 5
|
||||
#define SQLITE_SCANSTAT_PARENTID 6
|
||||
#define SQLITE_SCANSTAT_NCYCLE 7
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Scan Status
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** This interface returns information about the predicted and measured
|
||||
** These interfaces return information about the predicted and measured
|
||||
** performance for pStmt. Advanced applications can use this
|
||||
** interface to compare the predicted and the measured performance and
|
||||
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
|
||||
@ -9944,19 +9991,25 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
|
||||
**
|
||||
** The "iScanStatusOp" parameter determines which status information to return.
|
||||
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
|
||||
** of this interface is undefined.
|
||||
** ^The requested measurement is written into a variable pointed to by
|
||||
** the "pOut" parameter.
|
||||
** Parameter "idx" identifies the specific loop to retrieve statistics for.
|
||||
** Loops are numbered starting from zero. ^If idx is out of range - less than
|
||||
** zero or greater than or equal to the total number of loops used to implement
|
||||
** the statement - a non-zero value is returned and the variable that pOut
|
||||
** points to is unchanged.
|
||||
** of this interface is undefined. ^The requested measurement is written into
|
||||
** a variable pointed to by the "pOut" parameter.
|
||||
**
|
||||
** ^Statistics might not be available for all loops in all statements. ^In cases
|
||||
** where there exist loops with no available statistics, this function behaves
|
||||
** as if the loop did not exist - it returns non-zero and leave the variable
|
||||
** that pOut points to unchanged.
|
||||
** The "flags" parameter must be passed a mask of flags. At present only
|
||||
** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
|
||||
** is specified, then status information is available for all elements
|
||||
** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
|
||||
** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
|
||||
** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
|
||||
** the EXPLAIN QUERY PLAN output) are available. Invoking API
|
||||
** sqlite3_stmt_scanstatus() is equivalent to calling
|
||||
** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
|
||||
**
|
||||
** Parameter "idx" identifies the specific query element to retrieve statistics
|
||||
** for. Query elements are numbered starting from zero. A value of -1 may be
|
||||
** to query for statistics regarding the entire query. ^If idx is out of range
|
||||
** - less than -1 or greater than or equal to the total number of query
|
||||
** elements used to implement the statement - a non-zero value is returned and
|
||||
** the variable that pOut points to is unchanged.
|
||||
**
|
||||
** See also: [sqlite3_stmt_scanstatus_reset()]
|
||||
*/
|
||||
@ -9966,6 +10019,19 @@ SQLITE_API int sqlite3_stmt_scanstatus(
|
||||
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
|
||||
void *pOut /* Result written here */
|
||||
);
|
||||
SQLITE_API int sqlite3_stmt_scanstatus_v2(
|
||||
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
|
||||
int idx, /* Index of loop to report on */
|
||||
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
|
||||
int flags, /* Mask of flags defined below */
|
||||
void *pOut /* Result written here */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Scan Status
|
||||
** KEYWORDS: {scan status flags}
|
||||
*/
|
||||
#define SQLITE_SCANSTAT_COMPLEX 0x0001
|
||||
|
||||
/*
|
||||
** CAPI3REF: Zero Scan-Status Counters
|
||||
@ -10056,6 +10122,10 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
||||
** function is not defined for operations on WITHOUT ROWID tables, or for
|
||||
** DELETE operations on rowid tables.
|
||||
**
|
||||
** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from
|
||||
** the previous call on the same [database connection] D, or NULL for
|
||||
** the first call on D.
|
||||
**
|
||||
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
|
||||
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
|
||||
** provide additional information about a preupdate event. These routines
|
||||
@ -10461,6 +10531,19 @@ SQLITE_API int sqlite3_deserialize(
|
||||
# undef double
|
||||
#endif
|
||||
|
||||
#if defined(__wasi__)
|
||||
# undef SQLITE_WASI
|
||||
# define SQLITE_WASI 1
|
||||
# undef SQLITE_OMIT_WAL
|
||||
# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
|
||||
# ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
# define SQLITE_OMIT_LOAD_EXTENSION
|
||||
# endif
|
||||
# ifndef SQLITE_THREADSAFE
|
||||
# define SQLITE_THREADSAFE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
|
4
libsqlite3-sys/sqlite3/sqlite3ext.h
vendored
4
libsqlite3-sys/sqlite3/sqlite3ext.h
vendored
@ -359,6 +359,8 @@ struct sqlite3_api_routines {
|
||||
const char *(*db_name)(sqlite3*,int);
|
||||
/* Version 3.40.0 and later */
|
||||
int (*value_encoding)(sqlite3_value*);
|
||||
/* Version 3.41.0 and later */
|
||||
int (*is_interrupted)(sqlite3*);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -685,6 +687,8 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_db_name sqlite3_api->db_name
|
||||
/* Version 3.40.0 and later */
|
||||
#define sqlite3_value_encoding sqlite3_api->value_encoding
|
||||
/* Version 3.41.0 and later */
|
||||
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
@ -31,9 +31,6 @@ mod bindings {
|
||||
}
|
||||
pub use bindings::*;
|
||||
|
||||
pub type sqlite3_index_constraint = sqlite3_index_info_sqlite3_index_constraint;
|
||||
pub type sqlite3_index_constraint_usage = sqlite3_index_info_sqlite3_index_constraint_usage;
|
||||
|
||||
impl Default for sqlite3_vtab {
|
||||
fn default() -> Self {
|
||||
unsafe { mem::zeroed() }
|
||||
|
@ -9,8 +9,8 @@ export SQLITE3_LIB_DIR="$SCRIPT_DIR/sqlite3"
|
||||
export SQLITE3_INCLUDE_DIR="$SQLITE3_LIB_DIR"
|
||||
|
||||
# Download and extract amalgamation
|
||||
SQLITE=sqlite-amalgamation-3400000
|
||||
curl -O https://sqlite.org/2022/$SQLITE.zip
|
||||
SQLITE=sqlite-amalgamation-3410200
|
||||
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.h" > "$SQLITE3_LIB_DIR/sqlite3.h"
|
||||
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3ext.h" > "$SQLITE3_LIB_DIR/sqlite3ext.h"
|
||||
|
@ -8,7 +8,7 @@ mkdir -p "$SCRIPT_DIR/../target" "$SCRIPT_DIR/sqlcipher"
|
||||
export SQLCIPHER_LIB_DIR="$SCRIPT_DIR/sqlcipher"
|
||||
export SQLCIPHER_INCLUDE_DIR="$SQLCIPHER_LIB_DIR"
|
||||
|
||||
SQLCIPHER_VERSION="4.5.2"
|
||||
SQLCIPHER_VERSION="4.5.3"
|
||||
# Download and generate sqlcipher amalgamation
|
||||
mkdir -p $SCRIPT_DIR/sqlcipher.src
|
||||
[ -e "v${SQLCIPHER_VERSION}.tar.gz" ] || curl -sfL -O "https://github.com/sqlcipher/sqlcipher/archive/v${SQLCIPHER_VERSION}.tar.gz"
|
||||
|
@ -134,7 +134,7 @@
|
||||
//! // Insert another BLOB, this time using a parameter passed in from
|
||||
//! // rust (potentially with a dynamic size).
|
||||
//! db.execute(
|
||||
//! "INSERT INTO test_table (content) VALUES (?)",
|
||||
//! "INSERT INTO test_table (content) VALUES (?1)",
|
||||
//! [ZeroBlob(64)],
|
||||
//! )?;
|
||||
//!
|
||||
@ -175,7 +175,7 @@
|
||||
//! // Insert another blob, this time using a parameter passed in from
|
||||
//! // rust (potentially with a dynamic size).
|
||||
//! db.execute(
|
||||
//! "INSERT INTO test_table (content) VALUES (?)",
|
||||
//! "INSERT INTO test_table (content) VALUES (?1)",
|
||||
//! [ZeroBlob(64)],
|
||||
//! )?;
|
||||
//!
|
||||
|
@ -265,7 +265,7 @@ mod test {
|
||||
));
|
||||
blob.raw_read_at_exact(&mut s2, 5).unwrap_err();
|
||||
|
||||
let end_pos = blob.seek(std::io::SeekFrom::Current(0)).unwrap();
|
||||
let end_pos = blob.stream_position().unwrap();
|
||||
assert_eq!(end_pos, 1);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -17,13 +17,13 @@ impl Connection {
|
||||
/// # use rusqlite::{Connection, Result};
|
||||
/// fn insert_new_people(conn: &Connection) -> Result<()> {
|
||||
/// {
|
||||
/// let mut stmt = conn.prepare_cached("INSERT INTO People (name) VALUES (?)")?;
|
||||
/// let mut stmt = conn.prepare_cached("INSERT INTO People (name) VALUES (?1)")?;
|
||||
/// stmt.execute(["Joe Smith"])?;
|
||||
/// }
|
||||
/// {
|
||||
/// // This will return the same underlying SQLite statement handle without
|
||||
/// // having to prepare it again.
|
||||
/// let mut stmt = conn.prepare_cached("INSERT INTO People (name) VALUES (?)")?;
|
||||
/// let mut stmt = conn.prepare_cached("INSERT INTO People (name) VALUES (?1)")?;
|
||||
/// stmt.execute(["Bob Jones"])?;
|
||||
/// }
|
||||
/// Ok(())
|
||||
|
@ -69,13 +69,13 @@ impl InnerConnection {
|
||||
|
||||
// Replicate the check for sane open flags from SQLite, because the check in
|
||||
// SQLite itself wasn't added until version 3.7.3.
|
||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_ONLY.bits, 0x02);
|
||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits, 0x04);
|
||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_ONLY.bits(), 0x02);
|
||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits(), 0x04);
|
||||
debug_assert_eq!(
|
||||
1 << (OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE).bits,
|
||||
1 << (OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE).bits(),
|
||||
0x40
|
||||
);
|
||||
if (1 << (flags.bits & 0x7)) & 0x46 == 0 {
|
||||
if (1 << (flags.bits() & 0x7)) & 0x46 == 0 {
|
||||
return Err(Error::SqliteFailure(
|
||||
ffi::Error::new(ffi::SQLITE_MISUSE),
|
||||
None,
|
||||
@ -371,15 +371,7 @@ impl Drop for InnerConnection {
|
||||
#[allow(unused_must_use)]
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
use std::thread::panicking;
|
||||
|
||||
if let Err(e) = self.close() {
|
||||
if panicking() {
|
||||
eprintln!("Error while closing SQLite connection: {e:?}");
|
||||
} else {
|
||||
panic!("Error while closing SQLite connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
self.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
159
src/lib.rs
159
src/lib.rs
@ -62,7 +62,7 @@ use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
use std::result;
|
||||
use std::str;
|
||||
use std::sync::atomic::Ordering;
|
||||
@ -142,13 +142,6 @@ pub(crate) use util::SmallCString;
|
||||
|
||||
// Number of cached prepared statements we'll hold on to.
|
||||
const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
|
||||
/// To be used when your statement has no [parameter][sqlite-varparam].
|
||||
///
|
||||
/// [sqlite-varparam]: https://sqlite.org/lang_expr.html#varparam
|
||||
///
|
||||
/// This is deprecated in favor of using an empty array literal.
|
||||
#[deprecated = "Use an empty array instead; `stmt.execute(NO_PARAMS)` => `stmt.execute([])`"]
|
||||
pub const NO_PARAMS: &[&dyn ToSql] = &[];
|
||||
|
||||
/// A macro making it more convenient to longer lists of
|
||||
/// parameters as a `&[&dyn ToSql]`.
|
||||
@ -356,7 +349,6 @@ impl DatabaseName<'_> {
|
||||
pub struct Connection {
|
||||
db: RefCell<InnerConnection>,
|
||||
cache: StatementCache,
|
||||
path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Connection {}
|
||||
@ -453,7 +445,6 @@ impl Connection {
|
||||
InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection {
|
||||
db: RefCell::new(db),
|
||||
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
|
||||
path: Some(path.as_ref().to_path_buf()),
|
||||
})
|
||||
}
|
||||
|
||||
@ -478,7 +469,6 @@ impl Connection {
|
||||
InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Connection {
|
||||
db: RefCell::new(db),
|
||||
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
|
||||
path: Some(path.as_ref().to_path_buf()),
|
||||
})
|
||||
}
|
||||
|
||||
@ -560,7 +550,7 @@ impl Connection {
|
||||
/// ```rust,no_run
|
||||
/// # use rusqlite::{Connection};
|
||||
/// fn update_rows(conn: &Connection) {
|
||||
/// match conn.execute("UPDATE foo SET bar = 'baz' WHERE qux = ?", [1i32]) {
|
||||
/// match conn.execute("UPDATE foo SET bar = 'baz' WHERE qux = ?1", [1i32]) {
|
||||
/// Ok(updated) => println!("{} rows were updated", updated),
|
||||
/// Err(err) => println!("update failed: {}", err),
|
||||
/// }
|
||||
@ -606,12 +596,23 @@ impl Connection {
|
||||
|
||||
/// Returns the path to the database file, if one exists and is known.
|
||||
///
|
||||
/// Returns `Some("")` for a temporary or in-memory database.
|
||||
///
|
||||
/// Note that in some cases [PRAGMA
|
||||
/// database_list](https://sqlite.org/pragma.html#pragma_database_list) is
|
||||
/// likely to be more robust.
|
||||
#[inline]
|
||||
pub fn path(&self) -> Option<&Path> {
|
||||
self.path.as_deref()
|
||||
pub fn path(&self) -> Option<&str> {
|
||||
unsafe {
|
||||
let db = self.handle();
|
||||
let db_name = DatabaseName::Main.as_cstring().unwrap();
|
||||
let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
|
||||
if db_filename.is_null() {
|
||||
None
|
||||
} else {
|
||||
CStr::from_ptr(db_filename).to_str().ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to free as much heap memory as possible from the database
|
||||
@ -624,26 +625,6 @@ impl Connection {
|
||||
self.db.borrow_mut().release_memory()
|
||||
}
|
||||
|
||||
/// Convenience method to prepare and execute a single SQL statement with
|
||||
/// named parameter(s).
|
||||
///
|
||||
/// On success, returns the number of rows that were changed or inserted or
|
||||
/// deleted (via `sqlite3_changes`).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||
/// or if the underlying SQLite call fails.
|
||||
#[deprecated = "You can use `execute` with named params now."]
|
||||
pub fn execute_named(&self, sql: &str, params: &[(&str, &dyn ToSql)]) -> Result<usize> {
|
||||
// This function itself is deprecated, so it's fine
|
||||
#![allow(deprecated)]
|
||||
self.prepare(sql).and_then(|mut stmt| {
|
||||
stmt.check_no_tail()
|
||||
.and_then(|_| stmt.execute_named(params))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the SQLite rowid of the most recent successful INSERT.
|
||||
///
|
||||
/// Uses [sqlite3_last_insert_rowid](https://www.sqlite.org/c3ref/last_insert_rowid.html) under
|
||||
@ -697,28 +678,6 @@ impl Connection {
|
||||
self.query_row(sql, [], |r| r.get(0))
|
||||
}
|
||||
|
||||
/// Convenience method to execute a query with named parameter(s) that is
|
||||
/// expected to return a single row.
|
||||
///
|
||||
/// If the query returns more than one row, all rows except the first are
|
||||
/// ignored.
|
||||
///
|
||||
/// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
|
||||
/// query truly is optional, you can call `.optional()` on the result of
|
||||
/// this to get a `Result<Option<T>>`.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||
/// or if the underlying SQLite call fails.
|
||||
#[deprecated = "You can use `query_row` with named params now."]
|
||||
pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &dyn ToSql)], f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&Row<'_>) -> Result<T>,
|
||||
{
|
||||
self.query_row(sql, params, f)
|
||||
}
|
||||
|
||||
/// Convenience method to execute a query that is expected to return a
|
||||
/// single row, and execute a mapping via `f` on that returned row with
|
||||
/// the possibility of failure. The `Result` type of `f` must implement
|
||||
@ -765,7 +724,7 @@ impl Connection {
|
||||
/// ```rust,no_run
|
||||
/// # use rusqlite::{Connection, Result};
|
||||
/// fn insert_new_people(conn: &Connection) -> Result<()> {
|
||||
/// let mut stmt = conn.prepare("INSERT INTO People (name) VALUES (?)")?;
|
||||
/// let mut stmt = conn.prepare("INSERT INTO People (name) VALUES (?1)")?;
|
||||
/// stmt.execute(["Joe Smith"])?;
|
||||
/// stmt.execute(["Bob Jones"])?;
|
||||
/// Ok(())
|
||||
@ -947,12 +906,30 @@ impl Connection {
|
||||
/// This function is unsafe because improper use may impact the Connection.
|
||||
#[inline]
|
||||
pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> {
|
||||
let db_path = db_filename(db);
|
||||
let db = InnerConnection::new(db, false);
|
||||
Ok(Connection {
|
||||
db: RefCell::new(db),
|
||||
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
|
||||
path: db_path,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a `Connection` from a raw owned handle.
|
||||
///
|
||||
/// The returned connection will attempt to close the inner connection
|
||||
/// when dropped/closed. This function should only be called on connections
|
||||
/// owned by the caller.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because improper use may impact the Connection.
|
||||
/// In particular, it should only be called on connections created
|
||||
/// and owned by the caller, e.g. as a result of calling ffi::sqlite3_open().
|
||||
#[inline]
|
||||
pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Connection> {
|
||||
let db = InnerConnection::new(db, true);
|
||||
Ok(Connection {
|
||||
db: RefCell::new(db),
|
||||
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
|
||||
})
|
||||
}
|
||||
|
||||
@ -1005,7 +982,7 @@ impl Connection {
|
||||
impl fmt::Debug for Connection {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Connection")
|
||||
.field("path", &self.path)
|
||||
.field("path", &self.path())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@ -1078,6 +1055,7 @@ bitflags::bitflags! {
|
||||
/// The default open flags are `SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE
|
||||
/// | SQLITE_OPEN_URI | SQLITE_OPEN_NO_MUTEX`. See [`Connection::open`] for
|
||||
/// some discussion about these flags.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct OpenFlags: ::std::os::raw::c_int {
|
||||
/// The database is opened in read-only mode.
|
||||
@ -1196,16 +1174,6 @@ impl InterruptHandle {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option<PathBuf> {
|
||||
let db_name = DatabaseName::Main.as_cstring().unwrap();
|
||||
let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
|
||||
if db_filename.is_null() {
|
||||
None
|
||||
} else {
|
||||
CStr::from_ptr(db_filename).to_str().ok().map(PathBuf::from)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(doctest)]
|
||||
doc_comment::doctest!("../README.md");
|
||||
|
||||
@ -1307,6 +1275,21 @@ mod test {
|
||||
db.close().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path() -> Result<()> {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let db = Connection::open("")?;
|
||||
assert_eq!(Some(""), db.path());
|
||||
let db = Connection::open_in_memory()?;
|
||||
assert_eq!(Some(""), db.path());
|
||||
let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?;
|
||||
assert_eq!(Some(""), db.path());
|
||||
let path = tmp.path().join("file.db");
|
||||
let db = Connection::open(path)?;
|
||||
assert!(db.path().map(|p| p.ends_with("file.db")).unwrap_or(false));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_open_failure() {
|
||||
let filename = "no_such_file.db";
|
||||
@ -1432,8 +1415,8 @@ mod test {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
|
||||
|
||||
assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [1i32])?);
|
||||
assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [2i32])?);
|
||||
assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [1i32])?);
|
||||
assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?1)", [2i32])?);
|
||||
|
||||
assert_eq!(3i32, db.one_column::<i32>("SELECT SUM(x) FROM foo")?);
|
||||
Ok(())
|
||||
@ -1443,7 +1426,7 @@ mod test {
|
||||
#[cfg(feature = "extra_check")]
|
||||
fn test_execute_select() {
|
||||
let db = checked_memory_handle();
|
||||
let err = db.execute("SELECT 1 WHERE 1 < ?", [1i32]).unwrap_err();
|
||||
let err = db.execute("SELECT 1 WHERE 1 < ?1", [1i32]).unwrap_err();
|
||||
assert_eq!(
|
||||
err,
|
||||
Error::ExecuteReturnedResults,
|
||||
@ -1488,7 +1471,7 @@ mod test {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
|
||||
|
||||
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
|
||||
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
|
||||
assert_eq!(insert_stmt.execute([1i32])?, 1);
|
||||
assert_eq!(insert_stmt.execute([2i32])?, 1);
|
||||
assert_eq!(insert_stmt.execute([3i32])?, 1);
|
||||
@ -1497,7 +1480,7 @@ mod test {
|
||||
assert_eq!(insert_stmt.execute(["goodbye"])?, 1);
|
||||
assert_eq!(insert_stmt.execute([types::Null])?, 1);
|
||||
|
||||
let mut update_stmt = db.prepare("UPDATE foo SET x=? WHERE x<?")?;
|
||||
let mut update_stmt = db.prepare("UPDATE foo SET x=?1 WHERE x<?2")?;
|
||||
assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
|
||||
assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
|
||||
assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
|
||||
@ -1509,12 +1492,12 @@ mod test {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
|
||||
|
||||
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
|
||||
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?1)")?;
|
||||
assert_eq!(insert_stmt.execute([1i32])?, 1);
|
||||
assert_eq!(insert_stmt.execute([2i32])?, 1);
|
||||
assert_eq!(insert_stmt.execute([3i32])?, 1);
|
||||
|
||||
let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC")?;
|
||||
let mut query = db.prepare("SELECT x FROM foo WHERE x < ?1 ORDER BY x DESC")?;
|
||||
{
|
||||
let mut rows = query.query([4i32])?;
|
||||
let mut v = Vec::<i32>::new();
|
||||
@ -1779,7 +1762,7 @@ mod test {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.execute_batch("CREATE TABLE foo(i, x);")?;
|
||||
let vals = ["foobar", "1234", "qwerty"];
|
||||
let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?, ?)")?;
|
||||
let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?1, ?2)")?;
|
||||
for (i, v) in vals.iter().enumerate() {
|
||||
let i_to_insert = i as i64;
|
||||
assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
|
||||
@ -1819,6 +1802,16 @@ mod test {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_handle_owned() -> Result<()> {
|
||||
let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
|
||||
let r = unsafe { ffi::sqlite3_open(":memory:\0".as_ptr() as *const i8, &mut handle) };
|
||||
assert_eq!(r, ffi::SQLITE_OK);
|
||||
let db = unsafe { Connection::from_handle_owned(handle) }?;
|
||||
db.execute_batch("PRAGMA VACUUM")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
mod query_and_then_tests {
|
||||
|
||||
use super::*;
|
||||
@ -2045,7 +2038,7 @@ mod test {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
|
||||
let b: Box<dyn ToSql> = Box::new(5);
|
||||
db.execute("INSERT INTO foo VALUES(?)", [b])?;
|
||||
db.execute("INSERT INTO foo VALUES(?1)", [b])?;
|
||||
db.query_row("SELECT x FROM foo", [], |r| {
|
||||
assert_eq!(5, r.get_unwrap::<_, i32>(0));
|
||||
Ok(())
|
||||
@ -2057,10 +2050,10 @@ mod test {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.query_row(
|
||||
"SELECT
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?;",
|
||||
?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10,
|
||||
?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20,
|
||||
?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30,
|
||||
?31, ?32, ?33, ?34;",
|
||||
params![
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1,
|
||||
|
@ -70,7 +70,7 @@ use sealed::Sealed;
|
||||
/// ```rust,no_run
|
||||
/// # use rusqlite::{Connection, Result, params};
|
||||
/// fn update_rows(conn: &Connection) -> Result<()> {
|
||||
/// let mut stmt = conn.prepare("INSERT INTO test (a, b) VALUES (?, ?)")?;
|
||||
/// let mut stmt = conn.prepare("INSERT INTO test (a, b) VALUES (?1, ?2)")?;
|
||||
///
|
||||
/// // Using a tuple:
|
||||
/// stmt.execute((0, "foobar"))?;
|
||||
@ -138,9 +138,7 @@ use sealed::Sealed;
|
||||
/// ## No parameters
|
||||
///
|
||||
/// You can just use an empty tuple or the empty array literal to run a query
|
||||
/// that accepts no parameters. (The `rusqlite::NO_PARAMS` constant which was
|
||||
/// common in previous versions of this library is no longer needed, and is now
|
||||
/// deprecated).
|
||||
/// that accepts no parameters.
|
||||
///
|
||||
/// ### Example (no parameters)
|
||||
///
|
||||
@ -192,8 +190,7 @@ pub trait Params: Sealed {
|
||||
}
|
||||
|
||||
// Explicitly impl for empty array. Critically, for `conn.execute([])` to be
|
||||
// unambiguous, this must be the *only* implementation for an empty array. This
|
||||
// avoids `NO_PARAMS` being a necessary part of the API.
|
||||
// unambiguous, this must be the *only* implementation for an empty array.
|
||||
//
|
||||
// This sadly prevents `impl<T: ToSql, const N: usize> Params for [T; N]`, which
|
||||
// forces people to use `params![...]` or `rusqlite::params_from_iter` for long
|
||||
@ -357,7 +354,7 @@ impl_for_array_ref!(
|
||||
/// fn query(conn: &Connection, ids: &BTreeSet<String>) -> Result<()> {
|
||||
/// assert_eq!(ids.len(), 3, "Unrealistic sample code");
|
||||
///
|
||||
/// let mut stmt = conn.prepare("SELECT * FROM users WHERE id IN (?, ?, ?)")?;
|
||||
/// let mut stmt = conn.prepare("SELECT * FROM users WHERE id IN (?1, ?2, ?3)")?;
|
||||
/// let _rows = stmt.query(params_from_iter(ids.iter()))?;
|
||||
///
|
||||
/// // use _rows...
|
||||
|
@ -211,7 +211,7 @@ impl Connection {
|
||||
/// (e.g. `integrity_check`).
|
||||
///
|
||||
/// Prefer [PRAGMA function](https://sqlite.org/pragma.html#pragfunc) introduced in SQLite 3.20:
|
||||
/// `SELECT * FROM pragma_table_info(?);`
|
||||
/// `SELECT * FROM pragma_table_info(?1);`
|
||||
pub fn pragma<F, V>(
|
||||
&self,
|
||||
schema_name: Option<DatabaseName<'_>>,
|
||||
@ -303,15 +303,15 @@ fn is_identifier(s: &str) -> bool {
|
||||
}
|
||||
|
||||
fn is_identifier_start(c: char) -> bool {
|
||||
('A'..='Z').contains(&c) || c == '_' || ('a'..='z').contains(&c) || c > '\x7F'
|
||||
c.is_ascii_uppercase() || c == '_' || c.is_ascii_lowercase() || c > '\x7F'
|
||||
}
|
||||
|
||||
fn is_identifier_continue(c: char) -> bool {
|
||||
c == '$'
|
||||
|| ('0'..='9').contains(&c)
|
||||
|| ('A'..='Z').contains(&c)
|
||||
|| c.is_ascii_digit()
|
||||
|| c.is_ascii_uppercase()
|
||||
|| c == '_'
|
||||
|| ('a'..='z').contains(&c)
|
||||
|| c.is_ascii_lowercase()
|
||||
|| c > '\x7F'
|
||||
}
|
||||
|
||||
@ -379,7 +379,7 @@ mod test {
|
||||
#[cfg(feature = "modern_sqlite")]
|
||||
fn pragma_func() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let mut table_info = db.prepare("SELECT * FROM pragma_table_info(?)")?;
|
||||
let mut table_info = db.prepare("SELECT * FROM pragma_table_info(?1)")?;
|
||||
let mut columns = Vec::new();
|
||||
let mut rows = table_info.query(["sqlite_master"])?;
|
||||
|
||||
|
@ -169,8 +169,10 @@ impl RawStatement {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clear_bindings(&self) -> c_int {
|
||||
unsafe { ffi::sqlite3_clear_bindings(self.ptr) }
|
||||
pub fn clear_bindings(&self) {
|
||||
unsafe {
|
||||
ffi::sqlite3_clear_bindings(self.ptr);
|
||||
} // rc is always SQLITE_OK
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -195,7 +197,6 @@ impl RawStatement {
|
||||
}
|
||||
|
||||
// does not work for PRAGMA
|
||||
#[cfg(feature = "extra_check")]
|
||||
#[inline]
|
||||
pub fn readonly(&self) -> bool {
|
||||
unsafe { ffi::sqlite3_stmt_readonly(self.ptr) != 0 }
|
||||
|
14
src/row.rs
14
src/row.rs
@ -338,20 +338,6 @@ impl<'stmt> Row<'stmt> {
|
||||
pub fn get_ref_unwrap<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
|
||||
self.get_ref(idx).unwrap()
|
||||
}
|
||||
|
||||
/// Renamed to [`get_ref`](Row::get_ref).
|
||||
#[deprecated = "Use [`get_ref`](Row::get_ref) instead."]
|
||||
#[inline]
|
||||
pub fn get_raw_checked<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'_>> {
|
||||
self.get_ref(idx)
|
||||
}
|
||||
|
||||
/// Renamed to [`get_ref_unwrap`](Row::get_ref_unwrap).
|
||||
#[deprecated = "Use [`get_ref_unwrap`](Row::get_ref_unwrap) instead."]
|
||||
#[inline]
|
||||
pub fn get_raw<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
|
||||
self.get_ref_unwrap(idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'stmt> AsRef<Statement<'stmt>> for Row<'stmt> {
|
||||
|
@ -779,7 +779,7 @@ mod test {
|
||||
assert!(session.is_empty());
|
||||
|
||||
session.attach(None)?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?);", ["bar"])?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?1);", ["bar"])?;
|
||||
|
||||
session.changeset()
|
||||
}
|
||||
@ -792,7 +792,7 @@ mod test {
|
||||
assert!(session.is_empty());
|
||||
|
||||
session.attach(None)?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?);", ["bar"])?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?1);", ["bar"])?;
|
||||
|
||||
let mut output = Vec::new();
|
||||
session.changeset_strm(&mut output)?;
|
||||
@ -852,7 +852,7 @@ mod test {
|
||||
)?;
|
||||
|
||||
assert!(!CALLED.load(Ordering::Relaxed));
|
||||
let check = db.query_row("SELECT 1 FROM foo WHERE t = ?", ["bar"], |row| {
|
||||
let check = db.query_row("SELECT 1 FROM foo WHERE t = ?1", ["bar"], |row| {
|
||||
row.get::<_, i32>(0)
|
||||
})?;
|
||||
assert_eq!(1, check);
|
||||
@ -887,7 +887,7 @@ mod test {
|
||||
|_conflict_type, _item| ConflictAction::SQLITE_CHANGESET_OMIT,
|
||||
)?;
|
||||
|
||||
let check = db.query_row("SELECT 1 FROM foo WHERE t = ?", ["bar"], |row| {
|
||||
let check = db.query_row("SELECT 1 FROM foo WHERE t = ?1", ["bar"], |row| {
|
||||
row.get::<_, i32>(0)
|
||||
})?;
|
||||
assert_eq!(1, check);
|
||||
@ -903,7 +903,7 @@ mod test {
|
||||
assert!(session.is_empty());
|
||||
|
||||
session.attach(None)?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?);", ["bar"])?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?1);", ["bar"])?;
|
||||
|
||||
assert!(!session.is_empty());
|
||||
Ok(())
|
||||
|
279
src/statement.rs
279
src/statement.rs
@ -33,7 +33,7 @@ impl Statement<'_> {
|
||||
/// ```rust,no_run
|
||||
/// # use rusqlite::{Connection, Result, params};
|
||||
/// fn update_rows(conn: &Connection) -> Result<()> {
|
||||
/// let mut stmt = conn.prepare("UPDATE foo SET bar = ? WHERE qux = ?")?;
|
||||
/// let mut stmt = conn.prepare("UPDATE foo SET bar = ?1 WHERE qux = ?2")?;
|
||||
/// // For a single parameter, or a parameter where all the values have
|
||||
/// // the same type, just passing an array is simplest.
|
||||
/// stmt.execute([2i32])?;
|
||||
@ -58,7 +58,7 @@ impl Statement<'_> {
|
||||
/// fn store_file(conn: &Connection, path: &str, data: &[u8]) -> Result<()> {
|
||||
/// # // no need to do it for real.
|
||||
/// # fn sha256(_: &[u8]) -> [u8; 32] { [0; 32] }
|
||||
/// let query = "INSERT OR REPLACE INTO files(path, hash, data) VALUES (?, ?, ?)";
|
||||
/// let query = "INSERT OR REPLACE INTO files(path, hash, data) VALUES (?1, ?2, ?3)";
|
||||
/// let mut stmt = conn.prepare_cached(query)?;
|
||||
/// let hash: [u8; 32] = sha256(data);
|
||||
/// // The easiest way to pass positional parameters of have several
|
||||
@ -114,31 +114,6 @@ impl Statement<'_> {
|
||||
self.execute_with_bound_parameters()
|
||||
}
|
||||
|
||||
/// Execute the prepared statement with named parameter(s).
|
||||
///
|
||||
/// Note: This function is deprecated in favor of [`Statement::execute`],
|
||||
/// which can now take named parameters directly.
|
||||
///
|
||||
/// If any parameters that were in the prepared statement are not included
|
||||
/// in `params`, they will continue to use the most-recently bound value
|
||||
/// from a previous call to `execute_named`, or `NULL` if they have never
|
||||
/// been bound.
|
||||
///
|
||||
/// On success, returns the number of rows that were changed or inserted or
|
||||
/// deleted (via `sqlite3_changes`).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Will return `Err` if binding parameters fails, the executed statement
|
||||
/// returns rows (in which case `query` should be used instead), or the
|
||||
/// underlying SQLite call fails.
|
||||
#[doc(hidden)]
|
||||
#[deprecated = "You can use `execute` with named params now."]
|
||||
#[inline]
|
||||
pub fn execute_named(&mut self, params: &[(&str, &dyn ToSql)]) -> Result<usize> {
|
||||
self.execute(params)
|
||||
}
|
||||
|
||||
/// Execute an INSERT and return the ROWID.
|
||||
///
|
||||
/// # Note
|
||||
@ -193,7 +168,7 @@ impl Statement<'_> {
|
||||
/// ```rust,no_run
|
||||
/// # use rusqlite::{Connection, Result};
|
||||
/// fn query(conn: &Connection, name: &str) -> Result<()> {
|
||||
/// let mut stmt = conn.prepare("SELECT * FROM test where name = ?")?;
|
||||
/// let mut stmt = conn.prepare("SELECT * FROM test where name = ?1")?;
|
||||
/// let mut rows = stmt.query(rusqlite::params![name])?;
|
||||
/// while let Some(row) = rows.next()? {
|
||||
/// // ...
|
||||
@ -207,7 +182,7 @@ impl Statement<'_> {
|
||||
/// ```rust,no_run
|
||||
/// # use rusqlite::{Connection, Result};
|
||||
/// fn query(conn: &Connection, name: &str) -> Result<()> {
|
||||
/// let mut stmt = conn.prepare("SELECT * FROM test where name = ?")?;
|
||||
/// let mut stmt = conn.prepare("SELECT * FROM test where name = ?1")?;
|
||||
/// let mut rows = stmt.query([name])?;
|
||||
/// while let Some(row) = rows.next()? {
|
||||
/// // ...
|
||||
@ -254,26 +229,6 @@ impl Statement<'_> {
|
||||
Ok(Rows::new(self))
|
||||
}
|
||||
|
||||
/// Execute the prepared statement with named parameter(s), returning a
|
||||
/// handle for the resulting rows.
|
||||
///
|
||||
/// Note: This function is deprecated in favor of [`Statement::query`],
|
||||
/// which can now take named parameters directly.
|
||||
///
|
||||
/// If any parameters that were in the prepared statement are not included
|
||||
/// in `params`, they will continue to use the most-recently bound value
|
||||
/// from a previous call to `query_named`, or `NULL` if they have never been
|
||||
/// bound.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Will return `Err` if binding parameters fails.
|
||||
#[doc(hidden)]
|
||||
#[deprecated = "You can use `query` with named params now."]
|
||||
pub fn query_named(&mut self, params: &[(&str, &dyn ToSql)]) -> Result<Rows<'_>> {
|
||||
self.query(params)
|
||||
}
|
||||
|
||||
/// Executes the prepared statement and maps a function over the resulting
|
||||
/// rows, returning an iterator over the mapped function results.
|
||||
///
|
||||
@ -328,37 +283,6 @@ impl Statement<'_> {
|
||||
self.query(params).map(|rows| rows.mapped(f))
|
||||
}
|
||||
|
||||
/// Execute the prepared statement with named parameter(s), returning an
|
||||
/// iterator over the result of calling the mapping function over the
|
||||
/// query's rows.
|
||||
///
|
||||
/// Note: This function is deprecated in favor of [`Statement::query_map`],
|
||||
/// which can now take named parameters directly.
|
||||
///
|
||||
/// If any parameters that were in the prepared statement
|
||||
/// are not included in `params`, they will continue to use the
|
||||
/// most-recently bound value from a previous call to `query_named`,
|
||||
/// or `NULL` if they have never been bound.
|
||||
///
|
||||
/// `f` is used to transform the _streaming_ iterator into a _standard_
|
||||
/// iterator.
|
||||
///
|
||||
/// ## Failure
|
||||
///
|
||||
/// Will return `Err` if binding parameters fails.
|
||||
#[doc(hidden)]
|
||||
#[deprecated = "You can use `query_map` with named params now."]
|
||||
pub fn query_map_named<T, F>(
|
||||
&mut self,
|
||||
params: &[(&str, &dyn ToSql)],
|
||||
f: F,
|
||||
) -> Result<MappedRows<'_, F>>
|
||||
where
|
||||
F: FnMut(&Row<'_>) -> Result<T>,
|
||||
{
|
||||
self.query_map(params, f)
|
||||
}
|
||||
|
||||
/// Executes the prepared statement and maps a function over the resulting
|
||||
/// rows, where the function returns a `Result` with `Error` type
|
||||
/// implementing `std::convert::From<Error>` (so errors can be unified).
|
||||
@ -398,7 +322,7 @@ impl Statement<'_> {
|
||||
/// ```rust,no_run
|
||||
/// # use rusqlite::{Connection, Result};
|
||||
/// fn get_names(conn: &Connection) -> Result<Vec<String>> {
|
||||
/// let mut stmt = conn.prepare("SELECT name FROM people WHERE id = ?")?;
|
||||
/// let mut stmt = conn.prepare("SELECT name FROM people WHERE id = ?1")?;
|
||||
/// let rows = stmt.query_and_then(["one"], |row| row.get::<_, String>(0))?;
|
||||
///
|
||||
/// let mut persons = Vec::new();
|
||||
@ -423,36 +347,6 @@ impl Statement<'_> {
|
||||
self.query(params).map(|rows| rows.and_then(f))
|
||||
}
|
||||
|
||||
/// Execute the prepared statement with named parameter(s), returning an
|
||||
/// iterator over the result of calling the mapping function over the
|
||||
/// query's rows.
|
||||
///
|
||||
/// Note: This function is deprecated in favor of
|
||||
/// [`Statement::query_and_then`], which can now take named parameters
|
||||
/// directly.
|
||||
///
|
||||
/// If any parameters that were in the prepared statement are not included
|
||||
/// in `params`, they will continue to use the most-recently bound value
|
||||
/// from a previous call to `query_named`, or `NULL` if they have never been
|
||||
/// bound.
|
||||
///
|
||||
/// ## Failure
|
||||
///
|
||||
/// Will return `Err` if binding parameters fails.
|
||||
#[doc(hidden)]
|
||||
#[deprecated = "You can use `query_and_then` with named params now."]
|
||||
pub fn query_and_then_named<T, E, F>(
|
||||
&mut self,
|
||||
params: &[(&str, &dyn ToSql)],
|
||||
f: F,
|
||||
) -> Result<AndThenRows<'_, F>>
|
||||
where
|
||||
E: From<Error>,
|
||||
F: FnMut(&Row<'_>) -> Result<T, E>,
|
||||
{
|
||||
self.query_and_then(params, f)
|
||||
}
|
||||
|
||||
/// Return `true` if a query in the SQL statement it executes returns one
|
||||
/// or more rows and `false` if the SQL returns an empty set.
|
||||
#[inline]
|
||||
@ -487,35 +381,6 @@ impl Statement<'_> {
|
||||
rows.get_expected_row().and_then(f)
|
||||
}
|
||||
|
||||
/// Convenience method to execute a query with named parameter(s) that is
|
||||
/// expected to return a single row.
|
||||
///
|
||||
/// Note: This function is deprecated in favor of
|
||||
/// [`Statement::query_and_then`], which can now take named parameters
|
||||
/// directly.
|
||||
///
|
||||
/// If the query returns more than one row, all rows except the first are
|
||||
/// ignored.
|
||||
///
|
||||
/// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
|
||||
/// query truly is optional, you can call
|
||||
/// [`.optional()`](crate::OptionalExtension::optional) on the result of
|
||||
/// this to get a `Result<Option<T>>` (requires that the trait
|
||||
/// `rusqlite::OptionalExtension` is imported).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||
/// or if the underlying SQLite call fails.
|
||||
#[doc(hidden)]
|
||||
#[deprecated = "You can use `query_row` with named params now."]
|
||||
pub fn query_row_named<T, F>(&mut self, params: &[(&str, &dyn ToSql)], f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&Row<'_>) -> Result<T>,
|
||||
{
|
||||
self.query_row(params, f)
|
||||
}
|
||||
|
||||
/// Consumes the statement.
|
||||
///
|
||||
/// Functionally equivalent to the `Drop` implementation, but allows
|
||||
@ -844,6 +709,12 @@ impl Statement<'_> {
|
||||
self.stmt.is_explain()
|
||||
}
|
||||
|
||||
/// Returns true if the statement is read only.
|
||||
#[inline]
|
||||
pub fn readonly(&self) -> bool {
|
||||
self.stmt.readonly()
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra_check")]
|
||||
#[inline]
|
||||
pub(crate) fn check_no_tail(&self) -> Result<()> {
|
||||
@ -870,6 +741,11 @@ impl Statement<'_> {
|
||||
mem::swap(&mut stmt, &mut self.stmt);
|
||||
stmt
|
||||
}
|
||||
|
||||
/// Reset all bindings
|
||||
pub fn clear_bindings(&mut self) {
|
||||
self.stmt.clear_bindings()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Statement<'_> {
|
||||
@ -1009,13 +885,12 @@ mod test {
|
||||
use crate::{params_from_iter, Connection, Error, Result};
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_execute_named() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
|
||||
|
||||
assert_eq!(
|
||||
db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)])?,
|
||||
db.execute("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)])?,
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
@ -1032,7 +907,7 @@ mod test {
|
||||
|
||||
assert_eq!(
|
||||
6i32,
|
||||
db.query_row_named::<i32, _>(
|
||||
db.query_row::<i32, _, _>(
|
||||
"SELECT SUM(x) FROM foo WHERE x > :x",
|
||||
&[(":x", &0i32)],
|
||||
|r| r.get(0)
|
||||
@ -1050,7 +925,6 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_stmt_execute_named() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
|
||||
@ -1058,13 +932,9 @@ mod test {
|
||||
db.execute_batch(sql)?;
|
||||
|
||||
let mut stmt = db.prepare("INSERT INTO test (name) VALUES (:name)")?;
|
||||
stmt.execute_named(&[(":name", &"one")])?;
|
||||
stmt.execute(&[(":name", &"one")])?;
|
||||
|
||||
let mut stmt = db.prepare("SELECT COUNT(*) FROM test WHERE name = :name")?;
|
||||
assert_eq!(
|
||||
1i32,
|
||||
stmt.query_row_named::<i32, _>(&[(":name", &"one")], |r| r.get(0))?
|
||||
);
|
||||
assert_eq!(
|
||||
1i32,
|
||||
stmt.query_row::<i32, _, _>(&[(":name", "one")], |r| r.get(0))?
|
||||
@ -1073,7 +943,6 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_query_named() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let sql = r#"
|
||||
@ -1083,24 +952,13 @@ mod test {
|
||||
db.execute_batch(sql)?;
|
||||
|
||||
let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
|
||||
// legacy `_named` api
|
||||
{
|
||||
let mut rows = stmt.query_named(&[(":name", &"one")])?;
|
||||
let id: Result<i32> = rows.next()?.unwrap().get(0);
|
||||
assert_eq!(Ok(1), id);
|
||||
}
|
||||
|
||||
// plain api
|
||||
{
|
||||
let mut rows = stmt.query(&[(":name", "one")])?;
|
||||
let id: Result<i32> = rows.next()?.unwrap().get(0);
|
||||
assert_eq!(Ok(1), id);
|
||||
}
|
||||
let mut rows = stmt.query(&[(":name", "one")])?;
|
||||
let id: Result<i32> = rows.next()?.unwrap().get(0);
|
||||
assert_eq!(Ok(1), id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_query_map_named() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let sql = r#"
|
||||
@ -1110,61 +968,13 @@ mod test {
|
||||
db.execute_batch(sql)?;
|
||||
|
||||
let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
|
||||
// legacy `_named` api
|
||||
{
|
||||
let mut rows = stmt.query_map_named(&[(":name", &"one")], |row| {
|
||||
let id: Result<i32> = row.get(0);
|
||||
id.map(|i| 2 * i)
|
||||
})?;
|
||||
|
||||
let doubled_id: i32 = rows.next().unwrap()?;
|
||||
assert_eq!(2, doubled_id);
|
||||
}
|
||||
// plain api
|
||||
{
|
||||
let mut rows = stmt.query_map(&[(":name", "one")], |row| {
|
||||
let id: Result<i32> = row.get(0);
|
||||
id.map(|i| 2 * i)
|
||||
})?;
|
||||
|
||||
let doubled_id: i32 = rows.next().unwrap()?;
|
||||
assert_eq!(2, doubled_id);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_query_and_then_named() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let sql = r#"
|
||||
CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
|
||||
INSERT INTO test(id, name) VALUES (1, "one");
|
||||
INSERT INTO test(id, name) VALUES (2, "one");
|
||||
"#;
|
||||
db.execute_batch(sql)?;
|
||||
|
||||
let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC")?;
|
||||
let mut rows = stmt.query_and_then_named(&[(":name", &"one")], |row| {
|
||||
let id: i32 = row.get(0)?;
|
||||
if id == 1 {
|
||||
Ok(id)
|
||||
} else {
|
||||
Err(Error::SqliteSingleThreadedMode)
|
||||
}
|
||||
let mut rows = stmt.query_map(&[(":name", "one")], |row| {
|
||||
let id: Result<i32> = row.get(0);
|
||||
id.map(|i| 2 * i)
|
||||
})?;
|
||||
|
||||
// first row should be Ok
|
||||
let doubled_id: i32 = rows.next().unwrap()?;
|
||||
assert_eq!(1, doubled_id);
|
||||
|
||||
// second row should be Err
|
||||
#[allow(clippy::match_wild_err_arm)]
|
||||
match rows.next().unwrap() {
|
||||
Ok(_) => panic!("invalid Ok"),
|
||||
Err(Error::SqliteSingleThreadedMode) => (),
|
||||
Err(_) => panic!("invalid Err"),
|
||||
}
|
||||
assert_eq!(2, doubled_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1203,14 +1013,13 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_unbound_parameters_are_null() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let sql = "CREATE TABLE test (x TEXT, y TEXT)";
|
||||
db.execute_batch(sql)?;
|
||||
|
||||
let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)")?;
|
||||
stmt.execute_named(&[(":x", &"one")])?;
|
||||
stmt.execute(&[(":x", &"one")])?;
|
||||
|
||||
let result: Option<String> = db.one_column("SELECT y FROM test WHERE x = 'one'")?;
|
||||
assert!(result.is_none());
|
||||
@ -1267,7 +1076,7 @@ mod test {
|
||||
fn test_insert() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)")?;
|
||||
let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?)")?;
|
||||
let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?1)")?;
|
||||
assert_eq!(stmt.insert([1i32])?, 1);
|
||||
assert_eq!(stmt.insert([2i32])?, 2);
|
||||
match stmt.insert([1i32]).unwrap_err() {
|
||||
@ -1307,7 +1116,7 @@ mod test {
|
||||
INSERT INTO foo VALUES(2);
|
||||
END;";
|
||||
db.execute_batch(sql)?;
|
||||
let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?")?;
|
||||
let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?1")?;
|
||||
assert!(stmt.exists([1i32])?);
|
||||
assert!(stmt.exists([2i32])?);
|
||||
assert!(!stmt.exists([0i32])?);
|
||||
@ -1316,18 +1125,18 @@ mod test {
|
||||
#[test]
|
||||
fn test_tuple_params() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let s = db.query_row("SELECT printf('[%s]', ?)", ("abc",), |r| {
|
||||
let s = db.query_row("SELECT printf('[%s]', ?1)", ("abc",), |r| {
|
||||
r.get::<_, String>(0)
|
||||
})?;
|
||||
assert_eq!(s, "[abc]");
|
||||
let s = db.query_row(
|
||||
"SELECT printf('%d %s %d', ?, ?, ?)",
|
||||
"SELECT printf('%d %s %d', ?1, ?2, ?3)",
|
||||
(1i32, "abc", 2i32),
|
||||
|r| r.get::<_, String>(0),
|
||||
)?;
|
||||
assert_eq!(s, "1 abc 2");
|
||||
let s = db.query_row(
|
||||
"SELECT printf('%d %s %d %d', ?, ?, ?, ?)",
|
||||
"SELECT printf('%d %s %d %d', ?1, ?2, ?3, ?4)",
|
||||
(1, "abc", 2i32, 4i64),
|
||||
|r| r.get::<_, String>(0),
|
||||
)?;
|
||||
@ -1339,10 +1148,10 @@ mod test {
|
||||
);
|
||||
let query = "SELECT printf(
|
||||
'%d %s | %d %s | %d %s | %d %s || %d %s | %d %s | %d %s | %d %s',
|
||||
?, ?, ?, ?,
|
||||
?, ?, ?, ?,
|
||||
?, ?, ?, ?,
|
||||
?, ?, ?, ?
|
||||
?1, ?2, ?3, ?4,
|
||||
?5, ?6, ?7, ?8,
|
||||
?9, ?10, ?11, ?12,
|
||||
?13, ?14, ?15, ?16
|
||||
)";
|
||||
let s = db.query_row(query, bigtup, |r| r.get::<_, String>(0))?;
|
||||
assert_eq!(s, "0 a | 1 b | 2 c | 3 d || 4 e | 5 f | 6 g | 7 h");
|
||||
@ -1358,7 +1167,7 @@ mod test {
|
||||
INSERT INTO foo VALUES(2, 4);
|
||||
END;";
|
||||
db.execute_batch(sql)?;
|
||||
let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?")?;
|
||||
let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?1")?;
|
||||
let y: Result<i64> = stmt.query_row([1i32], |r| r.get(0));
|
||||
assert_eq!(3i64, y?);
|
||||
Ok(())
|
||||
@ -1395,7 +1204,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_expanded_sql() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let stmt = db.prepare("SELECT ?")?;
|
||||
let stmt = db.prepare("SELECT ?1")?;
|
||||
stmt.bind_parameter(&1, 1)?;
|
||||
assert_eq!(Some("SELECT 1".to_owned()), stmt.expanded_sql());
|
||||
Ok(())
|
||||
@ -1497,7 +1306,7 @@ mod test {
|
||||
assert_eq!("UTF-16le", encoding);
|
||||
db.execute_batch("CREATE TABLE foo(x TEXT)")?;
|
||||
let expected = "テスト";
|
||||
db.execute("INSERT INTO foo(x) VALUES (?)", [&expected])?;
|
||||
db.execute("INSERT INTO foo(x) VALUES (?1)", [&expected])?;
|
||||
let actual: String = db.one_column("SELECT x FROM foo")?;
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
@ -1507,7 +1316,7 @@ mod test {
|
||||
fn test_nul_byte() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let expected = "a\x00b";
|
||||
let actual: String = db.query_row("SELECT ?", [expected], |row| row.get(0))?;
|
||||
let actual: String = db.query_row("SELECT ?1", [expected], |row| row.get(0))?;
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
@ -1521,6 +1330,14 @@ mod test {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn readonly() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let stmt = db.prepare("SELECT 1;")?;
|
||||
assert!(stmt.readonly());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
|
||||
fn test_error_offset() -> Result<()> {
|
||||
|
@ -144,13 +144,13 @@ mod test {
|
||||
let mut db = Connection::open_in_memory()?;
|
||||
db.trace(Some(tracer));
|
||||
{
|
||||
let _ = db.query_row("SELECT ?", [1i32], |_| Ok(()));
|
||||
let _ = db.query_row("SELECT ?", ["hello"], |_| Ok(()));
|
||||
let _ = db.query_row("SELECT ?1", [1i32], |_| Ok(()));
|
||||
let _ = db.query_row("SELECT ?1", ["hello"], |_| Ok(()));
|
||||
}
|
||||
db.trace(None);
|
||||
{
|
||||
let _ = db.query_row("SELECT ?", [2i32], |_| Ok(()));
|
||||
let _ = db.query_row("SELECT ?", ["goodbye"], |_| Ok(()));
|
||||
let _ = db.query_row("SELECT ?1", [2i32], |_| Ok(()));
|
||||
let _ = db.query_row("SELECT ?1", ["goodbye"], |_| Ok(()));
|
||||
}
|
||||
|
||||
let traced_stmts = TRACED_STMTS.lock().unwrap();
|
||||
|
@ -718,7 +718,7 @@ mod test {
|
||||
}
|
||||
|
||||
fn insert(x: i32, conn: &Connection) -> Result<usize> {
|
||||
conn.execute("INSERT INTO foo VALUES(?)", [x])
|
||||
conn.execute("INSERT INTO foo VALUES(?1)", [x])
|
||||
}
|
||||
|
||||
fn assert_current_sum(x: i32, conn: &Connection) -> Result<()> {
|
||||
|
@ -176,7 +176,7 @@ mod test {
|
||||
fn test_naive_date() -> Result<()> {
|
||||
let db = checked_memory_handle()?;
|
||||
let date = NaiveDate::from_ymd_opt(2016, 2, 23).unwrap();
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [date])?;
|
||||
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);
|
||||
@ -189,7 +189,7 @@ mod test {
|
||||
fn test_naive_time() -> Result<()> {
|
||||
let db = checked_memory_handle()?;
|
||||
let time = NaiveTime::from_hms_opt(23, 56, 4).unwrap();
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [time])?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?1)", [time])?;
|
||||
|
||||
let s: String = db.one_column("SELECT t FROM foo")?;
|
||||
assert_eq!("23:56:04", s);
|
||||
@ -205,7 +205,7 @@ mod test {
|
||||
let time = NaiveTime::from_hms_opt(23, 56, 4).unwrap();
|
||||
let dt = NaiveDateTime::new(date, time);
|
||||
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [dt])?;
|
||||
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", s);
|
||||
@ -226,7 +226,7 @@ mod test {
|
||||
let dt = NaiveDateTime::new(date, time);
|
||||
let utc = Utc.from_utc_datetime(&dt);
|
||||
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [utc])?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?1)", [utc])?;
|
||||
|
||||
let s: String = db.one_column("SELECT t FROM foo")?;
|
||||
assert_eq!("2016-02-23 23:56:04.789+00:00", s);
|
||||
@ -253,7 +253,7 @@ mod test {
|
||||
let dt = NaiveDateTime::new(date, time);
|
||||
let local = Local.from_local_datetime(&dt).single().unwrap();
|
||||
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [local])?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?1)", [local])?;
|
||||
|
||||
// Stored string should be in UTC
|
||||
let s: String = db.one_column("SELECT t FROM foo")?;
|
||||
@ -269,7 +269,7 @@ mod test {
|
||||
let db = checked_memory_handle()?;
|
||||
let time = DateTime::parse_from_rfc3339("2020-04-07T11:23:45+04:00").unwrap();
|
||||
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [time])?;
|
||||
db.execute("INSERT INTO foo (t) VALUES (?1)", [time])?;
|
||||
|
||||
// Stored string should preserve timezone offset
|
||||
let s: String = db.one_column("SELECT t FROM foo")?;
|
||||
@ -298,7 +298,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_naive_date_time_param() -> Result<()> {
|
||||
let db = checked_memory_handle()?;
|
||||
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [Utc::now().naive_utc()], |r| r.get(0));
|
||||
let result: Result<bool> = db.query_row("SELECT 1 WHERE ?1 BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [Utc::now().naive_utc()], |r| r.get(0));
|
||||
result.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
@ -306,7 +306,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_date_time_param() -> Result<()> {
|
||||
let db = checked_memory_handle()?;
|
||||
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [Utc::now()], |r| r.get(0));
|
||||
let result: Result<bool> = db.query_row("SELECT 1 WHERE ?1 BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [Utc::now()], |r| r.get(0));
|
||||
result.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ mod test {
|
||||
{
|
||||
for n in out_of_range {
|
||||
let err = db
|
||||
.query_row("SELECT ?", [n], |r| r.get::<_, T>(0))
|
||||
.query_row("SELECT ?1", [n], |r| r.get::<_, T>(0))
|
||||
.unwrap_err();
|
||||
match err {
|
||||
Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
|
||||
@ -254,7 +254,7 @@ mod test {
|
||||
for n in in_range {
|
||||
assert_eq!(
|
||||
*n,
|
||||
db.query_row("SELECT ?", [n], |r| r.get::<_, T>(0))
|
||||
db.query_row("SELECT ?1", [n], |r| r.get::<_, T>(0))
|
||||
.unwrap()
|
||||
.into()
|
||||
);
|
||||
|
@ -102,7 +102,7 @@ mod value_ref;
|
||||
/// # use rusqlite::types::{Null};
|
||||
///
|
||||
/// fn insert_null(conn: &Connection) -> Result<usize> {
|
||||
/// conn.execute("INSERT INTO people (name) VALUES (?)", [Null])
|
||||
/// conn.execute("INSERT INTO people (name) VALUES (?1)", [Null])
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Copy, Clone)]
|
||||
@ -153,7 +153,7 @@ mod test {
|
||||
let db = checked_memory_handle()?;
|
||||
|
||||
let v1234 = vec![1u8, 2, 3, 4];
|
||||
db.execute("INSERT INTO foo(b) VALUES (?)", [&v1234])?;
|
||||
db.execute("INSERT INTO foo(b) VALUES (?1)", [&v1234])?;
|
||||
|
||||
let v: Vec<u8> = db.one_column("SELECT b FROM foo")?;
|
||||
assert_eq!(v, v1234);
|
||||
@ -165,7 +165,7 @@ mod test {
|
||||
let db = checked_memory_handle()?;
|
||||
|
||||
let empty = vec![];
|
||||
db.execute("INSERT INTO foo(b) VALUES (?)", [&empty])?;
|
||||
db.execute("INSERT INTO foo(b) VALUES (?1)", [&empty])?;
|
||||
|
||||
let v: Vec<u8> = db.one_column("SELECT b FROM foo")?;
|
||||
assert_eq!(v, empty);
|
||||
@ -177,7 +177,7 @@ mod test {
|
||||
let db = checked_memory_handle()?;
|
||||
|
||||
let s = "hello, world!";
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", [&s])?;
|
||||
db.execute("INSERT INTO foo(t) VALUES (?1)", [&s])?;
|
||||
|
||||
let from: String = db.one_column("SELECT t FROM foo")?;
|
||||
assert_eq!(from, s);
|
||||
@ -189,7 +189,7 @@ mod test {
|
||||
let db = checked_memory_handle()?;
|
||||
|
||||
let s = "hello, world!";
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", [s.to_owned()])?;
|
||||
db.execute("INSERT INTO foo(t) VALUES (?1)", [s.to_owned()])?;
|
||||
|
||||
let from: String = db.one_column("SELECT t FROM foo")?;
|
||||
assert_eq!(from, s);
|
||||
@ -200,7 +200,7 @@ mod test {
|
||||
fn test_value() -> Result<()> {
|
||||
let db = checked_memory_handle()?;
|
||||
|
||||
db.execute("INSERT INTO foo(i) VALUES (?)", [Value::Integer(10)])?;
|
||||
db.execute("INSERT INTO foo(i) VALUES (?1)", [Value::Integer(10)])?;
|
||||
|
||||
assert_eq!(10i64, db.one_column::<i64>("SELECT i FROM foo")?);
|
||||
Ok(())
|
||||
@ -213,8 +213,8 @@ mod test {
|
||||
let s = Some("hello, world!");
|
||||
let b = Some(vec![1u8, 2, 3, 4]);
|
||||
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", [&s])?;
|
||||
db.execute("INSERT INTO foo(b) VALUES (?)", [&b])?;
|
||||
db.execute("INSERT INTO foo(t) VALUES (?1)", [&s])?;
|
||||
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 rows = stmt.query([])?;
|
||||
|
@ -1,24 +1,62 @@
|
||||
//! [`ToSql`] and [`FromSql`] implementation for JSON `Value`.
|
||||
|
||||
use serde_json::Value;
|
||||
use serde_json::{Number, Value};
|
||||
|
||||
use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
use crate::Result;
|
||||
use crate::{Error, Result};
|
||||
|
||||
/// Serialize JSON `Value` to text.
|
||||
/// Serialize JSON `Value` to text:
|
||||
///
|
||||
///
|
||||
/// | JSON | SQLite |
|
||||
/// |----------|---------|
|
||||
/// | Null | NULL |
|
||||
/// | Bool | 'true' / 'false' |
|
||||
/// | Number | INT or REAL except u64 |
|
||||
/// | _ | TEXT |
|
||||
impl ToSql for Value {
|
||||
#[inline]
|
||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||
Ok(ToSqlOutput::from(serde_json::to_string(self).unwrap()))
|
||||
match self {
|
||||
Value::Null => Ok(ToSqlOutput::Borrowed(ValueRef::Null)),
|
||||
Value::Number(n) if n.is_i64() => Ok(ToSqlOutput::from(n.as_i64().unwrap())),
|
||||
Value::Number(n) if n.is_f64() => Ok(ToSqlOutput::from(n.as_f64().unwrap())),
|
||||
_ => serde_json::to_string(self)
|
||||
.map(ToSqlOutput::from)
|
||||
.map_err(|err| Error::ToSqlConversionFailure(err.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize text/blob to JSON `Value`.
|
||||
/// Deserialize SQLite value to JSON `Value`:
|
||||
///
|
||||
/// | SQLite | JSON |
|
||||
/// |----------|---------|
|
||||
/// | NULL | Null |
|
||||
/// | 'null' | Null |
|
||||
/// | 'true' | Bool |
|
||||
/// | 1 | Number |
|
||||
/// | 0.1 | Number |
|
||||
/// | '"text"' | String |
|
||||
/// | 'text' | _Error_ |
|
||||
/// | '[0, 1]' | Array |
|
||||
/// | '{"x": 1}' | Object |
|
||||
impl FromSql for Value {
|
||||
#[inline]
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
let bytes = value.as_bytes()?;
|
||||
serde_json::from_slice(bytes).map_err(|err| FromSqlError::Other(Box::new(err)))
|
||||
match value {
|
||||
ValueRef::Text(s) => serde_json::from_slice(s), // KO for b"text"
|
||||
ValueRef::Blob(b) => serde_json::from_slice(b),
|
||||
ValueRef::Integer(i) => Ok(Value::Number(Number::from(i))),
|
||||
ValueRef::Real(f) => {
|
||||
match Number::from_f64(f) {
|
||||
Some(n) => Ok(Value::Number(n)),
|
||||
_ => return Err(FromSqlError::InvalidType), // FIXME
|
||||
}
|
||||
}
|
||||
ValueRef::Null => Ok(Value::Null),
|
||||
}
|
||||
.map_err(|err| FromSqlError::Other(Box::new(err)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +64,7 @@ impl FromSql for Value {
|
||||
mod test {
|
||||
use crate::types::ToSql;
|
||||
use crate::{Connection, Result};
|
||||
use serde_json::Value;
|
||||
use serde_json::{Number, Value};
|
||||
|
||||
fn checked_memory_handle() -> Result<Connection> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
@ -41,7 +79,7 @@ mod test {
|
||||
let json = r#"{"foo": 13, "bar": "baz"}"#;
|
||||
let data: Value = serde_json::from_str(json).unwrap();
|
||||
db.execute(
|
||||
"INSERT INTO foo (t, b) VALUES (?, ?)",
|
||||
"INSERT INTO foo (t, b) VALUES (?1, ?2)",
|
||||
[&data as &dyn ToSql, &json.as_bytes()],
|
||||
)?;
|
||||
|
||||
@ -51,4 +89,47 @@ mod test {
|
||||
assert_eq!(data, b);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_sql() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
|
||||
let v: Option<String> = db.query_row("SELECT ?", [Value::Null], |r| r.get(0))?;
|
||||
assert_eq!(None, v);
|
||||
let v: String = db.query_row("SELECT ?", [Value::Bool(true)], |r| r.get(0))?;
|
||||
assert_eq!("true", v);
|
||||
let v: i64 = db.query_row("SELECT ?", [Value::Number(Number::from(1))], |r| r.get(0))?;
|
||||
assert_eq!(1, v);
|
||||
let v: f64 = db.query_row(
|
||||
"SELECT ?",
|
||||
[Value::Number(Number::from_f64(0.1).unwrap())],
|
||||
|r| r.get(0),
|
||||
)?;
|
||||
assert_eq!(0.1, v);
|
||||
let v: String =
|
||||
db.query_row("SELECT ?", [Value::String("text".to_owned())], |r| r.get(0))?;
|
||||
assert_eq!("\"text\"", v);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_sql() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
|
||||
let v: Value = db.one_column("SELECT NULL")?;
|
||||
assert_eq!(Value::Null, v);
|
||||
let v: Value = db.one_column("SELECT 'null'")?;
|
||||
assert_eq!(Value::Null, v);
|
||||
let v: Value = db.one_column("SELECT 'true'")?;
|
||||
assert_eq!(Value::Bool(true), v);
|
||||
let v: Value = db.one_column("SELECT 1")?;
|
||||
assert_eq!(Value::Number(Number::from(1)), v);
|
||||
let v: Value = db.one_column("SELECT 0.1")?;
|
||||
assert_eq!(Value::Number(Number::from_f64(0.1).unwrap()), v);
|
||||
let v: Value = db.one_column("SELECT '\"text\"'")?;
|
||||
assert_eq!(Value::String("text".to_owned()), v);
|
||||
let v: Result<Value> = db.one_column("SELECT 'text'");
|
||||
assert!(v.is_err());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ mod test {
|
||||
ts_vec.push(make_datetime(10_000_000_000, 0)); //November 20, 2286
|
||||
|
||||
for ts in ts_vec {
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", [ts])?;
|
||||
db.execute("INSERT INTO foo(t) VALUES (?1)", [ts])?;
|
||||
|
||||
let from: OffsetDateTime = db.one_column("SELECT t FROM foo")?;
|
||||
|
||||
@ -143,7 +143,7 @@ mod test {
|
||||
Ok(OffsetDateTime::parse("2013-10-07T04:23:19.120-04:00", &Rfc3339).unwrap()),
|
||||
),
|
||||
] {
|
||||
let result: Result<OffsetDateTime> = db.query_row("SELECT ?", [s], |r| r.get(0));
|
||||
let result: Result<OffsetDateTime> = db.query_row("SELECT ?1", [s], |r| r.get(0));
|
||||
assert_eq!(result, t);
|
||||
}
|
||||
Ok(())
|
||||
@ -160,7 +160,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_param() -> Result<()> {
|
||||
let db = Connection::open_in_memory()?;
|
||||
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [OffsetDateTime::now_utc()], |r| r.get(0));
|
||||
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();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -368,10 +368,10 @@ mod test {
|
||||
db.execute(
|
||||
"
|
||||
INSERT INTO foo(i128, desc) VALUES
|
||||
(?, 'zero'),
|
||||
(?, 'neg one'), (?, 'neg two'),
|
||||
(?, 'pos one'), (?, 'pos two'),
|
||||
(?, 'min'), (?, 'max')",
|
||||
(?1, 'zero'),
|
||||
(?2, 'neg one'), (?3, 'neg two'),
|
||||
(?4, 'pos one'), (?5, 'pos two'),
|
||||
(?6, 'min'), (?7, 'max')",
|
||||
[0i128, -1i128, -2i128, 1i128, 2i128, i128::MIN, i128::MAX],
|
||||
)?;
|
||||
|
||||
@ -410,11 +410,11 @@ mod test {
|
||||
let id = Uuid::new_v4();
|
||||
|
||||
db.execute(
|
||||
"INSERT INTO foo (id, label) VALUES (?, ?)",
|
||||
"INSERT INTO foo (id, label) VALUES (?1, ?2)",
|
||||
params![id, "target"],
|
||||
)?;
|
||||
|
||||
let mut stmt = db.prepare("SELECT id, label FROM foo WHERE id = ?")?;
|
||||
let mut stmt = db.prepare("SELECT id, label FROM foo WHERE id = ?1")?;
|
||||
|
||||
let mut rows = stmt.query(params![id])?;
|
||||
let row = rows.next()?.unwrap();
|
||||
|
@ -49,7 +49,7 @@ mod test {
|
||||
let url2 = "http://www.example2.com/👌";
|
||||
|
||||
db.execute(
|
||||
"INSERT INTO urls (i, v) VALUES (0, ?), (1, ?), (2, ?), (3, ?)",
|
||||
"INSERT INTO urls (i, v) VALUES (0, ?1), (1, ?2), (2, ?3), (3, ?4)",
|
||||
// also insert a non-hex encoded url (which might be present if it was
|
||||
// inserted separately)
|
||||
params![url0, url1, url2, "illegal"],
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! let v = [1i64, 2, 3, 4];
|
||||
//! // Note: A `Rc<Vec<Value>>` must be used as the parameter.
|
||||
//! let values = Rc::new(v.iter().copied().map(Value::from).collect::<Vec<Value>>());
|
||||
//! let mut stmt = db.prepare("SELECT value from rarray(?);")?;
|
||||
//! let mut stmt = db.prepare("SELECT value from rarray(?1);")?;
|
||||
//! let rows = stmt.query_map([values], |row| row.get::<_, i64>(0))?;
|
||||
//! for value in rows {
|
||||
//! println!("{}", value?);
|
||||
@ -206,7 +206,7 @@ mod test {
|
||||
let values: Vec<Value> = v.into_iter().map(Value::from).collect();
|
||||
let ptr = Rc::new(values);
|
||||
{
|
||||
let mut stmt = db.prepare("SELECT value from rarray(?);")?;
|
||||
let mut stmt = db.prepare("SELECT value from rarray(?1);")?;
|
||||
|
||||
let rows = stmt.query_map([&ptr], |row| row.get::<_, i64>(0))?;
|
||||
assert_eq!(2, Rc::strong_count(&ptr));
|
||||
|
@ -619,7 +619,7 @@ impl IndexConstraintUsage<'_> {
|
||||
|
||||
/// `feature = "vtab"`
|
||||
pub struct OrderByIter<'a> {
|
||||
iter: slice::Iter<'a, ffi::sqlite3_index_info_sqlite3_index_orderby>,
|
||||
iter: slice::Iter<'a, ffi::sqlite3_index_orderby>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for OrderByIter<'a> {
|
||||
@ -637,7 +637,7 @@ impl<'a> Iterator for OrderByIter<'a> {
|
||||
}
|
||||
|
||||
/// A column of the ORDER BY clause.
|
||||
pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
|
||||
pub struct OrderBy<'a>(&'a ffi::sqlite3_index_orderby);
|
||||
|
||||
impl OrderBy<'_> {
|
||||
/// Column number
|
||||
|
@ -28,6 +28,7 @@ const SERIES_COLUMN_STOP: c_int = 2;
|
||||
const SERIES_COLUMN_STEP: c_int = 3;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct QueryPlanFlags: ::std::os::raw::c_int {
|
||||
// start = $value -- constraint exists
|
||||
@ -41,7 +42,7 @@ bitflags::bitflags! {
|
||||
// output in ascending order
|
||||
const ASC = 16;
|
||||
// Both start and stop
|
||||
const BOTH = QueryPlanFlags::START.bits | QueryPlanFlags::STOP.bits;
|
||||
const BOTH = QueryPlanFlags::START.bits() | QueryPlanFlags::STOP.bits();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,13 +286,13 @@ mod test {
|
||||
let mut stmt = db.prepare("SELECT * FROM log;")?;
|
||||
let mut rows = stmt.query([])?;
|
||||
while rows.next()?.is_some() {}
|
||||
db.execute("DELETE FROM log WHERE a = ?", ["a1"])?;
|
||||
db.execute("DELETE FROM log WHERE a = ?1", ["a1"])?;
|
||||
db.execute(
|
||||
"INSERT INTO log (a, b, c) VALUES (?, ?, ?)",
|
||||
"INSERT INTO log (a, b, c) VALUES (?1, ?2, ?3)",
|
||||
["a", "b", "c"],
|
||||
)?;
|
||||
db.execute(
|
||||
"UPDATE log SET b = ?, c = ? WHERE a = ?",
|
||||
"UPDATE log SET b = ?1, c = ?2 WHERE a = ?3",
|
||||
["bn", "cn", "a1"],
|
||||
)?;
|
||||
Ok(())
|
||||
|
Loading…
Reference in New Issue
Block a user