Bug 1958063 - build(rust): shim-upgrade rusqlite 0.31.0 → 0.33.0 r=glandium

Do this by upgrading `application-services` repos to a commit that
_only_ differs from the current one in its `rusqlite` dependency.

Differential Revision: https://phabricator.services.mozilla.com/D244233
This commit is contained in:
Erich Gubler
2025-04-16 16:25:17 +00:00
parent b30b2aa3e1
commit 8221b15491
104 changed files with 46667 additions and 24322 deletions

View File

@@ -70,9 +70,9 @@ git = "https://github.com/jfkthame/mapped_hyph.git"
rev = "eff105f6ad7ec9b79816cfc1985a28e5340ad14b" rev = "eff105f6ad7ec9b79816cfc1985a28e5340ad14b"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94"] [source."git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499"]
git = "https://github.com/mozilla/application-services" git = "https://github.com/mozilla/application-services"
rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" rev = "e18923d336cb3e17e3d411c2a943631a3691c499"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/audioipc?rev=e6f44a2bd1e57d11dfc737632a9e849077632330"] [source."git+https://github.com/mozilla/audioipc?rev=e6f44a2bd1e57d11dfc737632a9e849077632330"]

86
Cargo.lock generated
View File

@@ -1792,7 +1792,7 @@ dependencies = [
[[package]] [[package]]
name = "error-support" name = "error-support"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"error-support-macros", "error-support-macros",
"lazy_static", "lazy_static",
@@ -1804,7 +1804,7 @@ dependencies = [
[[package]] [[package]]
name = "error-support-macros" name = "error-support-macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1921,7 +1921,7 @@ dependencies = [
[[package]] [[package]]
name = "firefox-versioning" name = "firefox-versioning"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"serde_json", "serde_json",
"thiserror 1.999.999", "thiserror 1.999.999",
@@ -2501,7 +2501,7 @@ dependencies = [
"qcms", "qcms",
"rsdparsa_capi", "rsdparsa_capi",
"rure", "rure",
"rusqlite", "rusqlite 0.33.0",
"rust_minidump_writer_linux", "rust_minidump_writer_linux",
"signature_cache", "signature_cache",
"static_prefs", "static_prefs",
@@ -2826,13 +2826,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "hashlink"
version = "0.9.999"
dependencies = [
"hashlink 0.10.0",
]
[[package]] [[package]]
name = "hashlink" name = "hashlink"
version = "0.10.0" version = "0.10.0"
@@ -3240,11 +3233,11 @@ dependencies = [
[[package]] [[package]]
name = "interrupt-support" name = "interrupt-support"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"parking_lot", "parking_lot",
"rusqlite", "rusqlite 0.33.0",
"uniffi", "uniffi",
] ]
@@ -3430,7 +3423,7 @@ dependencies = [
"nserror", "nserror",
"nsstring", "nsstring",
"rkv", "rkv",
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
"serde_json", "serde_json",
"storage_variant", "storage_variant",
@@ -3446,7 +3439,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"kvstore", "kvstore",
"moz_task", "moz_task",
"rusqlite", "rusqlite 0.33.0",
"tempfile", "tempfile",
] ]
@@ -3569,9 +3562,9 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.28.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" checksum = "ad8935b44e7c13394a179a438e0cebba0fe08fe01b54f152e29a93b5cf993fd4"
dependencies = [ dependencies = [
"cc", "cc",
"pkg-config", "pkg-config",
@@ -4211,7 +4204,7 @@ dependencies = [
"maybe-async", "maybe-async",
"mls-rs-core", "mls-rs-core",
"rand", "rand",
"rusqlite", "rusqlite 0.31.999",
"thiserror 1.999.999", "thiserror 1.999.999",
"zeroize", "zeroize",
] ]
@@ -4226,7 +4219,7 @@ dependencies = [
"nserror", "nserror",
"nss-gk-api", "nss-gk-api",
"nsstring", "nsstring",
"rusqlite", "rusqlite 0.33.0",
"static_prefs", "static_prefs",
"thin-vec", "thin-vec",
"xpcom", "xpcom",
@@ -4953,7 +4946,7 @@ checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
[[package]] [[package]]
name = "payload-support" name = "payload-support"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
@@ -5456,7 +5449,7 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]] [[package]]
name = "relevancy" name = "relevancy"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.21.999", "base64 0.21.999",
@@ -5468,7 +5461,7 @@ dependencies = [
"rand", "rand",
"rand_distr", "rand_distr",
"remote_settings", "remote_settings",
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
"serde_json", "serde_json",
"serde_path_to_error", "serde_path_to_error",
@@ -5481,7 +5474,7 @@ dependencies = [
[[package]] [[package]]
name = "remote_settings" name = "remote_settings"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
@@ -5491,7 +5484,7 @@ dependencies = [
"log", "log",
"parking_lot", "parking_lot",
"regex", "regex",
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
@@ -5658,14 +5651,21 @@ dependencies = [
[[package]] [[package]]
name = "rusqlite" name = "rusqlite"
version = "0.31.0" version = "0.31.999"
dependencies = [
"rusqlite 0.33.0",
]
[[package]]
name = "rusqlite"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" checksum = "1c6d5e5acb6f6129fe3f7ba0a7fc77bca1942cb568535e18e7bc40262baf3110"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"fallible-iterator", "fallible-iterator",
"fallible-streaming-iterator", "fallible-streaming-iterator",
"hashlink 0.9.999", "hashlink",
"libsqlite3-sys", "libsqlite3-sys",
"serde_json", "serde_json",
"smallvec", "smallvec",
@@ -5812,7 +5812,7 @@ dependencies = [
[[package]] [[package]]
name = "search" name = "search"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"error-support", "error-support",
"firefox-versioning", "firefox-versioning",
@@ -6024,7 +6024,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
name = "signature_cache" name = "signature_cache"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"hashlink 0.10.0", "hashlink",
] ]
[[package]] [[package]]
@@ -6103,13 +6103,13 @@ dependencies = [
[[package]] [[package]]
name = "sql-support" name = "sql-support"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"interrupt-support", "interrupt-support",
"lazy_static", "lazy_static",
"log", "log",
"parking_lot", "parking_lot",
"rusqlite", "rusqlite 0.33.0",
"tempfile", "tempfile",
"thiserror 1.999.999", "thiserror 1.999.999",
] ]
@@ -6302,7 +6302,7 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]] [[package]]
name = "suggest" name = "suggest"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@@ -6314,7 +6314,7 @@ dependencies = [
"parking_lot", "parking_lot",
"remote_settings", "remote_settings",
"rmp-serde", "rmp-serde",
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
"serde_json", "serde_json",
"sql-support", "sql-support",
@@ -6354,18 +6354,18 @@ dependencies = [
[[package]] [[package]]
name = "sync-guid" name = "sync-guid"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"base64 0.21.999", "base64 0.21.999",
"rand", "rand",
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
] ]
[[package]] [[package]]
name = "sync15" name = "sync15"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"error-support", "error-support",
@@ -6405,7 +6405,7 @@ dependencies = [
[[package]] [[package]]
name = "tabs" name = "tabs"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"error-support", "error-support",
@@ -6413,7 +6413,7 @@ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
"payload-support", "payload-support",
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@@ -6749,9 +6749,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]] [[package]]
name = "types" name = "types"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@@ -7131,7 +7131,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "viaduct" name = "viaduct"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"ffi-support", "ffi-support",
"log", "log",
@@ -7301,7 +7301,7 @@ dependencies = [
[[package]] [[package]]
name = "webext-storage" name = "webext-storage"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=8e84c588a5cc2686973c5026ecd240d6275d7e94#8e84c588a5cc2686973c5026ecd240d6275d7e94" source = "git+https://github.com/mozilla/application-services?rev=e18923d336cb3e17e3d411c2a943631a3691c499#e18923d336cb3e17e3d411c2a943631a3691c499"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"error-support", "error-support",
@@ -7310,7 +7310,7 @@ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
"parking_lot", "parking_lot",
"rusqlite", "rusqlite 0.33.0",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",

View File

@@ -65,7 +65,7 @@ rust-version = "1.82.0"
uniffi = "0.29.1" uniffi = "0.29.1"
uniffi_bindgen = "0.29.1" uniffi_bindgen = "0.29.1"
# Shared across multiple application-services consumers. # Shared across multiple application-services consumers.
rusqlite = "0.31.0" rusqlite = "0.33.0"
# Shared across multiple glean consumers. # Shared across multiple glean consumers.
glean = "=64.0.1" glean = "=64.0.1"
@@ -204,13 +204,15 @@ web-sys = { path = "build/rust/dummy-web/web-sys" }
# Upgrade `core-foundation` 0.9.* to 0.10. # Upgrade `core-foundation` 0.9.* to 0.10.
core-foundation = { path = "build/rust/core-foundation" } core-foundation = { path = "build/rust/core-foundation" }
# Patch `core-graphics-types` 0.1.* to 0.2. # Patch `core-graphics-types` 0.1.* to 0.2.
core-graphics-types = { path = "build/rust/core-graphics-types" } core-graphics-types = { path = "build/rust/core-graphics-types" }
# Patch `half` 1.* to 2. # Patch `half` 1.* to 2.
half = { path = "build/rust/half" } half = { path = "build/rust/half" }
# Upgrade `rusqlite` 0.31 to 0.33.
rusqlite = { path = "build/rust/rusqlite" }
# Overrides to allow easier use of common internal crates. # Overrides to allow easier use of common internal crates.
moz_asserts = { path = "mozglue/static/rust/moz_asserts" } moz_asserts = { path = "mozglue/static/rust/moz_asserts" }
@@ -227,9 +229,6 @@ plist = { path = "third_party/rust/plist" }
# Patch `unicode-width` 0.1.* to 0.2. # Patch `unicode-width` 0.1.* to 0.2.
unicode-width = { path = "build/rust/unicode-width" } unicode-width = { path = "build/rust/unicode-width" }
# Patch `hashlink` 0.9.* to 0.10.
hashlink = { path = "build/rust/hashlink" }
# To-be-published changes. # To-be-published changes.
unicode-bidi = { git = "https://github.com/servo/unicode-bidi", rev = "ca612daf1c08c53abe07327cb3e6ef6e0a760f0c" } unicode-bidi = { git = "https://github.com/servo/unicode-bidi", rev = "ca612daf1c08c53abe07327cb3e6ef6e0a760f0c" }
nss-gk-api = { git = "https://github.com/beurdouche/nss-gk-api", rev = "e48a946811ffd64abc78de3ee284957d8d1c0d63" } nss-gk-api = { git = "https://github.com/beurdouche/nss-gk-api", rev = "e48a946811ffd64abc78de3ee284957d8d1c0d63" }
@@ -254,14 +253,14 @@ malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" }
objc = { git = "https://github.com/glandium/rust-objc", rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" } objc = { git = "https://github.com/glandium/rust-objc", rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" }
# application-services overrides to make updating them all simpler. # application-services overrides to make updating them all simpler.
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
relevancy = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } relevancy = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
search = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } search = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
sql-support = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } sql-support = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
suggest = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } suggest = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
sync15 = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } sync15 = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
tabs = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } tabs = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
viaduct = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } viaduct = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
webext-storage = { git = "https://github.com/mozilla/application-services", rev = "8e84c588a5cc2686973c5026ecd240d6275d7e94" } webext-storage = { git = "https://github.com/mozilla/application-services", rev = "e18923d336cb3e17e3d411c2a943631a3691c499" }
allocator-api2 = { path = "third_party/rust/allocator-api2" } allocator-api2 = { path = "third_party/rust/allocator-api2" }

View File

@@ -1,15 +0,0 @@
[package]
name = "hashlink"
version = "0.9.999"
edition = "2021"
[lib]
path = "lib.rs"
[features]
serde = ["hashlink/serde"]
serde_impl = ["hashlink/serde_impl"]
[dependencies.hashlink]
version = "0.10.0"
default-features = false

View File

@@ -0,0 +1,22 @@
[package]
name = "rusqlite"
version = "0.31.999"
edition = "2021"
license = "MPL-2.0"
[lib]
path = "lib.rs"
[dependencies.rusqlite]
version = "0.33"
[features]
bundled = ["rusqlite/bundled"]
bundled-sqlcipher = ["rusqlite/bundled-sqlcipher"]
functions = ["rusqlite/functions"]
in_gecko = ["rusqlite/in_gecko"]
limits = ["rusqlite/limits"]
load_extension = ["rusqlite/load_extension"]
modern_sqlite = ["rusqlite/modern_sqlite"]
serde_json = ["rusqlite/serde_json"]
unlock_notify = ["rusqlite/unlock_notify"]

View File

@@ -1,4 +1,5 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pub use hashlink::*;
pub use rusqlite::*;

View File

@@ -16,5 +16,5 @@ mls-platform-api = { git = "https://github.com/beurdouche/mls-platform-api", rev
nss-gk-api = { git = "https://github.com/beurdouche/nss-gk-api", rev = "e48a946811ffd64abc78de3ee284957d8d1c0d63", default-features = false } nss-gk-api = { git = "https://github.com/beurdouche/nss-gk-api", rev = "e48a946811ffd64abc78de3ee284957d8d1c0d63", default-features = false }
thin-vec = { version = "^0.2.12", features = ["gecko-ffi"] } thin-vec = { version = "^0.2.12", features = ["gecko-ffi"] }
hex = "^0.4.3" hex = "^0.4.3"
rusqlite = "^0.31.0" rusqlite = "^0.33.0"
log = "^0.4.20" log = "^0.4.20"

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"f86577c4ceee8cab07cc66a2305629708c0bdf2d3e023ffc4b55344148b1817b","README.md":"7f1418b4a7c138ba20bcaea077fe6cf0d6ffbaf6df6b90c80efc52aa0d0e2e9f","build.rs":"49840f26c73c5db19cb4e7f02930e49d7a19648168b83f2313ac1a0303c103df","src/error.rs":"b83cbe8abd22a9d687508d236a2a77e28b3fc6c39673633e5820cc0e3fc86cba","src/interrupt_support.udl":"bac2d5a94b5ae5d1b819b2058b82c541e02b1f75ef157c1eb236bfb4f0c78a05","src/interruptee.rs":"c56f9ac610d0b24a128a907266432287558c4b73f6c24b82674ca7894181d18f","src/lib.rs":"cf44a84310913be5264e1c4a3e004a9f7a6cd82d01a109bb6ac4d6002b5dd560","src/shutdown.rs":"e4b7a89f1ef319646aee3282a0d60465c3dbf571c52a0295f3b1a8909f345818","src/sql.rs":"db9b93fb2fe813ae0af6313082f07fad0e381691290466a7ac67bec14024722d"},"package":null} {"files":{"Cargo.toml":"e2ccc2e0c9342740cc28ff33d328b2ccdb7f20fd7d98e2693680b18950296ed4","README.md":"7f1418b4a7c138ba20bcaea077fe6cf0d6ffbaf6df6b90c80efc52aa0d0e2e9f","build.rs":"49840f26c73c5db19cb4e7f02930e49d7a19648168b83f2313ac1a0303c103df","src/error.rs":"b83cbe8abd22a9d687508d236a2a77e28b3fc6c39673633e5820cc0e3fc86cba","src/interrupt_support.udl":"bac2d5a94b5ae5d1b819b2058b82c541e02b1f75ef157c1eb236bfb4f0c78a05","src/interruptee.rs":"c56f9ac610d0b24a128a907266432287558c4b73f6c24b82674ca7894181d18f","src/lib.rs":"cf44a84310913be5264e1c4a3e004a9f7a6cd82d01a109bb6ac4d6002b5dd560","src/shutdown.rs":"e4b7a89f1ef319646aee3282a0d60465c3dbf571c52a0295f3b1a8909f345818","src/sql.rs":"db9b93fb2fe813ae0af6313082f07fad0e381691290466a7ac67bec14024722d"},"package":null}

View File

@@ -32,7 +32,7 @@ lazy_static = "1.4"
parking_lot = ">=0.11,<=0.12" parking_lot = ">=0.11,<=0.12"
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = [ features = [
"functions", "functions",
"limits", "limits",

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"70d74c9e4358952e69e2d5d4b7e948dc39139ee70c6d9d0cb8baa7be8e7c5abf","LICENSE":"f59ba65550f2a5adff98ec6478d783402c8e0a3eb515025c0b3438f3d30dc39e","README.md":"6f31c834d526983cefa4d762430262eba52c45419751bd8a6cca9d943fd3eac9","Upgrade.md":"d151a67d4bbb1a5a300d084d210d6cd238d833a6d4bd5d958ae7469a9deccb36","bindgen-bindings/bindgen_3.14.0.rs":"21074ddbc5ef6bb7fb7c04ef48c730a2b074b9d695c93c685cf01f870248844b","bindgen-bindings/bindgen_3.14.0_ext.rs":"2988b5f0670d7862166d3820b8a176d3da329b6105567e66e45aafb17d736fa6","build.rs":"a3a0c7f409e20573d21448fb53c5a1f168fd04c5983af68671da126cc3bf9ff4","sqlcipher/LICENSE":"ea4fcb309f14a22065e1ea45362d494d320012249ed865fe9c7c0946db754131","sqlcipher/bindgen_bundled_version.rs":"b90cdb889a74ce82af24a78932979c59df4d9dbb31228d05e6574a2fd852d0ba","sqlcipher/sqlite3.c":"2dc94cbc5f013078ad7e48b65fe1c63cb79b4d25aba9ccaef1699724ae6640f7","sqlcipher/sqlite3.h":"46bf1085dbe8063fe002f667a4ff9cf953ae7896d2893cdfb7be47260b2489cd","sqlcipher/sqlite3ext.h":"7f9ae3bab94bbc62d909fbb0149861b4a0832299f12d7ccbfecc7f28a8d27aa2","sqlite3/bindgen_bundled_version.rs":"3dda83bd41376847eb3e0fd9e4aa645e6f5b48ebdc5227df051c044ebdce177a","sqlite3/bindgen_bundled_version_ext.rs":"73b54ea41acf310e13555ec925d5eaee6443d0787e6b1e4310f83647967a1a04","sqlite3/sqlite3.c":"7956a38f236a6be6c0bb30c96ba4f85f19e5a69f6beb6d2c62c9d246972a6775","sqlite3/sqlite3.h":"0c207567adc631521a353e067cfbc5044ebf11868f3c3fbf3178d6990409740e","sqlite3/sqlite3ext.h":"b184dd1586d935133d37ad76fa353faf0a1021ff2fdedeedcc3498fff74bbb94","sqlite3/wasm32-wasi-vfs.c":"b95842044da2b8777876b7d3fef8c9711e8c201fb4a4255dbac98729a456bb5d","src/error.rs":"73ce88d90e3d5a99fc4fdc146fe5405e7d9cdcc5334eb4f0f53e0919c9b19c05","src/lib.rs":"9a415d321a3094ad2b69c40b757fe82b37cc65585f7a41d8a075b6ca5735feea","upgrade.sh":"87498d63d69bb84f04b5b5ca94af03b6c1e6786bee4b28b99b2fb95e489ec74b","upgrade_sqlcipher.sh":"0372ba89bb41427c2c2010a3d41f1363d77eb73bbfecc2fde20aae8499a42a21","wrapper.h":"b78f576f7eeabf316e183d476b0f16344b6897680b4df47628d3ce38c0aa979a","wrapper_ext.h":"fa7a53fea99318ee29d75e6d5fab4d7ed26e9599803268e6a24396265f2a6f3a"},"package":"0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f"} {"files":{"Cargo.lock":"975c5e4f30f92f3638eca27fe5126c32fe78f1d0e557023c2e4fab621a031378","Cargo.toml":"731e3cdf7d5f449261bc268d8fb25657b4917765852987de834b7cd57be128e5","LICENSE":"f59ba65550f2a5adff98ec6478d783402c8e0a3eb515025c0b3438f3d30dc39e","README.md":"3586aa2cf1a91cee6b2b8d005d1d66e2ee9f0e12cd125f15f2d4abe18d44cb46","Upgrade.md":"d151a67d4bbb1a5a300d084d210d6cd238d833a6d4bd5d958ae7469a9deccb36","bindgen-bindings/bindgen_3.14.0.rs":"8e353165d424514aaf979cddbc8c05f779948900ae1b90f34e2b12114521452e","bindgen-bindings/bindgen_3.14.0_ext.rs":"cbc03ec6295b8186265baca6c5cc6b1337a0368c27f46d03a1cff24f2bb079df","build.rs":"4afa423cffce00d5812a526a14dca482db2f517deb6a4d5cdc1907a212e7e271","sqlcipher/LICENSE":"ea4fcb309f14a22065e1ea45362d494d320012249ed865fe9c7c0946db754131","sqlcipher/bindgen_bundled_version.rs":"55a5fe42292acbcd753e9c6e1ffbdddf160632fbbb18ccf0f392508bd936ed8e","sqlcipher/sqlite3.c":"f240498b2f20d6876905041417903b7fd837f964ad6c94c04727ef022f386151","sqlcipher/sqlite3.h":"7df828fe118508d543476be6de79633522eb5222ae922cef467a619c5a003a48","sqlcipher/sqlite3ext.h":"b184dd1586d935133d37ad76fa353faf0a1021ff2fdedeedcc3498fff74bbb94","sqlite3/bindgen_bundled_version.rs":"58b7709a2ffc375734b475f1dcca145f07f2f33b708f21be389deb047e0649c2","sqlite3/bindgen_bundled_version_ext.rs":"8bd658cae7a151a25cf49ff86bec24a97a74dd18f32da1e427675d91857829af","sqlite3/sqlite3.c":"5fdc8109b60ea295a2ffe526bcce47812c501db7a41b4b4baeeea921e6f9bfc8","sqlite3/sqlite3.h":"78d2dbfa4ebd6146f26ceb735702685af0e77b83ad3df69e4904786924c6899c","sqlite3/sqlite3ext.h":"b184dd1586d935133d37ad76fa353faf0a1021ff2fdedeedcc3498fff74bbb94","sqlite3/wasm32-wasi-vfs.c":"b95842044da2b8777876b7d3fef8c9711e8c201fb4a4255dbac98729a456bb5d","src/error.rs":"74be652185b6884bb95c0b0347daf326e5323acd81e0d41158d5490e06184993","src/lib.rs":"c554c2afcef26fb107fdb867beb499f670e4aa628b0bcfbdeec709e48fd61157","upgrade.sh":"cf9dedc66cd1679aad9f025a651d809db060f142bfae535eef4972676681fd6d","upgrade_sqlcipher.sh":"4933703942151b2742ddfff25b3ee362ac7e4dd19039382682484d03a6885bd3","wrapper.h":"b78f576f7eeabf316e183d476b0f16344b6897680b4df47628d3ce38c0aa979a","wrapper_ext.h":"fa7a53fea99318ee29d75e6d5fab4d7ed26e9599803268e6a24396265f2a6f3a"},"package":"ad8935b44e7c13394a179a438e0cebba0fe08fe01b54f152e29a93b5cf993fd4"}

328
third_party/rust/libsqlite3-sys/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,328 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "cc"
version = "1.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
dependencies = [
"shlex",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "libsqlite3-sys"
version = "0.31.0"
dependencies = [
"bindgen",
"cc",
"openssl-sys",
"pkg-config",
"prettyplease",
"quote",
"syn",
"vcpkg",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "openssl-src"
version = "300.4.1+3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
dependencies = [
"cc",
"libc",
"openssl-src",
"pkg-config",
"vcpkg",
]
[[package]]
name = "pkg-config"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "prettyplease"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc-hash"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@@ -12,10 +12,15 @@
[package] [package]
edition = "2021" edition = "2021"
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.28.0" version = "0.31.0"
authors = ["The rusqlite developers"] authors = ["The rusqlite developers"]
build = "build.rs" build = "build.rs"
links = "sqlite3" links = "sqlite3"
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Native bindings to the libsqlite3 library" description = "Native bindings to the libsqlite3 library"
readme = "README.md" readme = "README.md"
keywords = [ keywords = [
@@ -27,46 +32,6 @@ categories = ["external-ffi-bindings"]
license = "MIT" license = "MIT"
repository = "https://github.com/rusqlite/rusqlite" repository = "https://github.com/rusqlite/rusqlite"
[dependencies.openssl-sys]
version = "0.9"
optional = true
[build-dependencies.bindgen]
version = "0.69"
features = ["runtime"]
optional = true
default-features = false
[build-dependencies.cc]
version = "1.0"
optional = true
[build-dependencies.pkg-config]
version = "0.3.19"
optional = true
[build-dependencies.prettyplease]
version = "0.2"
optional = true
[build-dependencies.quote]
version = "1"
optional = true
default-features = false
[build-dependencies.syn]
version = "2.0"
features = [
"full",
"extra-traits",
"visit-mut",
]
optional = true
[build-dependencies.vcpkg]
version = "0.2"
optional = true
[features] [features]
buildtime_bindgen = [ buildtime_bindgen = [
"bindgen", "bindgen",
@@ -107,3 +72,47 @@ sqlcipher = []
unlock_notify = [] unlock_notify = []
wasm32-wasi-vfs = [] wasm32-wasi-vfs = []
with-asan = [] with-asan = []
[lib]
name = "libsqlite3_sys"
path = "src/lib.rs"
[dependencies.openssl-sys]
version = "0.9.103"
optional = true
[build-dependencies.bindgen]
version = "0.71"
features = ["runtime"]
optional = true
default-features = false
[build-dependencies.cc]
version = "1.1.6"
optional = true
[build-dependencies.pkg-config]
version = "0.3.19"
optional = true
[build-dependencies.prettyplease]
version = "0.2.20"
optional = true
[build-dependencies.quote]
version = "1.0.36"
optional = true
default-features = false
[build-dependencies.syn]
version = "2.0.72"
features = [
"full",
"extra-traits",
"visit-mut",
]
optional = true
[build-dependencies.vcpkg]
version = "0.2.15"
optional = true

View File

@@ -27,7 +27,7 @@ In your Cargo.toml:
# That said, it's not ideal for all scenarios and in particular, generic # That said, it's not ideal for all scenarios and in particular, generic
# libraries built around `rusqlite` should probably not enable it, which # libraries built around `rusqlite` should probably not enable it, which
# is why it is not a default feature -- it could become hard to disable. # is why it is not a default feature -- it could become hard to disable.
rusqlite = { version = "0.30.0", features = ["bundled"] } rusqlite = { version = "0.33.0", features = ["bundled"] }
``` ```
Simple example usage: Simple example usage:
@@ -94,17 +94,14 @@ features](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-s
allows loading dynamic library-based SQLite extensions. allows loading dynamic library-based SQLite extensions.
* `loadable_extension` to program [loadable extension](https://sqlite.org/loadext.html) in Rust. * `loadable_extension` to program [loadable extension](https://sqlite.org/loadext.html) in Rust.
* [`backup`](https://docs.rs/rusqlite/~0/rusqlite/backup/index.html) * [`backup`](https://docs.rs/rusqlite/~0/rusqlite/backup/index.html)
allows use of SQLite's online backup API. Note: This feature requires SQLite 3.6.11 or later. allows use of SQLite's online backup API.
* [`functions`](https://docs.rs/rusqlite/~0/rusqlite/functions/index.html) * [`functions`](https://docs.rs/rusqlite/~0/rusqlite/functions/index.html)
allows you to load Rust closures into SQLite connections for use in queries. allows you to load Rust closures into SQLite connections for use in queries.
Note: This feature requires SQLite 3.7.3 or later.
* `window` for [window function](https://www.sqlite.org/windowfunctions.html) support (`fun(...) OVER ...`). (Implies `functions`.) * `window` for [window function](https://www.sqlite.org/windowfunctions.html) support (`fun(...) OVER ...`). (Implies `functions`.)
* [`trace`](https://docs.rs/rusqlite/~0/rusqlite/trace/index.html) * [`trace`](https://docs.rs/rusqlite/~0/rusqlite/trace/index.html)
allows hooks into SQLite's tracing and profiling APIs. Note: This feature allows hooks into SQLite's tracing and profiling APIs.
requires SQLite 3.6.23 or later.
* [`blob`](https://docs.rs/rusqlite/~0/rusqlite/blob/index.html) * [`blob`](https://docs.rs/rusqlite/~0/rusqlite/blob/index.html)
gives `std::io::{Read, Write, Seek}` access to SQL BLOBs. Note: This feature gives `std::io::{Read, Write, Seek}` access to SQL BLOBs.
requires SQLite 3.7.4 or later.
* [`limits`](https://docs.rs/rusqlite/~0/rusqlite/struct.Connection.html#method.limit) * [`limits`](https://docs.rs/rusqlite/~0/rusqlite/struct.Connection.html#method.limit)
allows you to set and retrieve SQLite's per connection limits. allows you to set and retrieve SQLite's per connection limits.
* `chrono` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html) * `chrono` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html)
@@ -126,6 +123,7 @@ features](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-s
- As the name implies this depends on the `bundled-sqlcipher` feature, and automatically turns it on. - As the name implies this depends on the `bundled-sqlcipher` feature, and automatically turns it on.
- If turned on, this uses the [`openssl-sys`](https://crates.io/crates/openssl-sys) crate, with the `vendored` feature enabled in order to build and bundle the OpenSSL crypto library. - If turned on, this uses the [`openssl-sys`](https://crates.io/crates/openssl-sys) crate, with the `vendored` feature enabled in order to build and bundle the OpenSSL crypto library.
* `hooks` for [Commit, Rollback](http://sqlite.org/c3ref/commit_hook.html) and [Data Change](http://sqlite.org/c3ref/update_hook.html) notification callbacks. * `hooks` for [Commit, Rollback](http://sqlite.org/c3ref/commit_hook.html) and [Data Change](http://sqlite.org/c3ref/update_hook.html) notification callbacks.
* `preupdate_hook` for [preupdate](https://sqlite.org/c3ref/preupdate_count.html) notification callbacks. (Implies `hooks`.)
* `unlock_notify` for [Unlock](https://sqlite.org/unlock_notify.html) notification. * `unlock_notify` for [Unlock](https://sqlite.org/unlock_notify.html) notification.
* `vtab` for [virtual table](https://sqlite.org/vtab.html) support (allows you to write virtual table implementations in Rust). Currently, only read-only virtual tables are supported. * `vtab` for [virtual table](https://sqlite.org/vtab.html) support (allows you to write virtual table implementations in Rust). Currently, only read-only virtual tables are supported.
* `series` exposes [`generate_series(...)`](https://www.sqlite.org/series.html) Table-Valued Function. (Implies `vtab`.) * `series` exposes [`generate_series(...)`](https://www.sqlite.org/series.html) Table-Valued Function. (Implies `vtab`.)
@@ -150,11 +148,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 * 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 [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 link against that. This source is embedded in the `libsqlite3-sys` crate and
is currently SQLite 3.44.0 (as of `rusqlite` 0.30.0 / `libsqlite3-sys` is currently SQLite 3.48.0 (as of `rusqlite` 0.33.0 / `libsqlite3-sys`
0.27.0). This is probably the simplest solution to any build problems. You can enable this by adding the following in your `Cargo.toml` file: 0.31.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 ```toml
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.30.0" version = "0.33.0"
features = ["bundled"] 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.) * 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.)
@@ -247,3 +245,8 @@ Depending on the set of enabled cargo `features`, rusqlite and libsqlite3-sys wi
- If `--features=bundled` is enabled, the vendored source of SQLite will be compiled and linked in. SQLite is in the public domain, as described [here](https://www.sqlite.org/copyright.html). - If `--features=bundled` is enabled, the vendored source of SQLite will be compiled and linked in. SQLite is in the public domain, as described [here](https://www.sqlite.org/copyright.html).
Both of these are quite permissive, have no bearing on the license of the code in `rusqlite` or `libsqlite3-sys` themselves, and can be entirely ignored if you do not use the feature in question. Both of these are quite permissive, have no bearing on the license of the code in `rusqlite` or `libsqlite3-sys` themselves, and can be entirely ignored if you do not use the feature in question.
## Minimum supported Rust version (MSRV)
Latest stable Rust version at the time of release. It might compile with older versions.

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
/* automatically generated by rust-bindgen 0.69.1 */ /* automatically generated by rust-bindgen 0.71.1 */
pub const SQLITE_VERSION: &[u8; 7] = b"3.14.0\0"; pub const SQLITE_VERSION: &::std::ffi::CStr = c"3.14.0";
pub const SQLITE_VERSION_NUMBER: i32 = 3014000; pub const SQLITE_VERSION_NUMBER: i32 = 3014000;
pub const SQLITE_SOURCE_ID: &[u8; 61] = pub const SQLITE_SOURCE_ID: &::std::ffi::CStr =
b"2016-08-08 13:40:27 d5e98057028abcf7217d0d2b2e29bbbcdf09d6de\0"; c"2016-08-08 13:40:27 d5e98057028abcf7217d0d2b2e29bbbcdf09d6de";
pub const SQLITE_OK: i32 = 0; pub const SQLITE_OK: i32 = 0;
pub const SQLITE_ERROR: i32 = 1; pub const SQLITE_ERROR: i32 = 1;
pub const SQLITE_INTERNAL: i32 = 2; pub const SQLITE_INTERNAL: i32 = 2;
@@ -237,10 +237,10 @@ pub const SQLITE_FUNCTION: i32 = 31;
pub const SQLITE_SAVEPOINT: i32 = 32; pub const SQLITE_SAVEPOINT: i32 = 32;
pub const SQLITE_COPY: i32 = 0; pub const SQLITE_COPY: i32 = 0;
pub const SQLITE_RECURSIVE: i32 = 33; pub const SQLITE_RECURSIVE: i32 = 33;
pub const SQLITE_TRACE_STMT: i32 = 1; pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1;
pub const SQLITE_TRACE_PROFILE: i32 = 2; pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2;
pub const SQLITE_TRACE_ROW: i32 = 4; pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4;
pub const SQLITE_TRACE_CLOSE: i32 = 8; pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8;
pub const SQLITE_LIMIT_LENGTH: i32 = 0; pub const SQLITE_LIMIT_LENGTH: i32 = 0;
pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1;
pub const SQLITE_LIMIT_COLUMN: i32 = 2; pub const SQLITE_LIMIT_COLUMN: i32 = 2;
@@ -364,7 +364,7 @@ pub const FTS5_TOKENIZE_PREFIX: i32 = 2;
pub const FTS5_TOKENIZE_DOCUMENT: i32 = 4; pub const FTS5_TOKENIZE_DOCUMENT: i32 = 4;
pub const FTS5_TOKENIZE_AUX: i32 = 8; pub const FTS5_TOKENIZE_AUX: i32 = 8;
pub const FTS5_TOKEN_COLOCATED: i32 = 1; pub const FTS5_TOKEN_COLOCATED: i32 = 1;
extern "C" { unsafe extern "C" {
pub static sqlite3_version: [::std::os::raw::c_char; 0usize]; pub static sqlite3_version: [::std::os::raw::c_char; 0usize];
} }
#[repr(C)] #[repr(C)]
@@ -666,10 +666,10 @@ pub struct sqlite3_context {
} }
pub type sqlite3_destructor_type = pub type sqlite3_destructor_type =
::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>; ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>;
extern "C" { unsafe extern "C" {
pub static mut sqlite3_temp_directory: *mut ::std::os::raw::c_char; pub static mut sqlite3_temp_directory: *mut ::std::os::raw::c_char;
} }
extern "C" { unsafe extern "C" {
pub static mut sqlite3_data_directory: *mut ::std::os::raw::c_char; pub static mut sqlite3_data_directory: *mut ::std::os::raw::c_char;
} }
#[repr(C)] #[repr(C)]
@@ -2673,30 +2673,6 @@ pub unsafe fn sqlite3_bind_text(
(fun)(arg1, arg2, arg3, n, arg4) (fun)(arg1, arg2, arg3, n, arg4)
} }
static __SQLITE3_BIND_TEXT16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_bind_text16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_BIND_TEXT16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: ::std::option::Option<
unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void),
>,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5)
}
static __SQLITE3_BIND_VALUE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_BIND_VALUE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -2815,38 +2791,6 @@ pub unsafe fn sqlite3_collation_needed(
(fun)(arg1, arg2, arg3) (fun)(arg1, arg2, arg3)
} }
static __SQLITE3_COLLATION_NEEDED16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_collation_needed16(
arg1: *mut sqlite3,
arg2: *mut ::std::os::raw::c_void,
arg3: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: *mut sqlite3,
eTextRep: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
),
>,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_COLLATION_NEEDED16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *mut ::std::os::raw::c_void,
arg3: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: *mut sqlite3,
eTextRep: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
),
>,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3)
}
static __SQLITE3_COLUMN_BLOB: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_BLOB: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -2879,22 +2823,6 @@ pub unsafe fn sqlite3_column_bytes(
(fun)(arg1, iCol) (fun)(arg1, iCol)
} }
static __SQLITE3_COLUMN_BYTES16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_column_bytes16(
arg1: *mut sqlite3_stmt,
iCol: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_COLUMN_BYTES16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
iCol: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, iCol)
}
static __SQLITE3_COLUMN_COUNT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_COUNT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -2924,23 +2852,6 @@ pub unsafe fn sqlite3_column_database_name(
(fun)(arg1, arg2) (fun)(arg1, arg2)
} }
static __SQLITE3_COLUMN_DATABASE_NAME16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_column_database_name16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_COLUMN_DATABASE_NAME16
.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1, arg2)
}
static __SQLITE3_COLUMN_DECLTYPE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_DECLTYPE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -2957,22 +2868,6 @@ pub unsafe fn sqlite3_column_decltype(
(fun)(arg1, i) (fun)(arg1, i)
} }
static __SQLITE3_COLUMN_DECLTYPE16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_column_decltype16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_COLUMN_DECLTYPE16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1, arg2)
}
static __SQLITE3_COLUMN_DOUBLE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_DOUBLE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3037,22 +2932,6 @@ pub unsafe fn sqlite3_column_name(
(fun)(arg1, arg2) (fun)(arg1, arg2)
} }
static __SQLITE3_COLUMN_NAME16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_column_name16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_COLUMN_NAME16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1, arg2)
}
static __SQLITE3_COLUMN_ORIGIN_NAME: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_ORIGIN_NAME: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3069,23 +2948,6 @@ pub unsafe fn sqlite3_column_origin_name(
(fun)(arg1, arg2) (fun)(arg1, arg2)
} }
static __SQLITE3_COLUMN_ORIGIN_NAME16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_column_origin_name16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_COLUMN_ORIGIN_NAME16
.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1, arg2)
}
static __SQLITE3_COLUMN_TABLE_NAME: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_TABLE_NAME: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3102,22 +2964,6 @@ pub unsafe fn sqlite3_column_table_name(
(fun)(arg1, arg2) (fun)(arg1, arg2)
} }
static __SQLITE3_COLUMN_TABLE_NAME16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_column_table_name16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_COLUMN_TABLE_NAME16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1, arg2)
}
static __SQLITE3_COLUMN_TEXT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_TEXT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3134,22 +2980,6 @@ pub unsafe fn sqlite3_column_text(
(fun)(arg1, iCol) (fun)(arg1, iCol)
} }
static __SQLITE3_COLUMN_TEXT16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_column_text16(
arg1: *mut sqlite3_stmt,
iCol: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_COLUMN_TEXT16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_stmt,
iCol: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1, iCol)
}
static __SQLITE3_COLUMN_TYPE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_COLUMN_TYPE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3220,220 +3050,6 @@ pub unsafe fn sqlite3_complete(
(fun)(sql) (fun)(sql)
} }
static __SQLITE3_COMPLETE16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_complete16(
sql: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_COMPLETE16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
sql: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(sql)
}
static __SQLITE3_CREATE_COLLATION: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_create_collation(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: ::std::os::raw::c_int,
arg4: *mut ::std::os::raw::c_void,
arg5: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_CREATE_COLLATION.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: ::std::os::raw::c_int,
arg4: *mut ::std::os::raw::c_void,
arg5: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5)
}
static __SQLITE3_CREATE_COLLATION16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_create_collation16(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: *mut ::std::os::raw::c_void,
arg5: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_CREATE_COLLATION16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: *mut ::std::os::raw::c_void,
arg5: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5)
}
static __SQLITE3_CREATE_FUNCTION: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_create_function(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: ::std::os::raw::c_int,
arg4: ::std::os::raw::c_int,
arg5: *mut ::std::os::raw::c_void,
xFunc: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xStep: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xFinal: ::std::option::Option<unsafe extern "C" fn(arg1: *mut sqlite3_context)>,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_CREATE_FUNCTION.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: ::std::os::raw::c_int,
arg4: ::std::os::raw::c_int,
arg5: *mut ::std::os::raw::c_void,
xFunc: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xStep: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xFinal: ::std::option::Option<unsafe extern "C" fn(arg1: *mut sqlite3_context)>,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5, xFunc, xStep, xFinal)
}
static __SQLITE3_CREATE_FUNCTION16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_create_function16(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::os::raw::c_int,
arg5: *mut ::std::os::raw::c_void,
xFunc: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xStep: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xFinal: ::std::option::Option<unsafe extern "C" fn(arg1: *mut sqlite3_context)>,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_CREATE_FUNCTION16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::os::raw::c_int,
arg5: *mut ::std::os::raw::c_void,
xFunc: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xStep: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xFinal: ::std::option::Option<unsafe extern "C" fn(arg1: *mut sqlite3_context)>,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5, xFunc, xStep, xFinal)
}
static __SQLITE3_CREATE_MODULE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_create_module(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: *const sqlite3_module,
arg4: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_CREATE_MODULE.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: *const sqlite3_module,
arg4: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4)
}
static __SQLITE3_DATA_COUNT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_DATA_COUNT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3512,18 +3128,6 @@ pub unsafe fn sqlite3_errmsg(arg1: *mut sqlite3) -> *const ::std::os::raw::c_cha
(fun)(arg1) (fun)(arg1)
} }
static __SQLITE3_ERRMSG16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_errmsg16(arg1: *mut sqlite3) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_ERRMSG16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(arg1: *mut sqlite3) -> *const ::std::os::raw::c_void = ::std::mem::transmute(
ptr,
);
(fun)(arg1)
}
static __SQLITE3_EXEC: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_EXEC: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3710,66 +3314,6 @@ pub unsafe fn sqlite3_open(
(fun)(arg1, arg2) (fun)(arg1, arg2)
} }
static __SQLITE3_OPEN16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_open16(
arg1: *const ::std::os::raw::c_void,
arg2: *mut *mut sqlite3,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_OPEN16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *const ::std::os::raw::c_void,
arg2: *mut *mut sqlite3,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2)
}
static __SQLITE3_PREPARE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_prepare(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: ::std::os::raw::c_int,
arg4: *mut *mut sqlite3_stmt,
arg5: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_PREPARE.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: ::std::os::raw::c_int,
arg4: *mut *mut sqlite3_stmt,
arg5: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5)
}
static __SQLITE3_PREPARE16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_prepare16(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: *mut *mut sqlite3_stmt,
arg5: *mut *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_PREPARE16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: *mut *mut sqlite3_stmt,
arg5: *mut *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5)
}
static __SQLITE3_PROFILE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_PROFILE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3906,24 +3450,6 @@ pub unsafe fn sqlite3_result_error(
(fun)(arg1, arg2, arg3) (fun)(arg1, arg2, arg3)
} }
static __SQLITE3_RESULT_ERROR16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_result_error16(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
) {
let ptr = __SQLITE3_RESULT_ERROR16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
) = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3)
}
static __SQLITE3_RESULT_INT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_RESULT_INT: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -3986,72 +3512,6 @@ pub unsafe fn sqlite3_result_text(
(fun)(arg1, arg2, arg3, arg4) (fun)(arg1, arg2, arg3, arg4)
} }
static __SQLITE3_RESULT_TEXT16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_result_text16(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) {
let ptr = __SQLITE3_RESULT_TEXT16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<
unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void),
>,
) = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4)
}
static __SQLITE3_RESULT_TEXT16BE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_result_text16be(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) {
let ptr = __SQLITE3_RESULT_TEXT16BE.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<
unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void),
>,
) = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4)
}
static __SQLITE3_RESULT_TEXT16LE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_result_text16le(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) {
let ptr = __SQLITE3_RESULT_TEXT16LE.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<
unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void),
>,
) = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4)
}
static __SQLITE3_RESULT_VALUE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_RESULT_VALUE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -4303,18 +3763,6 @@ pub unsafe fn sqlite3_value_bytes(arg1: *mut sqlite3_value) -> ::std::os::raw::c
(fun)(arg1) (fun)(arg1)
} }
static __SQLITE3_VALUE_BYTES16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_value_bytes16(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_VALUE_BYTES16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int = ::std::mem::transmute(
ptr,
);
(fun)(arg1)
}
static __SQLITE3_VALUE_DOUBLE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_VALUE_DOUBLE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -4379,48 +3827,6 @@ pub unsafe fn sqlite3_value_text(
(fun)(arg1) (fun)(arg1)
} }
static __SQLITE3_VALUE_TEXT16: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_value_text16(
arg1: *mut sqlite3_value,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_VALUE_TEXT16.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_value,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1)
}
static __SQLITE3_VALUE_TEXT16BE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_value_text16be(
arg1: *mut sqlite3_value,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_VALUE_TEXT16BE.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_value,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1)
}
static __SQLITE3_VALUE_TEXT16LE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_value_text16le(
arg1: *mut sqlite3_value,
) -> *const ::std::os::raw::c_void {
let ptr = __SQLITE3_VALUE_TEXT16LE.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3_value,
) -> *const ::std::os::raw::c_void = ::std::mem::transmute(ptr);
(fun)(arg1)
}
static __SQLITE3_VALUE_TYPE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_VALUE_TYPE: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -4473,28 +3879,6 @@ pub unsafe fn sqlite3_prepare_v2(
(fun)(arg1, arg2, arg3, arg4, arg5) (fun)(arg1, arg2, arg3, arg4, arg5)
} }
static __SQLITE3_PREPARE16_V2: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_prepare16_v2(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: *mut *mut sqlite3_stmt,
arg5: *mut *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_PREPARE16_V2.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: *mut *mut sqlite3_stmt,
arg5: *mut *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int = ::std::mem::transmute(ptr);
(fun)(arg1, arg2, arg3, arg4, arg5)
}
static __SQLITE3_CLEAR_BINDINGS: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_CLEAR_BINDINGS: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -5498,18 +4882,6 @@ pub unsafe fn sqlite3_vtab_on_conflict(arg1: *mut sqlite3) -> ::std::os::raw::c_
(fun)(arg1) (fun)(arg1)
} }
static __SQLITE3_CLOSE_V2: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(),
);
pub unsafe fn sqlite3_close_v2(arg1: *mut sqlite3) -> ::std::os::raw::c_int {
let ptr = __SQLITE3_CLOSE_V2.load(::std::sync::atomic::Ordering::Acquire);
assert!(! ptr.is_null(), "SQLite API not initialized or SQLite feature omitted");
let fun: unsafe extern "C" fn(arg1: *mut sqlite3) -> ::std::os::raw::c_int = ::std::mem::transmute(
ptr,
);
(fun)(arg1)
}
static __SQLITE3_DB_FILENAME: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new( static __SQLITE3_DB_FILENAME: ::std::sync::atomic::AtomicPtr<()> = ::std::sync::atomic::AtomicPtr::new(
::std::ptr::null_mut(), ::std::ptr::null_mut(),
); );
@@ -6167,10 +5539,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_BIND_TEXT __SQLITE3_BIND_TEXT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).bind_text16 {
__SQLITE3_BIND_TEXT16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).bind_value { if let Some(fun) = (*p_api).bind_value {
__SQLITE3_BIND_VALUE __SQLITE3_BIND_VALUE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6195,10 +5563,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_COLLATION_NEEDED __SQLITE3_COLLATION_NEEDED
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).collation_needed16 {
__SQLITE3_COLLATION_NEEDED16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_blob { if let Some(fun) = (*p_api).column_blob {
__SQLITE3_COLUMN_BLOB __SQLITE3_COLUMN_BLOB
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6207,10 +5571,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_COLUMN_BYTES __SQLITE3_COLUMN_BYTES
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).column_bytes16 {
__SQLITE3_COLUMN_BYTES16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_count { if let Some(fun) = (*p_api).column_count {
__SQLITE3_COLUMN_COUNT __SQLITE3_COLUMN_COUNT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6219,18 +5579,10 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_COLUMN_DATABASE_NAME __SQLITE3_COLUMN_DATABASE_NAME
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).column_database_name16 {
__SQLITE3_COLUMN_DATABASE_NAME16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_decltype { if let Some(fun) = (*p_api).column_decltype {
__SQLITE3_COLUMN_DECLTYPE __SQLITE3_COLUMN_DECLTYPE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).column_decltype16 {
__SQLITE3_COLUMN_DECLTYPE16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_double { if let Some(fun) = (*p_api).column_double {
__SQLITE3_COLUMN_DOUBLE __SQLITE3_COLUMN_DOUBLE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6247,34 +5599,18 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_COLUMN_NAME __SQLITE3_COLUMN_NAME
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).column_name16 {
__SQLITE3_COLUMN_NAME16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_origin_name { if let Some(fun) = (*p_api).column_origin_name {
__SQLITE3_COLUMN_ORIGIN_NAME __SQLITE3_COLUMN_ORIGIN_NAME
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).column_origin_name16 {
__SQLITE3_COLUMN_ORIGIN_NAME16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_table_name { if let Some(fun) = (*p_api).column_table_name {
__SQLITE3_COLUMN_TABLE_NAME __SQLITE3_COLUMN_TABLE_NAME
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).column_table_name16 {
__SQLITE3_COLUMN_TABLE_NAME16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_text { if let Some(fun) = (*p_api).column_text {
__SQLITE3_COLUMN_TEXT __SQLITE3_COLUMN_TEXT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).column_text16 {
__SQLITE3_COLUMN_TEXT16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).column_type { if let Some(fun) = (*p_api).column_type {
__SQLITE3_COLUMN_TYPE __SQLITE3_COLUMN_TYPE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6291,30 +5627,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_COMPLETE __SQLITE3_COMPLETE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).complete16 {
__SQLITE3_COMPLETE16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).create_collation {
__SQLITE3_CREATE_COLLATION
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).create_collation16 {
__SQLITE3_CREATE_COLLATION16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).create_function {
__SQLITE3_CREATE_FUNCTION
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).create_function16 {
__SQLITE3_CREATE_FUNCTION16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).create_module {
__SQLITE3_CREATE_MODULE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).data_count { if let Some(fun) = (*p_api).data_count {
__SQLITE3_DATA_COUNT __SQLITE3_DATA_COUNT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6339,10 +5651,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_ERRMSG __SQLITE3_ERRMSG
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).errmsg16 {
__SQLITE3_ERRMSG16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).exec { if let Some(fun) = (*p_api).exec {
__SQLITE3_EXEC __SQLITE3_EXEC
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6391,18 +5699,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_OPEN __SQLITE3_OPEN
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).open16 {
__SQLITE3_OPEN16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).prepare {
__SQLITE3_PREPARE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).prepare16 {
__SQLITE3_PREPARE16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).profile { if let Some(fun) = (*p_api).profile {
__SQLITE3_PROFILE __SQLITE3_PROFILE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6431,10 +5727,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_RESULT_ERROR __SQLITE3_RESULT_ERROR
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).result_error16 {
__SQLITE3_RESULT_ERROR16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).result_int { if let Some(fun) = (*p_api).result_int {
__SQLITE3_RESULT_INT __SQLITE3_RESULT_INT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6451,18 +5743,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_RESULT_TEXT __SQLITE3_RESULT_TEXT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).result_text16 {
__SQLITE3_RESULT_TEXT16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).result_text16be {
__SQLITE3_RESULT_TEXT16BE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).result_text16le {
__SQLITE3_RESULT_TEXT16LE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).result_value { if let Some(fun) = (*p_api).result_value {
__SQLITE3_RESULT_VALUE __SQLITE3_RESULT_VALUE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6511,10 +5791,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_VALUE_BYTES __SQLITE3_VALUE_BYTES
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).value_bytes16 {
__SQLITE3_VALUE_BYTES16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).value_double { if let Some(fun) = (*p_api).value_double {
__SQLITE3_VALUE_DOUBLE __SQLITE3_VALUE_DOUBLE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6535,18 +5811,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_VALUE_TEXT __SQLITE3_VALUE_TEXT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).value_text16 {
__SQLITE3_VALUE_TEXT16
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).value_text16be {
__SQLITE3_VALUE_TEXT16BE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).value_text16le {
__SQLITE3_VALUE_TEXT16LE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).value_type { if let Some(fun) = (*p_api).value_type {
__SQLITE3_VALUE_TYPE __SQLITE3_VALUE_TYPE
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6559,10 +5823,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_PREPARE_V2 __SQLITE3_PREPARE_V2
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).prepare16_v2 {
__SQLITE3_PREPARE16_V2
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).clear_bindings { if let Some(fun) = (*p_api).clear_bindings {
__SQLITE3_CLEAR_BINDINGS __SQLITE3_CLEAR_BINDINGS
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
@@ -6803,10 +6063,6 @@ pub unsafe fn rusqlite_extension_init2(
__SQLITE3_VTAB_ON_CONFLICT __SQLITE3_VTAB_ON_CONFLICT
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
} }
if let Some(fun) = (*p_api).close_v2 {
__SQLITE3_CLOSE_V2
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);
}
if let Some(fun) = (*p_api).db_filename { if let Some(fun) = (*p_api).db_filename {
__SQLITE3_DB_FILENAME __SQLITE3_DB_FILENAME
.store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release);

View File

@@ -5,8 +5,8 @@ use std::path::Path;
/// `cfg!(windows)`, since the latter does not properly handle cross-compilation /// `cfg!(windows)`, since the latter does not properly handle cross-compilation
/// ///
/// Note that there is no way to know at compile-time which system we'll be /// Note that there is no way to know at compile-time which system we'll be
/// targetting, and this test must be made at run-time (of the build script) See /// targeting, and this test must be made at run-time (of the build script) See
/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts /// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
fn win_target() -> bool { fn win_target() -> bool {
env::var("CARGO_CFG_WINDOWS").is_ok() env::var("CARGO_CFG_WINDOWS").is_ok()
} }
@@ -15,7 +15,7 @@ fn win_target() -> bool {
/// See [`win_target`] /// See [`win_target`]
#[cfg(any(feature = "bundled", feature = "bundled-windows"))] #[cfg(any(feature = "bundled", feature = "bundled-windows"))]
fn android_target() -> bool { fn android_target() -> bool {
env::var("CARGO_CFG_TARGET_OS").map_or(false, |v| v == "android") env::var("CARGO_CFG_TARGET_OS").is_ok_and(|v| v == "android")
} }
/// Tells whether a given compiler will be used `compiler_name` is compared to /// Tells whether a given compiler will be used `compiler_name` is compared to
@@ -23,7 +23,7 @@ fn android_target() -> bool {
/// ///
/// See [`win_target`] /// See [`win_target`]
fn is_compiler(compiler_name: &str) -> bool { fn is_compiler(compiler_name: &str) -> bool {
env::var("CARGO_CFG_TARGET_ENV").map_or(false, |v| v == compiler_name) env::var("CARGO_CFG_TARGET_ENV").is_ok_and(|v| v == compiler_name)
} }
/// Copy bindgen file from `dir` to `out_path`. /// Copy bindgen file from `dir` to `out_path`.
@@ -47,7 +47,7 @@ fn main() {
} }
println!("cargo:rerun-if-env-changed=LIBSQLITE3_SYS_USE_PKG_CONFIG"); println!("cargo:rerun-if-env-changed=LIBSQLITE3_SYS_USE_PKG_CONFIG");
if env::var_os("LIBSQLITE3_SYS_USE_PKG_CONFIG").map_or(false, |s| s != "0") if env::var_os("LIBSQLITE3_SYS_USE_PKG_CONFIG").is_some_and(|s| s != "0")
|| cfg!(feature = "loadable_extension") || cfg!(feature = "loadable_extension")
{ {
build_linked::main(&out_dir, &out_path); build_linked::main(&out_dir, &out_path);
@@ -131,12 +131,12 @@ mod build_bundled {
.flag("-DSQLITE_ENABLE_LOAD_EXTENSION=1") .flag("-DSQLITE_ENABLE_LOAD_EXTENSION=1")
.flag("-DSQLITE_ENABLE_MEMORY_MANAGEMENT") .flag("-DSQLITE_ENABLE_MEMORY_MANAGEMENT")
.flag("-DSQLITE_ENABLE_RTREE") .flag("-DSQLITE_ENABLE_RTREE")
.flag("-DSQLITE_ENABLE_STAT2")
.flag("-DSQLITE_ENABLE_STAT4") .flag("-DSQLITE_ENABLE_STAT4")
.flag("-DSQLITE_SOUNDEX") .flag("-DSQLITE_SOUNDEX")
.flag("-DSQLITE_THREADSAFE=1") .flag("-DSQLITE_THREADSAFE=1")
.flag("-DSQLITE_USE_URI") .flag("-DSQLITE_USE_URI")
.flag("-DHAVE_USLEEP=1") .flag("-DHAVE_USLEEP=1")
.flag("-DHAVE_ISNAN")
.flag("-D_POSIX_THREAD_SAFE_FUNCTIONS") // cross compile with MinGW .flag("-D_POSIX_THREAD_SAFE_FUNCTIONS") // cross compile with MinGW
.warnings(false); .warnings(false);
@@ -156,25 +156,34 @@ mod build_bundled {
let (lib_dir, inc_dir) = match (lib_dir, inc_dir) { let (lib_dir, inc_dir) = match (lib_dir, inc_dir) {
(Some(lib_dir), Some(inc_dir)) => { (Some(lib_dir), Some(inc_dir)) => {
use_openssl = true; use_openssl = true;
(lib_dir, inc_dir) (vec![lib_dir], inc_dir)
} }
(lib_dir, inc_dir) => match find_openssl_dir(&host, &target) { (lib_dir, inc_dir) => match find_openssl_dir(&host, &target) {
None => { None => {
if is_windows && !cfg!(feature = "bundled-sqlcipher-vendored-openssl") { if is_windows && !cfg!(feature = "bundled-sqlcipher-vendored-openssl") {
panic!("Missing environment variable OPENSSL_DIR or OPENSSL_DIR is not set") panic!("Missing environment variable OPENSSL_DIR or OPENSSL_DIR is not set")
} else { } else {
(PathBuf::new(), PathBuf::new()) (vec![PathBuf::new()], PathBuf::new())
} }
} }
Some(openssl_dir) => { Some(openssl_dir) => {
let lib_dir = lib_dir.unwrap_or_else(|| openssl_dir.join("lib")); let lib_dir = lib_dir.map(|d| vec![d]).unwrap_or_else(|| {
let mut lib_dirs = vec![];
// OpenSSL 3.0 now puts its libraries in lib64/ by default,
// check for both it and lib/.
if openssl_dir.join("lib64").exists() {
lib_dirs.push(openssl_dir.join("lib64"));
}
if openssl_dir.join("lib").exists() {
lib_dirs.push(openssl_dir.join("lib"));
}
lib_dirs
});
let inc_dir = inc_dir.unwrap_or_else(|| openssl_dir.join("include")); let inc_dir = inc_dir.unwrap_or_else(|| openssl_dir.join("include"));
assert!( if !lib_dir.iter().all(|p| p.exists()) {
Path::new(&lib_dir).exists(), panic!("OpenSSL library directory does not exist: {lib_dir:?}");
"OpenSSL library directory does not exist: {}", }
lib_dir.to_string_lossy()
);
if !Path::new(&inc_dir).exists() { if !Path::new(&inc_dir).exists() {
panic!( panic!(
@@ -196,8 +205,10 @@ mod build_bundled {
} else if use_openssl { } else if use_openssl {
cfg.include(inc_dir.to_string_lossy().as_ref()); cfg.include(inc_dir.to_string_lossy().as_ref());
let lib_name = if is_windows { "libcrypto" } else { "crypto" }; let lib_name = if is_windows { "libcrypto" } else { "crypto" };
println!("cargo:rustc-link-lib=dylib={}", lib_name); println!("cargo:rustc-link-lib=dylib={lib_name}");
println!("cargo:rustc-link-search={}", lib_dir.to_string_lossy()); for lib_dir_item in &lib_dir {
println!("cargo:rustc-link-search={}", lib_dir_item.to_string_lossy());
}
} else if is_apple { } else if is_apple {
cfg.flag("-DSQLCIPHER_CRYPTO_CC"); cfg.flag("-DSQLCIPHER_CRYPTO_CC");
println!("cargo:rustc-link-lib=framework=Security"); println!("cargo:rustc-link-lib=framework=Security");
@@ -225,29 +236,10 @@ mod build_bundled {
cfg.static_crt(true); cfg.static_crt(true);
} }
// Older versions of visual studio don't support c99 (including isnan), which
// causes a build failure when the linker fails to find the `isnan`
// function. `sqlite` provides its own implementation, using the fact
// that x != x when x is NaN.
//
// There may be other platforms that don't support `isnan`, they should be
// tested for here.
if is_compiler("msvc") {
use cc::windows_registry::{find_vs_version, VsVers};
let vs_has_nan = match find_vs_version() {
Ok(ver) => ver != VsVers::Vs12,
Err(_msg) => false,
};
if vs_has_nan {
cfg.flag("-DHAVE_ISNAN");
}
} else {
cfg.flag("-DHAVE_ISNAN");
}
if !win_target() { if !win_target() {
cfg.flag("-DHAVE_LOCALTIME_R"); cfg.flag("-DHAVE_LOCALTIME_R");
} }
if env::var("TARGET").map_or(false, |v| v == "wasm32-wasi") { if env::var("TARGET").is_ok_and(|v| v.starts_with("wasm32-wasi")) {
cfg.flag("-USQLITE_THREADSAFE") cfg.flag("-USQLITE_THREADSAFE")
.flag("-DSQLITE_THREADSAFE=0") .flag("-DSQLITE_THREADSAFE=0")
// https://github.com/rust-lang/rust/issues/74393 // https://github.com/rust-lang/rust/issues/74393
@@ -272,17 +264,17 @@ mod build_bundled {
} }
if let Ok(limit) = env::var("SQLITE_MAX_VARIABLE_NUMBER") { if let Ok(limit) = env::var("SQLITE_MAX_VARIABLE_NUMBER") {
cfg.flag(&format!("-DSQLITE_MAX_VARIABLE_NUMBER={limit}")); cfg.flag(format!("-DSQLITE_MAX_VARIABLE_NUMBER={limit}"));
} }
println!("cargo:rerun-if-env-changed=SQLITE_MAX_VARIABLE_NUMBER"); println!("cargo:rerun-if-env-changed=SQLITE_MAX_VARIABLE_NUMBER");
if let Ok(limit) = env::var("SQLITE_MAX_EXPR_DEPTH") { if let Ok(limit) = env::var("SQLITE_MAX_EXPR_DEPTH") {
cfg.flag(&format!("-DSQLITE_MAX_EXPR_DEPTH={limit}")); cfg.flag(format!("-DSQLITE_MAX_EXPR_DEPTH={limit}"));
} }
println!("cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH"); println!("cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH");
if let Ok(limit) = env::var("SQLITE_MAX_COLUMN") { if let Ok(limit) = env::var("SQLITE_MAX_COLUMN") {
cfg.flag(&format!("-DSQLITE_MAX_COLUMN={limit}")); cfg.flag(format!("-DSQLITE_MAX_COLUMN={limit}"));
} }
println!("cargo:rerun-if-env-changed=SQLITE_MAX_COLUMN"); println!("cargo:rerun-if-env-changed=SQLITE_MAX_COLUMN");
@@ -291,9 +283,9 @@ mod build_bundled {
if extra.starts_with("-D") || extra.starts_with("-U") { if extra.starts_with("-D") || extra.starts_with("-U") {
cfg.flag(extra); cfg.flag(extra);
} else if extra.starts_with("SQLITE_") { } else if extra.starts_with("SQLITE_") {
cfg.flag(&format!("-D{extra}")); cfg.flag(format!("-D{extra}"));
} else { } else {
panic!("Don't understand {} in LIBSQLITE3_FLAGS", extra); panic!("Don't understand {extra} in LIBSQLITE3_FLAGS");
} }
} }
} }
@@ -344,7 +336,7 @@ pub enum HeaderLocation {
} }
impl From<HeaderLocation> for String { impl From<HeaderLocation> for String {
fn from(header: HeaderLocation) -> String { fn from(header: HeaderLocation) -> Self {
match header { match header {
HeaderLocation::FromEnvironment => { HeaderLocation::FromEnvironment => {
let prefix = env_prefix(); let prefix = env_prefix();
@@ -487,8 +479,8 @@ mod build_linked {
} }
#[cfg(not(feature = "buildtime_bindgen"))] #[cfg(not(feature = "buildtime_bindgen"))]
#[allow(dead_code)]
mod bindings { mod bindings {
#![allow(dead_code)]
use super::HeaderLocation; use super::HeaderLocation;
use std::path::Path; use std::path::Path;
@@ -515,6 +507,7 @@ mod bindings {
if name == "SQLITE_SERIALIZE_NOCOPY" if name == "SQLITE_SERIALIZE_NOCOPY"
|| name.starts_with("SQLITE_DESERIALIZE_") || name.starts_with("SQLITE_DESERIALIZE_")
|| name.starts_with("SQLITE_PREPARE_") || name.starts_with("SQLITE_PREPARE_")
|| name.starts_with("SQLITE_TRACE_")
{ {
Some(IntKind::UInt) Some(IntKind::UInt)
} else { } else {
@@ -540,6 +533,7 @@ mod bindings {
let mut bindings = bindgen::builder() let mut bindings = bindgen::builder()
.default_macro_constant_type(bindgen::MacroTypeVariation::Signed) .default_macro_constant_type(bindgen::MacroTypeVariation::Signed)
.disable_nested_struct_naming() .disable_nested_struct_naming()
.generate_cstr(true)
.trust_clang_mangling(false) .trust_clang_mangling(false)
.header(header.clone()) .header(header.clone())
.parse_callbacks(Box::new(SqliteTypeChooser)); .parse_callbacks(Box::new(SqliteTypeChooser));
@@ -554,8 +548,8 @@ mod bindings {
xEntryPoint: ::std::option::Option< xEntryPoint: ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
db: *mut sqlite3, db: *mut sqlite3,
pzErrMsg: *mut *const ::std::os::raw::c_char, pzErrMsg: *mut *mut ::std::os::raw::c_char,
pThunk: *const sqlite3_api_routines, _: *const sqlite3_api_routines,
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
>, >,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
@@ -568,13 +562,19 @@ mod bindings {
xEntryPoint: ::std::option::Option< xEntryPoint: ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
db: *mut sqlite3, db: *mut sqlite3,
pzErrMsg: *mut *const ::std::os::raw::c_char, pzErrMsg: *mut *mut ::std::os::raw::c_char,
pThunk: *const sqlite3_api_routines, _: *const sqlite3_api_routines,
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
>, >,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
}"#, }"#,
); )
.blocklist_function(".*16.*")
.blocklist_function("sqlite3_close_v2")
.blocklist_function("sqlite3_create_collation")
.blocklist_function("sqlite3_create_function")
.blocklist_function("sqlite3_create_module")
.blocklist_function("sqlite3_prepare");
} }
if cfg!(any(feature = "sqlcipher", feature = "bundled-sqlcipher")) { if cfg!(any(feature = "sqlcipher", feature = "bundled-sqlcipher")) {
@@ -668,16 +668,23 @@ mod loadable_extension {
// (2) `#define sqlite3_xyz sqlite3_api->abc` => `pub unsafe fn // (2) `#define sqlite3_xyz sqlite3_api->abc` => `pub unsafe fn
// sqlite3_xyz(args) -> ty {...}` for each `abc` field: // sqlite3_xyz(args) -> ty {...}` for each `abc` field:
for field in sqlite3_api_routines.fields { for field in sqlite3_api_routines.fields {
let ident = field.ident.expect("unamed field"); let ident = field.ident.expect("unnamed field");
let span = ident.span(); let span = ident.span();
let name = ident.to_string(); let name = ident.to_string();
if name == "vmprintf" || name == "xvsnprintf" || name == "str_vappendf" { if name.contains("16") {
continue; // skip UTF-16 api as rust uses UTF-8
} else if name == "vmprintf" || name == "xvsnprintf" || name == "str_vappendf" {
continue; // skip va_list continue; // skip va_list
} else if name == "aggregate_count" } else if name == "aggregate_count"
|| name == "expired" || name == "expired"
|| name == "global_recover" || name == "global_recover"
|| name == "thread_cleanup" || name == "thread_cleanup"
|| name == "transfer_bindings" || name == "transfer_bindings"
|| name == "create_collation"
|| name == "create_function"
|| name == "create_module"
|| name == "prepare"
|| name == "close_v2"
{ {
continue; // omit deprecated continue; // omit deprecated
} }

View File

@@ -1,33 +1,32 @@
/* automatically generated by rust-bindgen 0.63.0 */ /* automatically generated by rust-bindgen 0.70.1 */
extern "C" { extern "C" {
pub fn sqlite3_auto_extension( pub fn sqlite3_auto_extension(
xEntryPoint: ::std::option::Option< xEntryPoint: ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
db: *mut sqlite3, db: *mut sqlite3,
pzErrMsg: *mut *const ::std::os::raw::c_char, pzErrMsg: *mut *mut ::std::os::raw::c_char,
pThunk: *const sqlite3_api_routines, _: *const sqlite3_api_routines,
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
>, >,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" { extern "C" {
pub fn sqlite3_cancel_auto_extension( pub fn sqlite3_cancel_auto_extension(
xEntryPoint: ::std::option::Option< xEntryPoint: ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
db: *mut sqlite3, db: *mut sqlite3,
pzErrMsg: *mut *const ::std::os::raw::c_char, pzErrMsg: *mut *mut ::std::os::raw::c_char,
pThunk: *const sqlite3_api_routines, _: *const sqlite3_api_routines,
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
>, >,
) -> ::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: &[u8; 7] = b"3.46.1\0";
pub const SQLITE_VERSION_NUMBER: i32 = 3039004; pub const SQLITE_VERSION_NUMBER: i32 = 3046001;
pub const SQLITE_SOURCE_ID: &[u8; 85usize] = pub const SQLITE_SOURCE_ID: &[u8; 85] =
b"2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26alt1\0"; b"2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69aalt1\0";
pub const SQLITE_OK: i32 = 0; pub const SQLITE_OK: i32 = 0;
pub const SQLITE_ERROR: i32 = 1; pub const SQLITE_ERROR: i32 = 1;
pub const SQLITE_INTERNAL: i32 = 2; pub const SQLITE_INTERNAL: i32 = 2;
@@ -95,6 +94,7 @@ pub const SQLITE_IOERR_COMMIT_ATOMIC: i32 = 7690;
pub const SQLITE_IOERR_ROLLBACK_ATOMIC: i32 = 7946; pub const SQLITE_IOERR_ROLLBACK_ATOMIC: i32 = 7946;
pub const SQLITE_IOERR_DATA: i32 = 8202; pub const SQLITE_IOERR_DATA: i32 = 8202;
pub const SQLITE_IOERR_CORRUPTFS: i32 = 8458; pub const SQLITE_IOERR_CORRUPTFS: i32 = 8458;
pub const SQLITE_IOERR_IN_PAGE: i32 = 8714;
pub const SQLITE_LOCKED_SHAREDCACHE: i32 = 262; pub const SQLITE_LOCKED_SHAREDCACHE: i32 = 262;
pub const SQLITE_LOCKED_VTAB: i32 = 518; pub const SQLITE_LOCKED_VTAB: i32 = 518;
pub const SQLITE_BUSY_RECOVERY: i32 = 261; pub const SQLITE_BUSY_RECOVERY: i32 = 261;
@@ -130,6 +130,7 @@ pub const SQLITE_CONSTRAINT_PINNED: i32 = 2835;
pub const SQLITE_CONSTRAINT_DATATYPE: i32 = 3091; pub const SQLITE_CONSTRAINT_DATATYPE: i32 = 3091;
pub const SQLITE_NOTICE_RECOVER_WAL: i32 = 283; pub const SQLITE_NOTICE_RECOVER_WAL: i32 = 283;
pub const SQLITE_NOTICE_RECOVER_ROLLBACK: i32 = 539; 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_WARNING_AUTOINDEX: i32 = 284;
pub const SQLITE_AUTH_USER: i32 = 279; pub const SQLITE_AUTH_USER: i32 = 279;
pub const SQLITE_OK_LOAD_PERMANENTLY: i32 = 256; pub const SQLITE_OK_LOAD_PERMANENTLY: i32 = 256;
@@ -220,6 +221,7 @@ pub const SQLITE_FCNTL_RESERVE_BYTES: i32 = 38;
pub const SQLITE_FCNTL_CKPT_START: i32 = 39; pub const SQLITE_FCNTL_CKPT_START: i32 = 39;
pub const SQLITE_FCNTL_EXTERNAL_READER: i32 = 40; pub const SQLITE_FCNTL_EXTERNAL_READER: i32 = 40;
pub const SQLITE_FCNTL_CKSM_FILE: i32 = 41; 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_GET_LOCKPROXYFILE: i32 = 2;
pub const SQLITE_SET_LOCKPROXYFILE: i32 = 3; pub const SQLITE_SET_LOCKPROXYFILE: i32 = 3;
pub const SQLITE_LAST_ERRNO: i32 = 4; pub const SQLITE_LAST_ERRNO: i32 = 4;
@@ -259,6 +261,7 @@ pub const SQLITE_CONFIG_STMTJRNL_SPILL: i32 = 26;
pub const SQLITE_CONFIG_SMALL_MALLOC: i32 = 27; pub const SQLITE_CONFIG_SMALL_MALLOC: i32 = 27;
pub const SQLITE_CONFIG_SORTERREF_SIZE: i32 = 28; pub const SQLITE_CONFIG_SORTERREF_SIZE: i32 = 28;
pub const SQLITE_CONFIG_MEMDB_MAXSIZE: i32 = 29; pub const SQLITE_CONFIG_MEMDB_MAXSIZE: i32 = 29;
pub const SQLITE_CONFIG_ROWID_IN_VIEW: i32 = 30;
pub const SQLITE_DBCONFIG_MAINDBNAME: i32 = 1000; pub const SQLITE_DBCONFIG_MAINDBNAME: i32 = 1000;
pub const SQLITE_DBCONFIG_LOOKASIDE: i32 = 1001; pub const SQLITE_DBCONFIG_LOOKASIDE: i32 = 1001;
pub const SQLITE_DBCONFIG_ENABLE_FKEY: i32 = 1002; pub const SQLITE_DBCONFIG_ENABLE_FKEY: i32 = 1002;
@@ -277,7 +280,9 @@ pub const SQLITE_DBCONFIG_DQS_DDL: i32 = 1014;
pub const SQLITE_DBCONFIG_ENABLE_VIEW: i32 = 1015; pub const SQLITE_DBCONFIG_ENABLE_VIEW: i32 = 1015;
pub const SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: i32 = 1016; pub const SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: i32 = 1016;
pub const SQLITE_DBCONFIG_TRUSTED_SCHEMA: i32 = 1017; pub const SQLITE_DBCONFIG_TRUSTED_SCHEMA: i32 = 1017;
pub const SQLITE_DBCONFIG_MAX: i32 = 1017; pub const SQLITE_DBCONFIG_STMT_SCANSTATUS: i32 = 1018;
pub const SQLITE_DBCONFIG_REVERSE_SCANORDER: i32 = 1019;
pub const SQLITE_DBCONFIG_MAX: i32 = 1019;
pub const SQLITE_DENY: i32 = 1; pub const SQLITE_DENY: i32 = 1;
pub const SQLITE_IGNORE: i32 = 2; pub const SQLITE_IGNORE: i32 = 2;
pub const SQLITE_CREATE_INDEX: i32 = 1; pub const SQLITE_CREATE_INDEX: i32 = 1;
@@ -314,10 +319,10 @@ pub const SQLITE_FUNCTION: i32 = 31;
pub const SQLITE_SAVEPOINT: i32 = 32; pub const SQLITE_SAVEPOINT: i32 = 32;
pub const SQLITE_COPY: i32 = 0; pub const SQLITE_COPY: i32 = 0;
pub const SQLITE_RECURSIVE: i32 = 33; pub const SQLITE_RECURSIVE: i32 = 33;
pub const SQLITE_TRACE_STMT: i32 = 1; pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1;
pub const SQLITE_TRACE_PROFILE: i32 = 2; pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2;
pub const SQLITE_TRACE_ROW: i32 = 4; pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4;
pub const SQLITE_TRACE_CLOSE: i32 = 8; pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8;
pub const SQLITE_LIMIT_LENGTH: i32 = 0; pub const SQLITE_LIMIT_LENGTH: i32 = 0;
pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1;
pub const SQLITE_LIMIT_COLUMN: i32 = 2; pub const SQLITE_LIMIT_COLUMN: i32 = 2;
@@ -330,9 +335,9 @@ pub const SQLITE_LIMIT_LIKE_PATTERN_LENGTH: i32 = 8;
pub const SQLITE_LIMIT_VARIABLE_NUMBER: i32 = 9; pub const SQLITE_LIMIT_VARIABLE_NUMBER: i32 = 9;
pub const SQLITE_LIMIT_TRIGGER_DEPTH: i32 = 10; pub const SQLITE_LIMIT_TRIGGER_DEPTH: i32 = 10;
pub const SQLITE_LIMIT_WORKER_THREADS: i32 = 11; pub const SQLITE_LIMIT_WORKER_THREADS: i32 = 11;
pub const SQLITE_PREPARE_PERSISTENT: i32 = 1; pub const SQLITE_PREPARE_PERSISTENT: ::std::os::raw::c_uint = 1;
pub const SQLITE_PREPARE_NORMALIZE: i32 = 2; pub const SQLITE_PREPARE_NORMALIZE: ::std::os::raw::c_uint = 2;
pub const SQLITE_PREPARE_NO_VTAB: i32 = 4; pub const SQLITE_PREPARE_NO_VTAB: ::std::os::raw::c_uint = 4;
pub const SQLITE_INTEGER: i32 = 1; pub const SQLITE_INTEGER: i32 = 1;
pub const SQLITE_FLOAT: i32 = 2; pub const SQLITE_FLOAT: i32 = 2;
pub const SQLITE_BLOB: i32 = 4; pub const SQLITE_BLOB: i32 = 4;
@@ -349,6 +354,7 @@ pub const SQLITE_DETERMINISTIC: i32 = 2048;
pub const SQLITE_DIRECTONLY: i32 = 524288; pub const SQLITE_DIRECTONLY: i32 = 524288;
pub const SQLITE_SUBTYPE: i32 = 1048576; pub const SQLITE_SUBTYPE: i32 = 1048576;
pub const SQLITE_INNOCUOUS: i32 = 2097152; pub const SQLITE_INNOCUOUS: i32 = 2097152;
pub const SQLITE_RESULT_SUBTYPE: i32 = 16777216;
pub const SQLITE_WIN32_DATA_DIRECTORY_TYPE: i32 = 1; pub const SQLITE_WIN32_DATA_DIRECTORY_TYPE: i32 = 1;
pub const SQLITE_WIN32_TEMP_DIRECTORY_TYPE: i32 = 2; pub const SQLITE_WIN32_TEMP_DIRECTORY_TYPE: i32 = 2;
pub const SQLITE_TXN_NONE: i32 = 0; pub const SQLITE_TXN_NONE: i32 = 0;
@@ -393,6 +399,7 @@ pub const SQLITE_TESTCTRL_FIRST: i32 = 5;
pub const SQLITE_TESTCTRL_PRNG_SAVE: i32 = 5; pub const SQLITE_TESTCTRL_PRNG_SAVE: i32 = 5;
pub const SQLITE_TESTCTRL_PRNG_RESTORE: i32 = 6; pub const SQLITE_TESTCTRL_PRNG_RESTORE: i32 = 6;
pub const SQLITE_TESTCTRL_PRNG_RESET: i32 = 7; pub const SQLITE_TESTCTRL_PRNG_RESET: i32 = 7;
pub const SQLITE_TESTCTRL_FK_NO_ACTION: i32 = 7;
pub const SQLITE_TESTCTRL_BITVEC_TEST: i32 = 8; pub const SQLITE_TESTCTRL_BITVEC_TEST: i32 = 8;
pub const SQLITE_TESTCTRL_FAULT_INSTALL: i32 = 9; pub const SQLITE_TESTCTRL_FAULT_INSTALL: i32 = 9;
pub const SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: i32 = 10; pub const SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: i32 = 10;
@@ -400,6 +407,7 @@ pub const SQLITE_TESTCTRL_PENDING_BYTE: i32 = 11;
pub const SQLITE_TESTCTRL_ASSERT: i32 = 12; pub const SQLITE_TESTCTRL_ASSERT: i32 = 12;
pub const SQLITE_TESTCTRL_ALWAYS: i32 = 13; pub const SQLITE_TESTCTRL_ALWAYS: i32 = 13;
pub const SQLITE_TESTCTRL_RESERVE: i32 = 14; pub const SQLITE_TESTCTRL_RESERVE: i32 = 14;
pub const SQLITE_TESTCTRL_JSON_SELFCHECK: i32 = 14;
pub const SQLITE_TESTCTRL_OPTIMIZATIONS: i32 = 15; pub const SQLITE_TESTCTRL_OPTIMIZATIONS: i32 = 15;
pub const SQLITE_TESTCTRL_ISKEYWORD: i32 = 16; pub const SQLITE_TESTCTRL_ISKEYWORD: i32 = 16;
pub const SQLITE_TESTCTRL_SCRATCHMALLOC: i32 = 17; pub const SQLITE_TESTCTRL_SCRATCHMALLOC: i32 = 17;
@@ -421,7 +429,8 @@ pub const SQLITE_TESTCTRL_SEEK_COUNT: i32 = 30;
pub const SQLITE_TESTCTRL_TRACEFLAGS: i32 = 31; pub const SQLITE_TESTCTRL_TRACEFLAGS: i32 = 31;
pub const SQLITE_TESTCTRL_TUNE: i32 = 32; pub const SQLITE_TESTCTRL_TUNE: i32 = 32;
pub const SQLITE_TESTCTRL_LOGEST: i32 = 33; pub const SQLITE_TESTCTRL_LOGEST: i32 = 33;
pub const SQLITE_TESTCTRL_LAST: i32 = 33; pub const SQLITE_TESTCTRL_USELONGDOUBLE: i32 = 34;
pub const SQLITE_TESTCTRL_LAST: i32 = 34;
pub const SQLITE_STATUS_MEMORY_USED: i32 = 0; pub const SQLITE_STATUS_MEMORY_USED: i32 = 0;
pub const SQLITE_STATUS_PAGECACHE_USED: i32 = 1; pub const SQLITE_STATUS_PAGECACHE_USED: i32 = 1;
pub const SQLITE_STATUS_PAGECACHE_OVERFLOW: i32 = 2; pub const SQLITE_STATUS_PAGECACHE_OVERFLOW: i32 = 2;
@@ -462,6 +471,7 @@ pub const SQLITE_CHECKPOINT_TRUNCATE: i32 = 3;
pub const SQLITE_VTAB_CONSTRAINT_SUPPORT: i32 = 1; pub const SQLITE_VTAB_CONSTRAINT_SUPPORT: i32 = 1;
pub const SQLITE_VTAB_INNOCUOUS: i32 = 2; pub const SQLITE_VTAB_INNOCUOUS: i32 = 2;
pub const SQLITE_VTAB_DIRECTONLY: i32 = 3; pub const SQLITE_VTAB_DIRECTONLY: i32 = 3;
pub const SQLITE_VTAB_USES_ALL_SCHEMAS: i32 = 4;
pub const SQLITE_ROLLBACK: i32 = 1; pub const SQLITE_ROLLBACK: i32 = 1;
pub const SQLITE_FAIL: i32 = 3; pub const SQLITE_FAIL: i32 = 3;
pub const SQLITE_REPLACE: i32 = 5; pub const SQLITE_REPLACE: i32 = 5;
@@ -471,18 +481,23 @@ pub const SQLITE_SCANSTAT_EST: i32 = 2;
pub const SQLITE_SCANSTAT_NAME: i32 = 3; pub const SQLITE_SCANSTAT_NAME: i32 = 3;
pub const SQLITE_SCANSTAT_EXPLAIN: i32 = 4; pub const SQLITE_SCANSTAT_EXPLAIN: i32 = 4;
pub const SQLITE_SCANSTAT_SELECTID: i32 = 5; pub const SQLITE_SCANSTAT_SELECTID: i32 = 5;
pub const SQLITE_SERIALIZE_NOCOPY: i32 = 1; pub const SQLITE_SCANSTAT_PARENTID: i32 = 6;
pub const SQLITE_DESERIALIZE_FREEONCLOSE: i32 = 1; pub const SQLITE_SCANSTAT_NCYCLE: i32 = 7;
pub const SQLITE_DESERIALIZE_RESIZEABLE: i32 = 2; pub const SQLITE_SCANSTAT_COMPLEX: i32 = 1;
pub const SQLITE_DESERIALIZE_READONLY: i32 = 4; pub const SQLITE_SERIALIZE_NOCOPY: ::std::os::raw::c_uint = 1;
pub const SQLITE_DESERIALIZE_FREEONCLOSE: ::std::os::raw::c_uint = 1;
pub const SQLITE_DESERIALIZE_RESIZEABLE: ::std::os::raw::c_uint = 2;
pub const SQLITE_DESERIALIZE_READONLY: ::std::os::raw::c_uint = 4;
pub const NOT_WITHIN: i32 = 0; pub const NOT_WITHIN: i32 = 0;
pub const PARTLY_WITHIN: i32 = 1; pub const PARTLY_WITHIN: i32 = 1;
pub const FULLY_WITHIN: i32 = 2; pub const FULLY_WITHIN: i32 = 2;
pub const __SQLITESESSION_H_: i32 = 1;
pub const SQLITE_SESSION_OBJCONFIG_SIZE: i32 = 1; pub const SQLITE_SESSION_OBJCONFIG_SIZE: i32 = 1;
pub const SQLITE_SESSION_OBJCONFIG_ROWID: i32 = 2;
pub const SQLITE_CHANGESETSTART_INVERT: i32 = 2; pub const SQLITE_CHANGESETSTART_INVERT: i32 = 2;
pub const SQLITE_CHANGESETAPPLY_NOSAVEPOINT: i32 = 1; pub const SQLITE_CHANGESETAPPLY_NOSAVEPOINT: i32 = 1;
pub const SQLITE_CHANGESETAPPLY_INVERT: i32 = 2; pub const SQLITE_CHANGESETAPPLY_INVERT: i32 = 2;
pub const SQLITE_CHANGESETAPPLY_IGNORENOOP: i32 = 4;
pub const SQLITE_CHANGESETAPPLY_FKNOACTION: i32 = 8;
pub const SQLITE_CHANGESET_DATA: i32 = 1; pub const SQLITE_CHANGESET_DATA: i32 = 1;
pub const SQLITE_CHANGESET_NOTFOUND: i32 = 2; pub const SQLITE_CHANGESET_NOTFOUND: i32 = 2;
pub const SQLITE_CHANGESET_CONFLICT: i32 = 3; pub const SQLITE_CHANGESET_CONFLICT: i32 = 3;
@@ -532,9 +547,6 @@ pub type sqlite3_uint64 = sqlite_uint64;
extern "C" { extern "C" {
pub fn sqlite3_close(arg1: *mut sqlite3) -> ::std::os::raw::c_int; pub fn sqlite3_close(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_close_v2(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
}
pub type sqlite3_callback = ::std::option::Option< pub type sqlite3_callback = ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void, arg1: *mut ::std::os::raw::c_void,
@@ -683,6 +695,7 @@ pub struct sqlite3_mutex {
pub struct sqlite3_api_routines { pub struct sqlite3_api_routines {
_unused: [u8; 0], _unused: [u8; 0],
} }
pub type sqlite3_filename = *const ::std::os::raw::c_char;
pub type sqlite3_syscall_ptr = ::std::option::Option<unsafe extern "C" fn()>; pub type sqlite3_syscall_ptr = ::std::option::Option<unsafe extern "C" fn()>;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@@ -696,7 +709,7 @@ pub struct sqlite3_vfs {
pub xOpen: ::std::option::Option< pub xOpen: ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
arg1: *mut sqlite3_vfs, arg1: *mut sqlite3_vfs,
zName: *const ::std::os::raw::c_char, zName: sqlite3_filename,
arg2: *mut sqlite3_file, arg2: *mut sqlite3_file,
flags: ::std::os::raw::c_int, flags: ::std::os::raw::c_int,
pOutFlags: *mut ::std::os::raw::c_int, pOutFlags: *mut ::std::os::raw::c_int,
@@ -878,10 +891,10 @@ extern "C" {
pub fn sqlite3_interrupt(arg1: *mut sqlite3); pub fn sqlite3_interrupt(arg1: *mut sqlite3);
} }
extern "C" { extern "C" {
pub fn sqlite3_complete(sql: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; pub fn sqlite3_is_interrupted(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
} }
extern "C" { extern "C" {
pub fn sqlite3_complete16(sql: *const ::std::os::raw::c_void) -> ::std::os::raw::c_int; pub fn sqlite3_complete(sql: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
} }
extern "C" { extern "C" {
pub fn sqlite3_busy_handler( pub fn sqlite3_busy_handler(
@@ -1031,12 +1044,6 @@ extern "C" {
ppDb: *mut *mut sqlite3, ppDb: *mut *mut sqlite3,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_open16(
filename: *const ::std::os::raw::c_void,
ppDb: *mut *mut sqlite3,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_open_v2( pub fn sqlite3_open_v2(
filename: *const ::std::os::raw::c_char, filename: *const ::std::os::raw::c_char,
@@ -1047,44 +1054,38 @@ extern "C" {
} }
extern "C" { extern "C" {
pub fn sqlite3_uri_parameter( pub fn sqlite3_uri_parameter(
zFilename: *const ::std::os::raw::c_char, z: sqlite3_filename,
zParam: *const ::std::os::raw::c_char, zParam: *const ::std::os::raw::c_char,
) -> *const ::std::os::raw::c_char; ) -> *const ::std::os::raw::c_char;
} }
extern "C" { extern "C" {
pub fn sqlite3_uri_boolean( pub fn sqlite3_uri_boolean(
zFile: *const ::std::os::raw::c_char, z: sqlite3_filename,
zParam: *const ::std::os::raw::c_char, zParam: *const ::std::os::raw::c_char,
bDefault: ::std::os::raw::c_int, bDefault: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" { extern "C" {
pub fn sqlite3_uri_int64( pub fn sqlite3_uri_int64(
arg1: *const ::std::os::raw::c_char, arg1: sqlite3_filename,
arg2: *const ::std::os::raw::c_char, arg2: *const ::std::os::raw::c_char,
arg3: sqlite3_int64, arg3: sqlite3_int64,
) -> sqlite3_int64; ) -> sqlite3_int64;
} }
extern "C" { extern "C" {
pub fn sqlite3_uri_key( pub fn sqlite3_uri_key(
zFilename: *const ::std::os::raw::c_char, z: sqlite3_filename,
N: ::std::os::raw::c_int, N: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_char; ) -> *const ::std::os::raw::c_char;
} }
extern "C" { extern "C" {
pub fn sqlite3_filename_database( pub fn sqlite3_filename_database(arg1: sqlite3_filename) -> *const ::std::os::raw::c_char;
arg1: *const ::std::os::raw::c_char,
) -> *const ::std::os::raw::c_char;
} }
extern "C" { extern "C" {
pub fn sqlite3_filename_journal( pub fn sqlite3_filename_journal(arg1: sqlite3_filename) -> *const ::std::os::raw::c_char;
arg1: *const ::std::os::raw::c_char,
) -> *const ::std::os::raw::c_char;
} }
extern "C" { extern "C" {
pub fn sqlite3_filename_wal( pub fn sqlite3_filename_wal(arg1: sqlite3_filename) -> *const ::std::os::raw::c_char;
arg1: *const ::std::os::raw::c_char,
) -> *const ::std::os::raw::c_char;
} }
extern "C" { extern "C" {
pub fn sqlite3_database_file_object(arg1: *const ::std::os::raw::c_char) -> *mut sqlite3_file; pub fn sqlite3_database_file_object(arg1: *const ::std::os::raw::c_char) -> *mut sqlite3_file;
@@ -1096,10 +1097,10 @@ extern "C" {
zWal: *const ::std::os::raw::c_char, zWal: *const ::std::os::raw::c_char,
nParam: ::std::os::raw::c_int, nParam: ::std::os::raw::c_int,
azParam: *mut *const ::std::os::raw::c_char, azParam: *mut *const ::std::os::raw::c_char,
) -> *mut ::std::os::raw::c_char; ) -> sqlite3_filename;
} }
extern "C" { extern "C" {
pub fn sqlite3_free_filename(arg1: *mut ::std::os::raw::c_char); pub fn sqlite3_free_filename(arg1: sqlite3_filename);
} }
extern "C" { extern "C" {
pub fn sqlite3_errcode(db: *mut sqlite3) -> ::std::os::raw::c_int; pub fn sqlite3_errcode(db: *mut sqlite3) -> ::std::os::raw::c_int;
@@ -1110,9 +1111,6 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_errmsg(arg1: *mut sqlite3) -> *const ::std::os::raw::c_char; pub fn sqlite3_errmsg(arg1: *mut sqlite3) -> *const ::std::os::raw::c_char;
} }
extern "C" {
pub fn sqlite3_errmsg16(arg1: *mut sqlite3) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_errstr(arg1: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; pub fn sqlite3_errstr(arg1: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char;
} }
@@ -1131,15 +1129,6 @@ extern "C" {
newVal: ::std::os::raw::c_int, newVal: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_prepare(
db: *mut sqlite3,
zSql: *const ::std::os::raw::c_char,
nByte: ::std::os::raw::c_int,
ppStmt: *mut *mut sqlite3_stmt,
pzTail: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_prepare_v2( pub fn sqlite3_prepare_v2(
db: *mut sqlite3, db: *mut sqlite3,
@@ -1159,34 +1148,6 @@ extern "C" {
pzTail: *mut *const ::std::os::raw::c_char, pzTail: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_prepare16(
db: *mut sqlite3,
zSql: *const ::std::os::raw::c_void,
nByte: ::std::os::raw::c_int,
ppStmt: *mut *mut sqlite3_stmt,
pzTail: *mut *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_prepare16_v2(
db: *mut sqlite3,
zSql: *const ::std::os::raw::c_void,
nByte: ::std::os::raw::c_int,
ppStmt: *mut *mut sqlite3_stmt,
pzTail: *mut *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_prepare16_v3(
db: *mut sqlite3,
zSql: *const ::std::os::raw::c_void,
nByte: ::std::os::raw::c_int,
prepFlags: ::std::os::raw::c_uint,
ppStmt: *mut *mut sqlite3_stmt,
pzTail: *mut *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_sql(pStmt: *mut sqlite3_stmt) -> *const ::std::os::raw::c_char; pub fn sqlite3_sql(pStmt: *mut sqlite3_stmt) -> *const ::std::os::raw::c_char;
} }
@@ -1199,6 +1160,12 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_stmt_isexplain(pStmt: *mut sqlite3_stmt) -> ::std::os::raw::c_int; pub fn sqlite3_stmt_isexplain(pStmt: *mut sqlite3_stmt) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_stmt_explain(
pStmt: *mut sqlite3_stmt,
eMode: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_stmt_busy(arg1: *mut sqlite3_stmt) -> ::std::os::raw::c_int; pub fn sqlite3_stmt_busy(arg1: *mut sqlite3_stmt) -> ::std::os::raw::c_int;
} }
@@ -1266,15 +1233,6 @@ extern "C" {
arg5: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>, arg5: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_bind_text16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_bind_text64( pub fn sqlite3_bind_text64(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
@@ -1342,60 +1300,30 @@ extern "C" {
N: ::std::os::raw::c_int, N: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_char; ) -> *const ::std::os::raw::c_char;
} }
extern "C" {
pub fn sqlite3_column_name16(
arg1: *mut sqlite3_stmt,
N: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_column_database_name( pub fn sqlite3_column_database_name(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int, arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_char; ) -> *const ::std::os::raw::c_char;
} }
extern "C" {
pub fn sqlite3_column_database_name16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_column_table_name( pub fn sqlite3_column_table_name(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int, arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_char; ) -> *const ::std::os::raw::c_char;
} }
extern "C" {
pub fn sqlite3_column_table_name16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_column_origin_name( pub fn sqlite3_column_origin_name(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int, arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_char; ) -> *const ::std::os::raw::c_char;
} }
extern "C" {
pub fn sqlite3_column_origin_name16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_column_decltype( pub fn sqlite3_column_decltype(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int, arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_char; ) -> *const ::std::os::raw::c_char;
} }
extern "C" {
pub fn sqlite3_column_decltype16(
arg1: *mut sqlite3_stmt,
arg2: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_step(arg1: *mut sqlite3_stmt) -> ::std::os::raw::c_int; pub fn sqlite3_step(arg1: *mut sqlite3_stmt) -> ::std::os::raw::c_int;
} }
@@ -1429,12 +1357,6 @@ extern "C" {
iCol: ::std::os::raw::c_int, iCol: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_uchar; ) -> *const ::std::os::raw::c_uchar;
} }
extern "C" {
pub fn sqlite3_column_text16(
arg1: *mut sqlite3_stmt,
iCol: ::std::os::raw::c_int,
) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_column_value( pub fn sqlite3_column_value(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
@@ -1447,12 +1369,6 @@ extern "C" {
iCol: ::std::os::raw::c_int, iCol: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_column_bytes16(
arg1: *mut sqlite3_stmt,
iCol: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_column_type( pub fn sqlite3_column_type(
arg1: *mut sqlite3_stmt, arg1: *mut sqlite3_stmt,
@@ -1465,54 +1381,6 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_reset(pStmt: *mut sqlite3_stmt) -> ::std::os::raw::c_int; pub fn sqlite3_reset(pStmt: *mut sqlite3_stmt) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_create_function(
db: *mut sqlite3,
zFunctionName: *const ::std::os::raw::c_char,
nArg: ::std::os::raw::c_int,
eTextRep: ::std::os::raw::c_int,
pApp: *mut ::std::os::raw::c_void,
xFunc: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xStep: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xFinal: ::std::option::Option<unsafe extern "C" fn(arg1: *mut sqlite3_context)>,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn sqlite3_create_function16(
db: *mut sqlite3,
zFunctionName: *const ::std::os::raw::c_void,
nArg: ::std::os::raw::c_int,
eTextRep: ::std::os::raw::c_int,
pApp: *mut ::std::os::raw::c_void,
xFunc: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xStep: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_context,
arg2: ::std::os::raw::c_int,
arg3: *mut *mut sqlite3_value,
),
>,
xFinal: ::std::option::Option<unsafe extern "C" fn(arg1: *mut sqlite3_context)>,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_create_function_v2( pub fn sqlite3_create_function_v2(
db: *mut sqlite3, db: *mut sqlite3,
@@ -1616,21 +1484,9 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_value_text(arg1: *mut sqlite3_value) -> *const ::std::os::raw::c_uchar; pub fn sqlite3_value_text(arg1: *mut sqlite3_value) -> *const ::std::os::raw::c_uchar;
} }
extern "C" {
pub fn sqlite3_value_text16(arg1: *mut sqlite3_value) -> *const ::std::os::raw::c_void;
}
extern "C" {
pub fn sqlite3_value_text16le(arg1: *mut sqlite3_value) -> *const ::std::os::raw::c_void;
}
extern "C" {
pub fn sqlite3_value_text16be(arg1: *mut sqlite3_value) -> *const ::std::os::raw::c_void;
}
extern "C" { extern "C" {
pub fn sqlite3_value_bytes(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int; pub fn sqlite3_value_bytes(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_value_bytes16(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_value_type(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int; pub fn sqlite3_value_type(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int;
} }
@@ -1643,6 +1499,9 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_value_frombind(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int; pub fn sqlite3_value_frombind(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_value_encoding(arg1: *mut sqlite3_value) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_value_subtype(arg1: *mut sqlite3_value) -> ::std::os::raw::c_uint; pub fn sqlite3_value_subtype(arg1: *mut sqlite3_value) -> ::std::os::raw::c_uint;
} }
@@ -1678,6 +1537,20 @@ extern "C" {
arg3: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>, arg3: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
); );
} }
extern "C" {
pub fn sqlite3_get_clientdata(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
) -> *mut ::std::os::raw::c_void;
}
extern "C" {
pub fn sqlite3_set_clientdata(
arg1: *mut sqlite3,
arg2: *const ::std::os::raw::c_char,
arg3: *mut ::std::os::raw::c_void,
arg4: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int;
}
pub type sqlite3_destructor_type = pub type sqlite3_destructor_type =
::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>; ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>;
extern "C" { extern "C" {
@@ -1706,13 +1579,6 @@ extern "C" {
arg3: ::std::os::raw::c_int, arg3: ::std::os::raw::c_int,
); );
} }
extern "C" {
pub fn sqlite3_result_error16(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
);
}
extern "C" { extern "C" {
pub fn sqlite3_result_error_toobig(arg1: *mut sqlite3_context); pub fn sqlite3_result_error_toobig(arg1: *mut sqlite3_context);
} }
@@ -1748,30 +1614,6 @@ extern "C" {
encoding: ::std::os::raw::c_uchar, encoding: ::std::os::raw::c_uchar,
); );
} }
extern "C" {
pub fn sqlite3_result_text16(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
);
}
extern "C" {
pub fn sqlite3_result_text16le(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
);
}
extern "C" {
pub fn sqlite3_result_text16be(
arg1: *mut sqlite3_context,
arg2: *const ::std::os::raw::c_void,
arg3: ::std::os::raw::c_int,
arg4: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
);
}
extern "C" { extern "C" {
pub fn sqlite3_result_value(arg1: *mut sqlite3_context, arg2: *mut sqlite3_value); pub fn sqlite3_result_value(arg1: *mut sqlite3_context, arg2: *mut sqlite3_value);
} }
@@ -1795,23 +1637,6 @@ extern "C" {
extern "C" { extern "C" {
pub fn sqlite3_result_subtype(arg1: *mut sqlite3_context, arg2: ::std::os::raw::c_uint); pub fn sqlite3_result_subtype(arg1: *mut sqlite3_context, arg2: ::std::os::raw::c_uint);
} }
extern "C" {
pub fn sqlite3_create_collation(
arg1: *mut sqlite3,
zName: *const ::std::os::raw::c_char,
eTextRep: ::std::os::raw::c_int,
pArg: *mut ::std::os::raw::c_void,
xCompare: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_create_collation_v2( pub fn sqlite3_create_collation_v2(
arg1: *mut sqlite3, arg1: *mut sqlite3,
@@ -1830,23 +1655,6 @@ extern "C" {
xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>, xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_create_collation16(
arg1: *mut sqlite3,
zName: *const ::std::os::raw::c_void,
eTextRep: ::std::os::raw::c_int,
pArg: *mut ::std::os::raw::c_void,
xCompare: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
arg4: ::std::os::raw::c_int,
arg5: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_collation_needed( pub fn sqlite3_collation_needed(
arg1: *mut sqlite3, arg1: *mut sqlite3,
@@ -1861,20 +1669,6 @@ extern "C" {
>, >,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_collation_needed16(
arg1: *mut sqlite3,
arg2: *mut ::std::os::raw::c_void,
arg3: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut ::std::os::raw::c_void,
arg2: *mut sqlite3,
eTextRep: ::std::os::raw::c_int,
arg3: *const ::std::os::raw::c_void,
),
>,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_key( pub fn sqlite3_key(
db: *mut sqlite3, db: *mut sqlite3,
@@ -1929,12 +1723,6 @@ extern "C" {
zValue: *const ::std::os::raw::c_char, zValue: *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3_win32_set_directory16(
type_: ::std::os::raw::c_ulong,
zValue: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_get_autocommit(arg1: *mut sqlite3) -> ::std::os::raw::c_int; pub fn sqlite3_get_autocommit(arg1: *mut sqlite3) -> ::std::os::raw::c_int;
} }
@@ -1951,7 +1739,7 @@ extern "C" {
pub fn sqlite3_db_filename( pub fn sqlite3_db_filename(
db: *mut sqlite3, db: *mut sqlite3,
zDbName: *const ::std::os::raw::c_char, zDbName: *const ::std::os::raw::c_char,
) -> *const ::std::os::raw::c_char; ) -> sqlite3_filename;
} }
extern "C" { extern "C" {
pub fn sqlite3_db_readonly( pub fn sqlite3_db_readonly(
@@ -2198,6 +1986,15 @@ pub struct sqlite3_module {
pub xShadowName: ::std::option::Option< pub xShadowName: ::std::option::Option<
unsafe extern "C" fn(arg1: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int, unsafe extern "C" fn(arg1: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int,
>, >,
pub xIntegrity: ::std::option::Option<
unsafe extern "C" fn(
pVTab: *mut sqlite3_vtab,
zSchema: *const ::std::os::raw::c_char,
zTabName: *const ::std::os::raw::c_char,
mFlags: ::std::os::raw::c_int,
pzErr: *mut *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int,
>,
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@@ -2236,14 +2033,6 @@ pub struct sqlite3_index_constraint_usage {
pub argvIndex: ::std::os::raw::c_int, pub argvIndex: ::std::os::raw::c_int,
pub omit: ::std::os::raw::c_uchar, pub omit: ::std::os::raw::c_uchar,
} }
extern "C" {
pub fn sqlite3_create_module(
db: *mut sqlite3,
zName: *const ::std::os::raw::c_char,
p: *const sqlite3_module,
pClientData: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3_create_module_v2( pub fn sqlite3_create_module_v2(
db: *mut sqlite3, db: *mut sqlite3,
@@ -2759,6 +2548,15 @@ extern "C" {
pOut: *mut ::std::os::raw::c_void, pOut: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
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" { extern "C" {
pub fn sqlite3_stmt_scanstatus_reset(arg1: *mut sqlite3_stmt); pub fn sqlite3_stmt_scanstatus_reset(arg1: *mut sqlite3_stmt);
} }
@@ -3086,6 +2884,16 @@ extern "C" {
ppOut: *mut *mut ::std::os::raw::c_void, ppOut: *mut *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3changeset_upgrade(
db: *mut sqlite3,
zDb: *const ::std::os::raw::c_char,
nIn: ::std::os::raw::c_int,
pIn: *const ::std::os::raw::c_void,
pnOut: *mut ::std::os::raw::c_int,
ppOut: *mut *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int;
}
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sqlite3_changegroup { pub struct sqlite3_changegroup {
@@ -3094,6 +2902,13 @@ pub struct sqlite3_changegroup {
extern "C" { extern "C" {
pub fn sqlite3changegroup_new(pp: *mut *mut sqlite3_changegroup) -> ::std::os::raw::c_int; pub fn sqlite3changegroup_new(pp: *mut *mut sqlite3_changegroup) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3changegroup_schema(
arg1: *mut sqlite3_changegroup,
arg2: *mut sqlite3,
zDb: *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3changegroup_add( pub fn sqlite3changegroup_add(
arg1: *mut sqlite3_changegroup, arg1: *mut sqlite3_changegroup,
@@ -3101,6 +2916,12 @@ extern "C" {
pData: *mut ::std::os::raw::c_void, pData: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" {
pub fn sqlite3changegroup_add_change(
arg1: *mut sqlite3_changegroup,
arg2: *mut sqlite3_changeset_iter,
) -> ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn sqlite3changegroup_output( pub fn sqlite3changegroup_output(
arg1: *mut sqlite3_changegroup, arg1: *mut sqlite3_changegroup,
@@ -3555,6 +3376,24 @@ pub struct Fts5ExtensionApi {
piCol: *mut ::std::os::raw::c_int, piCol: *mut ::std::os::raw::c_int,
), ),
>, >,
pub xQueryToken: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut Fts5Context,
iPhrase: ::std::os::raw::c_int,
iToken: ::std::os::raw::c_int,
ppToken: *mut *const ::std::os::raw::c_char,
pnToken: *mut ::std::os::raw::c_int,
) -> ::std::os::raw::c_int,
>,
pub xInstToken: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut Fts5Context,
iIdx: ::std::os::raw::c_int,
iToken: ::std::os::raw::c_int,
arg2: *mut *const ::std::os::raw::c_char,
arg3: *mut ::std::os::raw::c_int,
) -> ::std::os::raw::c_int,
>,
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@@ -3601,7 +3440,7 @@ pub struct fts5_api {
unsafe extern "C" fn( unsafe extern "C" fn(
pApi: *mut fts5_api, pApi: *mut fts5_api,
zName: *const ::std::os::raw::c_char, zName: *const ::std::os::raw::c_char,
pContext: *mut ::std::os::raw::c_void, pUserData: *mut ::std::os::raw::c_void,
pTokenizer: *mut fts5_tokenizer, pTokenizer: *mut fts5_tokenizer,
xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>, xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
@@ -3610,7 +3449,7 @@ pub struct fts5_api {
unsafe extern "C" fn( unsafe extern "C" fn(
pApi: *mut fts5_api, pApi: *mut fts5_api,
zName: *const ::std::os::raw::c_char, zName: *const ::std::os::raw::c_char,
ppContext: *mut *mut ::std::os::raw::c_void, ppUserData: *mut *mut ::std::os::raw::c_void,
pTokenizer: *mut fts5_tokenizer, pTokenizer: *mut fts5_tokenizer,
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,
>, >,
@@ -3618,7 +3457,7 @@ pub struct fts5_api {
unsafe extern "C" fn( unsafe extern "C" fn(
pApi: *mut fts5_api, pApi: *mut fts5_api,
zName: *const ::std::os::raw::c_char, zName: *const ::std::os::raw::c_char,
pContext: *mut ::std::os::raw::c_void, pUserData: *mut ::std::os::raw::c_void,
xFunction: fts5_extension_function, xFunction: fts5_extension_function,
xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>, xDestroy: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
) -> ::std::os::raw::c_int, ) -> ::std::os::raw::c_int,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -331,9 +331,9 @@ struct sqlite3_api_routines {
const char *(*filename_journal)(const char*); const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*); const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */ /* Version 3.32.0 and later */
char *(*create_filename)(const char*,const char*,const char*, const char *(*create_filename)(const char*,const char*,const char*,
int,const char**); int,const char**);
void (*free_filename)(char*); void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*); sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */ /* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*); int (*txn_state)(sqlite3*,const char*);
@@ -357,6 +357,15 @@ struct sqlite3_api_routines {
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*, unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int); unsigned int);
const char *(*db_name)(sqlite3*,int); 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*);
/* Version 3.43.0 and later */
int (*stmt_explain)(sqlite3_stmt*,int);
/* Version 3.44.0 and later */
void *(*get_clientdata)(sqlite3*,const char*);
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
}; };
/* /*
@@ -681,6 +690,15 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_serialize sqlite3_api->serialize #define sqlite3_serialize sqlite3_api->serialize
#endif #endif
#define sqlite3_db_name sqlite3_api->db_name #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
/* Version 3.43.0 and later */
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
/* Version 3.44.0 and later */
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.45.0" #define SQLITE_VERSION "3.48.0"
#define SQLITE_VERSION_NUMBER 3045000 #define SQLITE_VERSION_NUMBER 3048000
#define SQLITE_SOURCE_ID "2024-01-15 17:01:13 1066602b2b1976fe58b5150777cced894af17c803e068f5918390d6915b46e1d" #define SQLITE_SOURCE_ID "2025-01-14 11:05:00 d2fe6b05f38d9d7cd78c5d252e99ac59f1aea071d669830c1ffe4e8966e84010"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers
@@ -420,6 +420,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into ** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not dereference the arrays or string pointers
** passed as the 3rd and 4th callback parameters after it returns.
** </ul> ** </ul>
*/ */
SQLITE_API int sqlite3_exec( SQLITE_API int sqlite3_exec(
@@ -650,6 +652,13 @@ SQLITE_API int sqlite3_exec(
** filesystem supports doing multiple write operations atomically when those ** filesystem supports doing multiple write operations atomically when those
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
**
** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
** from the database file in amounts that are not a multiple of the
** page size and that do not begin at a page boundary. Without this
** property, SQLite is careful to only do full-page reads and write
** on aligned pages, with the one exception that it will do a sub-page
** read of the first page to access the database header.
*/ */
#define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002 #define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -666,6 +675,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
/* /*
** CAPI3REF: File Locking Levels ** CAPI3REF: File Locking Levels
@@ -762,16 +772,16 @@ struct sqlite3_file {
** </ul> ** </ul>
** xLock() upgrades the database file lock. In other words, xLock() moves the ** xLock() upgrades the database file lock. In other words, xLock() moves the
** database file lock in the direction NONE toward EXCLUSIVE. The argument to ** database file lock in the direction NONE toward EXCLUSIVE. The argument to
** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never ** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** SQLITE_LOCK_NONE. If the database file lock is already at or above the ** SQLITE_LOCK_NONE. If the database file lock is already at or above the
** requested lock, then the call to xLock() is a no-op. ** requested lock, then the call to xLock() is a no-op.
** xUnlock() downgrades the database file lock to either SHARED or NONE. ** xUnlock() downgrades the database file lock to either SHARED or NONE.
* If the lock is already at or below the requested lock state, then the call ** If the lock is already at or below the requested lock state, then the call
** to xUnlock() is a no-op. ** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection, ** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED, ** either in this process or in some other process, is holding a RESERVED,
** PENDING, or EXCLUSIVE lock on the file. It returns true ** PENDING, or EXCLUSIVE lock on the file. It returns, via its output
** if such a lock exists and false otherwise. ** pointer parameter, true if such a lock exists and false otherwise.
** **
** The xFileControl() method is a generic interface that allows custom ** The xFileControl() method is a generic interface that allows custom
** VFS implementations to directly control an open file using the ** VFS implementations to directly control an open file using the
@@ -812,6 +822,7 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE] ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE] ** <li> [SQLITE_IOCAP_IMMUTABLE]
** <li> [SQLITE_IOCAP_BATCH_ATOMIC] ** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
** <li> [SQLITE_IOCAP_SUBPAGE_READ]
** </ul> ** </ul>
** **
** The SQLITE_IOCAP_ATOMIC property means that all writes of ** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1089,6 +1100,11 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing ** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined. ** and only needs to be supported when SQLITE_TEST is defined.
** **
** <li>[[SQLITE_FCNTL_NULL_IO]]
** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
** or file handle for the [sqlite3_file] object such that it will no longer
** read or write to the database file.
**
** <li>[[SQLITE_FCNTL_WAL_BLOCK]] ** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
** be advantageous to block on the next WAL lock if the lock is not immediately ** be advantageous to block on the next WAL lock if the lock is not immediately
@@ -1242,6 +1258,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_CKSM_FILE 41
#define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_RESET_CACHE 42
#define SQLITE_FCNTL_NULL_IO 43
/* deprecated names */ /* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -2141,6 +2158,22 @@ struct sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined ** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824. ** compile-time option is not set, then the default maximum is 1073741824.
**
** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
** defaults to on. This configuration option queries the current setting or
** changes the setting to off or on. The argument is a pointer to an integer.
** If that integer initially holds a value of 1, then the ability for VIEWs to
** have ROWIDs is activated. If the integer initially holds zero, then the
** ability is deactivated. Any other initial value for the integer leaves the
** setting unchanged. After changes, if any, the integer is written with
** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
** recommended case) then the integer is always filled with zero, regardless
** if its initial value.
** </dl> ** </dl>
*/ */
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2172,6 +2205,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/* /*
** CAPI3REF: Database Connection Configuration Options ** CAPI3REF: Database Connection Configuration Options
@@ -2603,10 +2637,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
** deleted by the most recently completed INSERT, UPDATE or DELETE ** deleted by the most recently completed INSERT, UPDATE or DELETE
** statement on the database connection specified by the only parameter. ** statement on the database connection specified by the only parameter.
** The two functions are identical except for the type of the return value ** The two functions are identical except for the type of the return value
** and that if the number of rows modified by the most recent INSERT, UPDATE ** and that if the number of rows modified by the most recent INSERT, UPDATE,
** or DELETE is greater than the maximum value supported by type "int", then ** or DELETE is greater than the maximum value supported by type "int", then
** the return value of sqlite3_changes() is undefined. ^Executing any other ** the return value of sqlite3_changes() is undefined. ^Executing any other
** type of SQL statement does not modify the value returned by these functions. ** type of SQL statement does not modify the value returned by these functions.
** For the purposes of this interface, a CREATE TABLE AS SELECT statement
** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
** added to the new table by the CREATE TABLE AS SELECT statement are not
** counted.
** **
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
@@ -3286,8 +3324,8 @@ SQLITE_API int sqlite3_set_authorizer(
#define SQLITE_RECURSIVE 33 /* NULL NULL */ #define SQLITE_RECURSIVE 33 /* NULL NULL */
/* /*
** CAPI3REF: Tracing And Profiling Functions ** CAPI3REF: Deprecated Tracing And Profiling Functions
** METHOD: sqlite3 ** DEPRECATED
** **
** These routines are deprecated. Use the [sqlite3_trace_v2()] interface ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
** instead of the routines described here. ** instead of the routines described here.
@@ -3551,8 +3589,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** **
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt> ** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
** <dd>The database connection comes up in "extended result code mode". ** <dd>The database connection comes up in "extended result code mode".
** In other words, the database behaves has if ** In other words, the database behaves as if
** [sqlite3_extended_result_codes(db,1)] where called on the database ** [sqlite3_extended_result_codes(db,1)] were called on the database
** connection as soon as the connection is created. In addition to setting ** connection as soon as the connection is created. In addition to setting
** the extended result code mode, this flag also causes [sqlite3_open_v2()] ** the extended result code mode, this flag also causes [sqlite3_open_v2()]
** to return an extended result code.</dd> ** to return an extended result code.</dd>
@@ -4166,11 +4204,22 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler ** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
** to return an error (error code SQLITE_ERROR) if the statement uses ** to return an error (error code SQLITE_ERROR) if the statement uses
** any virtual tables. ** any virtual tables.
**
** [[SQLITE_PREPARE_DONT_LOG]] <dt>SQLITE_PREPARE_DONT_LOG</dt>
** <dd>The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler
** errors from being sent to the error log defined by
** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test
** compiles to see if some SQL syntax is well-formed, without generating
** messages on the global error log when it is not. If the test compile
** fails, the sqlite3_prepare_v3() call returns the same error indications
** with or without this flag; it just omits the call to [sqlite3_log()] that
** logs the error.
** </dl> ** </dl>
*/ */
#define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_PERSISTENT 0x01
#define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NORMALIZE 0x02
#define SQLITE_PREPARE_NO_VTAB 0x04 #define SQLITE_PREPARE_NO_VTAB 0x04
#define SQLITE_PREPARE_DONT_LOG 0x10
/* /*
** CAPI3REF: Compiling An SQL Statement ** CAPI3REF: Compiling An SQL Statement
@@ -4203,13 +4252,17 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** and sqlite3_prepare16_v3() use UTF-16. ** and sqlite3_prepare16_v3() use UTF-16.
** **
** ^If the nByte argument is negative, then zSql is read up to the ** ^If the nByte argument is negative, then zSql is read up to the
** first zero terminator. ^If nByte is positive, then it is the ** first zero terminator. ^If nByte is positive, then it is the maximum
** number of bytes read from zSql. ^If nByte is zero, then no prepared ** number of bytes read from zSql. When nByte is positive, zSql is read
** up to the first zero terminator or until the nByte bytes have been read,
** whichever comes first. ^If nByte is zero, then no prepared
** statement is generated. ** statement is generated.
** If the caller knows that the supplied string is nul-terminated, then ** If the caller knows that the supplied string is nul-terminated, then
** there is a small performance advantage to passing an nByte parameter that ** there is a small performance advantage to passing an nByte parameter that
** is the number of bytes in the input string <i>including</i> ** is the number of bytes in the input string <i>including</i>
** the nul-terminator. ** the nul-terminator.
** Note that nByte measure the length of the input in bytes, not
** characters, even for the UTF-16 interfaces.
** **
** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only ** past the end of the first SQL statement in zSql. These routines only
@@ -5580,7 +5633,7 @@ SQLITE_API int sqlite3_create_window_function(
** This flag instructs SQLite to omit some corner-case optimizations that ** This flag instructs SQLite to omit some corner-case optimizations that
** might disrupt the operation of the [sqlite3_value_subtype()] function, ** might disrupt the operation of the [sqlite3_value_subtype()] function,
** causing it to return zero rather than the correct subtype(). ** causing it to return zero rather than the correct subtype().
** SQL functions that invokes [sqlite3_value_subtype()] should have this ** All SQL functions that invoke [sqlite3_value_subtype()] should have this
** property. If the SQLITE_SUBTYPE property is omitted, then the return ** property. If the SQLITE_SUBTYPE property is omitted, then the return
** value from [sqlite3_value_subtype()] might sometimes be zero even though ** value from [sqlite3_value_subtype()] might sometimes be zero even though
** a non-zero subtype was specified by the function argument expression. ** a non-zero subtype was specified by the function argument expression.
@@ -5596,6 +5649,15 @@ SQLITE_API int sqlite3_create_window_function(
** [sqlite3_result_subtype()] should avoid setting this property, as the ** [sqlite3_result_subtype()] should avoid setting this property, as the
** purpose of this property is to disable certain optimizations that are ** purpose of this property is to disable certain optimizations that are
** incompatible with subtypes. ** incompatible with subtypes.
**
** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
** that internally orders the values provided to the first argument. The
** ordered-set aggregate SQL notation with a single ORDER BY term can be
** used to invoke this function. If the ordered-set aggregate notation is
** used on a function that lacks this flag, then an error is raised. Note
** that the ordered-set aggregate syntax is only available if SQLite is
** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
** </dd> ** </dd>
** </dl> ** </dl>
*/ */
@@ -5604,6 +5666,7 @@ SQLITE_API int sqlite3_create_window_function(
#define SQLITE_SUBTYPE 0x000100000 #define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_INNOCUOUS 0x000200000
#define SQLITE_RESULT_SUBTYPE 0x001000000 #define SQLITE_RESULT_SUBTYPE 0x001000000
#define SQLITE_SELFORDER1 0x002000000
/* /*
** CAPI3REF: Deprecated Functions ** CAPI3REF: Deprecated Functions
@@ -5801,7 +5864,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
** one SQL function to another. Use the [sqlite3_result_subtype()] ** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function. ** routine to set the subtype for the return value of an SQL function.
** **
** Every [application-defined SQL function] that invoke this interface ** Every [application-defined SQL function] that invokes this interface
** should include the [SQLITE_SUBTYPE] property in the text ** should include the [SQLITE_SUBTYPE] property in the text
** encoding argument when the function is [sqlite3_create_function|registered]. ** encoding argument when the function is [sqlite3_create_function|registered].
** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() ** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype()
@@ -6868,6 +6931,12 @@ SQLITE_API int sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future ** The exceptions defined in this paragraph might change in a future
** release of SQLite. ** release of SQLite.
** **
** Whether the update hook is invoked before or after the
** corresponding change is currently unspecified and may differ
** depending on the type of change. Do not rely on the order of the
** hook call with regards to the final result of the operation which
** triggers the hook.
**
** The update hook implementation must not do anything that will modify ** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions ** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the ** to modify the database connection must be deferred until after the
@@ -7402,9 +7471,11 @@ struct sqlite3_module {
** will be returned by the strategy. ** will be returned by the strategy.
** **
** The xBestIndex method may optionally populate the idxFlags field with a ** The xBestIndex method may optionally populate the idxFlags field with a
** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - ** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite ** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
** assumes that the strategy may visit at most one row. ** output to show the idxNum has hex instead of as decimal. Another flag is
** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
** return at most one row.
** **
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
** SQLite also assumes that if a call to the xUpdate() method is made as ** SQLite also assumes that if a call to the xUpdate() method is made as
@@ -7468,7 +7539,9 @@ struct sqlite3_index_info {
** [sqlite3_index_info].idxFlags field to some combination of ** [sqlite3_index_info].idxFlags field to some combination of
** these bits. ** these bits.
*/ */
#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ #define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
/* in EXPLAIN QUERY PLAN */
/* /*
** CAPI3REF: Virtual Table Constraint Operator Codes ** CAPI3REF: Virtual Table Constraint Operator Codes
@@ -8305,6 +8378,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
#define SQLITE_TESTCTRL_GETOPT 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
@@ -8324,7 +8398,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_LOGEST 33
#define SQLITE_TESTCTRL_USELONGDOUBLE 34 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/* /*
@@ -8338,7 +8412,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
** The sqlite3_keyword_count() interface returns the number of distinct ** The sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite. ** keywords understood by SQLite.
** **
** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and ** The sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number ** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not ** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns ** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns
@@ -9300,6 +9374,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** APIs are not strictly speaking threadsafe. If they are invoked at the ** APIs are not strictly speaking threadsafe. If they are invoked at the
** same time as another thread is invoking sqlite3_backup_step() it is ** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values. ** possible that they return invalid values.
**
** <b>Alternatives To Using The Backup API</b>
**
** Other techniques for safely creating a consistent backup of an SQLite
** database include:
**
** <ul>
** <li> The [VACUUM INTO] command.
** <li> The [sqlite3_rsync] utility program.
** </ul>
*/ */
SQLITE_API sqlite3_backup *sqlite3_backup_init( SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */ sqlite3 *pDest, /* Destination database handle */
@@ -9917,24 +10001,45 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
** <li value="2"><p> ** <li value="2"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 2, that means ** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular ** that the query planner does not need the rows returned in any particular
** order, as long as rows with the same values in all "aOrderBy" columns ** order, as long as rows with the same values in all columns identified
** are adjacent.)^ ^(Furthermore, only a single row for each particular ** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows
** combination of values in the columns identified by the "aOrderBy" field ** contain the same values for all columns identified by "colUsed", all but
** needs to be returned.)^ ^It is always ok for two or more rows with the same ** one such row may optionally be omitted from the result.)^
** values in all "aOrderBy" columns to be returned, as long as all such rows ** The virtual table is not required to omit rows that are duplicates
** are adjacent. ^The virtual table may, if it chooses, omit extra rows ** over the "colUsed" columns, but if the virtual table can do that without
** that have the same value for all columns identified by "aOrderBy". ** too much extra effort, it could potentially help the query to run faster.
** ^However omitting the extra rows is optional.
** This mode is used for a DISTINCT query. ** This mode is used for a DISTINCT query.
** <li value="3"><p> ** <li value="3"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 3, that means ** ^(If the sqlite3_vtab_distinct() interface returns 3, that means the
** that the query planner needs only distinct rows but it does need the ** virtual table must return rows in the order defined by "aOrderBy" as
** rows to be sorted.)^ ^The virtual table implementation is free to omit ** if the sqlite3_vtab_distinct() interface had returned 0. However if
** rows that are identical in all aOrderBy columns, if it wants to, but ** two or more rows in the result have the same values for all columns
** it is not required to omit any rows. This mode is used for queries ** identified by "colUsed", then all but one such row may optionally be
** omitted.)^ Like when the return value is 2, the virtual table
** is not required to omit rows that are duplicates over the "colUsed"
** columns, but if the virtual table can do that without
** too much extra effort, it could potentially help the query to run faster.
** This mode is used for queries
** that have both DISTINCT and ORDER BY clauses. ** that have both DISTINCT and ORDER BY clauses.
** </ol> ** </ol>
** **
** <p>The following table summarizes the conditions under which the
** virtual table is allowed to set the "orderByConsumed" flag based on
** the value returned by sqlite3_vtab_distinct(). This table is a
** restatement of the previous four paragraphs:
**
** <table border=1 cellspacing=0 cellpadding=10 width="90%">
** <tr>
** <td valign="top">sqlite3_vtab_distinct() return value
** <td valign="top">Rows are returned in aOrderBy order
** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
** <td valign="top">Duplicates over all colUsed columns may be omitted
** <tr><td>0<td>yes<td>yes<td>no
** <tr><td>1<td>no<td>yes<td>no
** <tr><td>2<td>no<td>yes<td>yes
** <tr><td>3<td>yes<td>yes<td>yes
** </table>
**
** ^For the purposes of comparing virtual table output values to see if the ** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered ** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS" ** to be the same. In other words, the comparison operator is "IS"
@@ -10478,6 +10583,14 @@ typedef struct sqlite3_snapshot {
** If there is not already a read-transaction open on schema S when ** If there is not already a read-transaction open on schema S when
** this function is called, one is opened automatically. ** this function is called, one is opened automatically.
** **
** If a read-transaction is opened by this function, then it is guaranteed
** that the returned snapshot object may not be invalidated by a database
** writer or checkpointer until after the read-transaction is closed. This
** is not guaranteed if a read-transaction is already open when this
** function is called. In that case, any subsequent write or checkpoint
** operation on the database may invalidate the returned snapshot handle,
** even while the read-transaction remains open.
**
** The following must be true for this function to succeed. If any of ** The following must be true for this function to succeed. If any of
** the following statements are false when sqlite3_snapshot_get() is ** the following statements are false when sqlite3_snapshot_get() is
** called, SQLITE_ERROR is returned. The final value of *P is undefined ** called, SQLITE_ERROR is returned. The final value of *P is undefined
@@ -10786,8 +10899,6 @@ SQLITE_API int sqlite3_deserialize(
#if defined(__wasi__) #if defined(__wasi__)
# undef SQLITE_WASI # undef SQLITE_WASI
# define SQLITE_WASI 1 # define SQLITE_WASI 1
# undef SQLITE_OMIT_WAL
# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
# ifndef SQLITE_OMIT_LOAD_EXTENSION # ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION # define SQLITE_OMIT_LOAD_EXTENSION
# endif # endif
@@ -10799,7 +10910,7 @@ SQLITE_API int sqlite3_deserialize(
#ifdef __cplusplus #ifdef __cplusplus
} /* End of the 'extern "C"' block */ } /* End of the 'extern "C"' block */
#endif #endif
#endif /* SQLITE3_H */ /* #endif for SQLITE3_H will be added by mksqlite3.tcl */
/******** Begin file sqlite3rtree.h *********/ /******** Begin file sqlite3rtree.h *********/
/* /*
@@ -11979,6 +12090,30 @@ SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const c
*/ */
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
/*
** CAPI3REF: Add A Single Change To A Changegroup
** METHOD: sqlite3_changegroup
**
** This function adds the single change currently indicated by the iterator
** passed as the second argument to the changegroup object. The rules for
** adding the change are just as described for [sqlite3changegroup_add()].
**
** If the change is successfully added to the changegroup, SQLITE_OK is
** returned. Otherwise, an SQLite error code is returned.
**
** The iterator must point to a valid entry when this function is called.
** If it does not, SQLITE_ERROR is returned and no change is added to the
** changegroup. Additionally, the iterator must not have been opened with
** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
** returned.
*/
SQLITE_API int sqlite3changegroup_add_change(
sqlite3_changegroup*,
sqlite3_changeset_iter*
);
/* /*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** CAPI3REF: Obtain A Composite Changeset From A Changegroup
** METHOD: sqlite3_changegroup ** METHOD: sqlite3_changegroup
@@ -12783,8 +12918,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS ** EXTENSION API FUNCTIONS
** **
** xUserData(pFts): ** xUserData(pFts):
** Return a copy of the context pointer the extension function was ** Return a copy of the pUserData pointer passed to the xCreateFunction()
** registered with. ** API when the extension function was registered.
** **
** xColumnTotalSize(pFts, iCol, pnToken): ** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken ** If parameter iCol is less than zero, set output variable *pnToken
@@ -12966,6 +13101,10 @@ struct Fts5PhraseIter {
** (i.e. if it is a contentless table), then this API always iterates ** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** through an empty set (all calls to xPhraseFirst() set iCol to -1).
** **
** In all cases, matches are visited in (column ASC, offset ASC) order.
** i.e. all those in column 0, sorted by offset, followed by those in
** column 1, etc.
**
** xPhraseNext() ** xPhraseNext()
** See xPhraseFirst above. ** See xPhraseFirst above.
** **
@@ -13022,19 +13161,57 @@ struct Fts5PhraseIter {
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
** output variable (*ppToken) is set to point to a buffer containing the ** output variable (*ppToken) is set to point to a buffer containing the
** matching document token, and (*pnToken) to the size of that buffer in ** matching document token, and (*pnToken) to the size of that buffer in
** bytes. This API is not available if the specified token matches a ** bytes.
** prefix query term. In that case both output variables are always set
** to 0.
** **
** The output text is not a copy of the document text that was tokenized. ** The output text is not a copy of the document text that was tokenized.
** It is the output of the tokenizer module. For tokendata=1 tables, this ** It is the output of the tokenizer module. For tokendata=1 tables, this
** includes any embedded 0x00 and trailing data. ** includes any embedded 0x00 and trailing data.
** **
** This API may be slow in some cases if the token identified by parameters
** iIdx and iToken matched a prefix token in the query. In most cases, the
** first call to this API for each prefix token in the query is forced
** to scan the portion of the full-text index that matches the prefix
** token to collect the extra data required by this API. If the prefix
** token matches a large number of token instances in the document set,
** this may be a performance problem.
**
** If the user knows in advance that a query may use this API for a
** prefix token, FTS5 may be configured to collect all required data as part
** of the initial querying of the full-text index, avoiding the second scan
** entirely. This also causes prefix queries that do not use this API to
** run more slowly and use more memory. FTS5 may be configured in this way
** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
** option, or on a per-query basis using the
** [fts5_insttoken | fts5_insttoken()] user function.
**
** This API can be quite slow if used with an FTS5 table created with the ** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option. ** "detail=none" or "detail=column" option.
**
** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
** If parameter iCol is less than zero, or greater than or equal to the
** number of columns in the table, SQLITE_RANGE is returned.
**
** Otherwise, this function attempts to retrieve the locale associated
** with column iCol of the current row. Usually, there is no associated
** locale, and output parameters (*pzLocale) and (*pnLocale) are set
** to NULL and 0, respectively. However, if the fts5_locale() function
** was used to associate a locale with the value when it was inserted
** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
** is set to the size in bytes of the buffer, not including the
** nul-terminator.
**
** If successful, SQLITE_OK is returned. Or, if an error occurs, an
** SQLite error code is returned. The final value of the output parameters
** is undefined in this case.
**
** xTokenize_v2:
** Tokenize text using the tokenizer belonging to the FTS5 table. This
** API is the same as the xTokenize() API, except that it allows a tokenizer
** locale to be specified.
*/ */
struct Fts5ExtensionApi { struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*); void *(*xUserData)(Fts5Context*);
@@ -13076,6 +13253,15 @@ struct Fts5ExtensionApi {
const char **ppToken, int *pnToken const char **ppToken, int *pnToken
); );
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
/* Below this point are iVersion>=4 only */
int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
int (*xTokenize_v2)(Fts5Context*,
const char *pText, int nText, /* Text to tokenize */
const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
);
}; };
/* /*
@@ -13096,7 +13282,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text. ** A tokenizer instance is required to actually tokenize text.
** **
** The first argument passed to this function is a copy of the (void*) ** The first argument passed to this function is a copy of the (void*)
** pointer provided by the application when the fts5_tokenizer object ** pointer provided by the application when the fts5_tokenizer_v2 object
** was registered with FTS5 (the third argument to xCreateTokenizer()). ** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings ** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the ** containing the tokenizer arguments, if any, specified following the
@@ -13120,7 +13306,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object ** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate(). ** returned by an earlier call to xCreate().
** **
** The second argument indicates the reason that FTS5 is requesting ** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following ** tokenization of the supplied text. This is always one of the following
** four values: ** four values:
** **
@@ -13144,6 +13330,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database. ** on a columnsize=0 database.
** </ul> ** </ul>
** **
** The sixth and seventh arguments passed to xTokenize() - pLocale and
** nLocale - are a pointer to a buffer containing the locale to use for
** tokenization (e.g. "en_US") and its size in bytes, respectively. The
** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
** which case nLocale is always 0) to indicate that the tokenizer should
** use its default locale.
**
** For each token in the input string, the supplied callback xToken() must ** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer ** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth ** passed as the second argument to xTokenize(). The third and fourth
@@ -13167,6 +13360,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than ** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE. ** SQLITE_OK or SQLITE_DONE.
** **
** If the tokenizer is registered using an fts5_tokenizer_v2 object,
** then the xTokenize() method has two additional arguments - pLocale
** and nLocale. These specify the locale that the tokenizer should use
** for the current request. If pLocale and nLocale are both 0, then the
** tokenizer should use its default locale. Otherwise, pLocale points to
** an nLocale byte buffer containing the name of the locale to use as utf-8
** text. pLocale is not nul-terminated.
**
** FTS5_TOKENIZER
**
** There is also an fts5_tokenizer object. This is an older, deprecated,
** version of fts5_tokenizer_v2. It is similar except that:
**
** <ul>
** <li> There is no "iVersion" field, and
** <li> The xTokenize() method does not take a locale argument.
** </ul>
**
** Legacy fts5_tokenizer tokenizers must be registered using the
** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
**
** Tokenizer implementations registered using either API may be retrieved
** using both xFindTokenizer() and xFindTokenizer_v2().
**
** SYNONYM SUPPORT ** SYNONYM SUPPORT
** **
** Custom tokenizers may also support synonyms. Consider a case in which a ** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -13275,6 +13492,33 @@ struct Fts5ExtensionApi {
** inefficient. ** inefficient.
*/ */
typedef struct Fts5Tokenizer Fts5Tokenizer; typedef struct Fts5Tokenizer Fts5Tokenizer;
typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
struct fts5_tokenizer_v2 {
int iVersion; /* Currently always 2 */
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
void (*xDelete)(Fts5Tokenizer*);
int (*xTokenize)(Fts5Tokenizer*,
void *pCtx,
int flags, /* Mask of FTS5_TOKENIZE_* flags */
const char *pText, int nText,
const char *pLocale, int nLocale,
int (*xToken)(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
const char *pToken, /* Pointer to buffer containing token */
int nToken, /* Size of token in bytes */
int iStart, /* Byte offset of token within input text */
int iEnd /* Byte offset of end of token within input text */
)
);
};
/*
** New code should use the fts5_tokenizer_v2 type to define tokenizer
** implementations. The following type is included for legacy applications
** that still use it.
*/
typedef struct fts5_tokenizer fts5_tokenizer; typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer { struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -13294,6 +13538,7 @@ struct fts5_tokenizer {
); );
}; };
/* Flags that may be passed as the third argument to xTokenize() */ /* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002 #define FTS5_TOKENIZE_PREFIX 0x0002
@@ -13313,7 +13558,7 @@ struct fts5_tokenizer {
*/ */
typedef struct fts5_api fts5_api; typedef struct fts5_api fts5_api;
struct fts5_api { struct fts5_api {
int iVersion; /* Currently always set to 2 */ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */ /* Create a new tokenizer */
int (*xCreateTokenizer)( int (*xCreateTokenizer)(
@@ -13340,6 +13585,25 @@ struct fts5_api {
fts5_extension_function xFunction, fts5_extension_function xFunction,
void (*xDestroy)(void*) void (*xDestroy)(void*)
); );
/* APIs below this point are only available if iVersion>=3 */
/* Create a new tokenizer */
int (*xCreateTokenizer_v2)(
fts5_api *pApi,
const char *zName,
void *pUserData,
fts5_tokenizer_v2 *pTokenizer,
void (*xDestroy)(void*)
);
/* Find an existing tokenizer */
int (*xFindTokenizer_v2)(
fts5_api *pApi,
const char *zName,
void **ppUserData,
fts5_tokenizer_v2 **ppTokenizer
);
}; };
/* /*
@@ -13353,3 +13617,4 @@ struct fts5_api {
#endif /* _FTS5_H */ #endif /* _FTS5_H */
/******** End of fts5.h *********/ /******** End of fts5.h *********/
#endif /* SQLITE3_H */

View File

@@ -16,17 +16,17 @@ pub enum ErrorCode {
DatabaseBusy, DatabaseBusy,
/// A table in the database is locked /// A table in the database is locked
DatabaseLocked, DatabaseLocked,
/// A malloc() failed /// A `malloc()` failed
OutOfMemory, OutOfMemory,
/// Attempt to write a readonly database /// Attempt to write a readonly database
ReadOnly, ReadOnly,
/// Operation terminated by sqlite3_interrupt() /// Operation terminated by `sqlite3_interrupt()`
OperationInterrupted, OperationInterrupted,
/// Some kind of disk I/O error occurred /// Some kind of disk I/O error occurred
SystemIoFailure, SystemIoFailure,
/// The database disk image is malformed /// The database disk image is malformed
DatabaseCorrupt, DatabaseCorrupt,
/// Unknown opcode in sqlite3_file_control() /// Unknown opcode in `sqlite3_file_control()`
NotFound, NotFound,
/// Insertion failed because database is full /// Insertion failed because database is full
DiskFull, DiskFull,
@@ -48,7 +48,7 @@ pub enum ErrorCode {
NoLargeFileSupport, NoLargeFileSupport,
/// Authorization denied /// Authorization denied
AuthorizationForStatementDenied, AuthorizationForStatementDenied,
/// 2nd parameter to sqlite3_bind out of range /// 2nd parameter to `sqlite3_bind` out of range
ParameterOutOfRange, ParameterOutOfRange,
/// File opened that is not a database file /// File opened that is not a database file
NotADatabase, NotADatabase,
@@ -64,7 +64,7 @@ pub struct Error {
impl Error { impl Error {
#[must_use] #[must_use]
pub fn new(result_code: c_int) -> Error { pub fn new(result_code: c_int) -> Self {
let code = match result_code & 0xff { let code = match result_code & 0xff {
super::SQLITE_INTERNAL => ErrorCode::InternalMalfunction, super::SQLITE_INTERNAL => ErrorCode::InternalMalfunction,
super::SQLITE_PERM => ErrorCode::PermissionDenied, super::SQLITE_PERM => ErrorCode::PermissionDenied,
@@ -92,7 +92,7 @@ impl Error {
_ => ErrorCode::Unknown, _ => ErrorCode::Unknown,
}; };
Error { Self {
code, code,
extended_code: result_code, extended_code: result_code,
} }
@@ -118,7 +118,7 @@ impl error::Error for Error {
// Result codes. // Result codes.
// Note: These are not public because our bindgen bindings export whichever // Note: These are not public because our bindgen bindings export whichever
// constants are present in the current version of SQLite. We repeat them here // constants are present in the current version of SQLite. We repeat them here,
// so we don't have to worry about which version of SQLite added which // so we don't have to worry about which version of SQLite added which
// constants, and we only use them to implement code_to_str below. // constants, and we only use them to implement code_to_str below.
@@ -281,20 +281,20 @@ pub fn code_to_str(code: c_int) -> &'static str {
pub enum InitError { pub enum InitError {
/// Version mismatch between the extension and the SQLite3 library /// Version mismatch between the extension and the SQLite3 library
VersionMismatch { compile_time: i32, runtime: i32 }, VersionMismatch { compile_time: i32, runtime: i32 },
/// Invalid function pointer in one of sqlite3_api_routines fields /// Invalid function pointer in one of `sqlite3_api_routines` fields
NullFunctionPointer, NullFunctionPointer,
} }
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
impl ::std::fmt::Display for InitError { impl fmt::Display for InitError {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
InitError::VersionMismatch { Self::VersionMismatch {
compile_time, compile_time,
runtime, runtime,
} => { } => {
write!(f, "SQLite version mismatch: {runtime} < {compile_time}") write!(f, "SQLite version mismatch: {runtime} < {compile_time}")
} }
InitError::NullFunctionPointer => { Self::NullFunctionPointer => {
write!(f, "Some sqlite3_api_routines fields are null") write!(f, "Some sqlite3_api_routines fields are null")
} }
} }
@@ -302,3 +302,42 @@ impl ::std::fmt::Display for InitError {
} }
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
impl error::Error for InitError {} impl error::Error for InitError {}
#[cfg(test)]
mod test {
use crate::*;
#[test]
pub fn error_new() {
let assoc = vec![
(SQLITE_INTERNAL, ErrorCode::InternalMalfunction),
(SQLITE_PERM, ErrorCode::PermissionDenied),
(SQLITE_ABORT_ROLLBACK, ErrorCode::OperationAborted),
(SQLITE_BUSY_RECOVERY, ErrorCode::DatabaseBusy),
(SQLITE_LOCKED_SHAREDCACHE, ErrorCode::DatabaseLocked),
(SQLITE_NOMEM, ErrorCode::OutOfMemory),
(SQLITE_IOERR_READ, ErrorCode::SystemIoFailure),
(SQLITE_NOTFOUND, ErrorCode::NotFound),
(SQLITE_FULL, ErrorCode::DiskFull),
(SQLITE_PROTOCOL, ErrorCode::FileLockingProtocolFailed),
(SQLITE_SCHEMA, ErrorCode::SchemaChanged),
(SQLITE_TOOBIG, ErrorCode::TooBig),
(SQLITE_MISMATCH, ErrorCode::TypeMismatch),
(SQLITE_NOLFS, ErrorCode::NoLargeFileSupport),
(SQLITE_RANGE, ErrorCode::ParameterOutOfRange),
(SQLITE_NOTADB, ErrorCode::NotADatabase),
];
for (sqlite_code, rust_code) in assoc {
let err = Error::new(sqlite_code);
assert_eq!(
err,
Error {
code: rust_code,
extended_code: sqlite_code
}
);
let s = format!("{err}");
assert!(!s.is_empty());
}
}
}

View File

@@ -1,5 +1,4 @@
#![allow(non_snake_case, non_camel_case_types)] #![expect(non_snake_case, non_camel_case_types)]
#![cfg_attr(test, allow(deref_nullptr))] // https://github.com/rust-lang/rust-bindgen/issues/2066
// force linking to openssl // force linking to openssl
#[cfg(feature = "bundled-sqlcipher-vendored-openssl")] #[cfg(feature = "bundled-sqlcipher-vendored-openssl")]
@@ -7,7 +6,6 @@ extern crate openssl_sys;
pub use self::error::*; pub use self::error::*;
use std::default::Default;
use std::mem; use std::mem;
mod error; mod error;
@@ -19,10 +17,10 @@ pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
#[must_use] #[must_use]
pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type { pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
Some(unsafe { mem::transmute(-1_isize) }) Some(unsafe { mem::transmute::<isize, unsafe extern "C" fn(*mut std::ffi::c_void)>(-1_isize) })
} }
#[allow(clippy::all)] #[allow(dead_code, clippy::all)]
mod bindings { mod bindings {
include!(concat!(env!("OUT_DIR"), "/bindgen.rs")); include!(concat!(env!("OUT_DIR"), "/bindgen.rs"));
} }

View File

@@ -9,8 +9,8 @@ export SQLITE3_LIB_DIR="$SCRIPT_DIR/sqlite3"
mkdir -p "$TARGET_DIR" "$SQLITE3_LIB_DIR" mkdir -p "$TARGET_DIR" "$SQLITE3_LIB_DIR"
# Download and extract amalgamation # Download and extract amalgamation
SQLITE=sqlite-amalgamation-3450000 SQLITE=sqlite-amalgamation-3480000
curl -O https://sqlite.org/2024/$SQLITE.zip curl -O https://sqlite.org/2025/$SQLITE.zip
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.c" > "$SQLITE3_LIB_DIR/sqlite3.c" unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.c" > "$SQLITE3_LIB_DIR/sqlite3.c"
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.h" > "$SQLITE3_LIB_DIR/sqlite3.h" unzip -p "$SQLITE.zip" "$SQLITE/sqlite3.h" > "$SQLITE3_LIB_DIR/sqlite3.h"
unzip -p "$SQLITE.zip" "$SQLITE/sqlite3ext.h" > "$SQLITE3_LIB_DIR/sqlite3ext.h" unzip -p "$SQLITE.zip" "$SQLITE/sqlite3ext.h" > "$SQLITE3_LIB_DIR/sqlite3ext.h"
@@ -19,7 +19,7 @@ rm -f "$SQLITE.zip"
export SQLITE3_INCLUDE_DIR="$SQLITE3_LIB_DIR" export SQLITE3_INCLUDE_DIR="$SQLITE3_LIB_DIR"
# Regenerate bindgen file for sqlite3.h # Regenerate bindgen file for sqlite3.h
rm -f "$SQLITE3_LIB_DIR/bindgen_bundled_version.rs" rm -f "$SQLITE3_LIB_DIR/bindgen_bundled_version.rs"
cargo update cargo update --quiet
# Just to make sure there is only one bindgen.rs file in target dir # Just to make sure there is only one bindgen.rs file in target dir
find "$TARGET_DIR" -type f -name bindgen.rs -exec rm {} \; find "$TARGET_DIR" -type f -name bindgen.rs -exec rm {} \;
env LIBSQLITE3_SYS_BUNDLING=1 cargo build --features "buildtime_bindgen session" --no-default-features env LIBSQLITE3_SYS_BUNDLING=1 cargo build --features "buildtime_bindgen session" --no-default-features
@@ -38,6 +38,6 @@ rm -f "$SQLITE3_LIB_DIR/sqlite3ext.h.bk"
# Sanity checks # Sanity checks
cd "$SCRIPT_DIR/.." || { echo "fatal error" >&2; exit 1; } cd "$SCRIPT_DIR/.." || { echo "fatal error" >&2; exit 1; }
cargo update cargo update --quiet
cargo test --features "backup blob chrono functions limits load_extension serde_json trace vtab bundled" cargo test --features "backup blob chrono functions limits load_extension serde_json trace vtab bundled"
printf ' \e[35;1mFinished\e[0m bundled sqlite3 tests\n' printf ' \e[35;1mFinished\e[0m bundled sqlite3 tests\n'

View File

@@ -8,7 +8,7 @@ mkdir -p "$SCRIPT_DIR/../target" "$SCRIPT_DIR/sqlcipher"
export SQLCIPHER_LIB_DIR="$SCRIPT_DIR/sqlcipher" export SQLCIPHER_LIB_DIR="$SCRIPT_DIR/sqlcipher"
export SQLCIPHER_INCLUDE_DIR="$SQLCIPHER_LIB_DIR" export SQLCIPHER_INCLUDE_DIR="$SQLCIPHER_LIB_DIR"
SQLCIPHER_VERSION="4.5.3" SQLCIPHER_VERSION="4.6.1"
# Download and generate sqlcipher amalgamation # Download and generate sqlcipher amalgamation
mkdir -p $SCRIPT_DIR/sqlcipher.src 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" [ -e "v${SQLCIPHER_VERSION}.tar.gz" ] || curl -sfL -O "https://github.com/sqlcipher/sqlcipher/archive/v${SQLCIPHER_VERSION}.tar.gz"
@@ -30,6 +30,6 @@ find "$SCRIPT_DIR/../target" -type f -name bindgen.rs -exec mv {} "$SQLCIPHER_LI
# Sanity checks # Sanity checks
cd "$SCRIPT_DIR/.." || { echo "fatal error" >&2; exit 1; } cd "$SCRIPT_DIR/.." || { echo "fatal error" >&2; exit 1; }
cargo update cargo update --quiet
cargo test --features "backup blob chrono functions limits load_extension serde_json trace vtab bundled-sqlcipher-vendored-openssl" cargo test --features "backup blob chrono functions limits load_extension serde_json trace vtab bundled-sqlcipher-vendored-openssl"
printf ' \e[35;1mFinished\e[0m bundled-sqlcipher-vendored-openssl/sqlcipher tests\n' printf ' \e[35;1mFinished\e[0m bundled-sqlcipher-vendored-openssl/sqlcipher tests\n'

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"317f4e90836bae2153c14c3e564337f9bbb8defb20c18b877a8122fc427f00c8","src/bin/generate-test-data.rs":"7cc80b56929091d02675b9dd9bf4c657a95cda502656cf2ec8d91f56d7a393c7","src/db.rs":"d9dd44501ee3b19c696d8830d3036f7bfe0e8ad7751d5a057f5d8295ebf0bd4f","src/error.rs":"3a1308e65440769d9435fc95528d4ef42994c84d88e1da04ba058491dea387c4","src/ingest.rs":"09ac45d68470512f13a58f832c64d2a3dd85230b6454b3fd8fbecc6c1c735a7b","src/interest.rs":"e4369a1280867438bca12746f71288a03b4d5e180e156f4bc0335046012565f7","src/lib.rs":"80e69c16d0b84ae4b7434cd7cf43ade1c2f556bfa166bfb72a250b1eca8de075","src/ranker.rs":"e71414fe79ade26f3c79dceb5211af4f37984a9cded8c938dc1da8d8d28c2ad3","src/rs.rs":"3ba6ad925e62bbce1790598cb429328191393ec89f2ebc3d1fbf26b0db5de955","src/schema.rs":"38ea82679da2729a571aad936f96469e732ec1c104d7c21fd869842f7a5f30a3","src/url_hash.rs":"2e908316fb70923644d1990dbf470d69ce2f5e99b0c5c3d95ec691590be8ffa5","test-data":"1ef2cd092d59e7e126cd4a514af983d449ed9f9c98708702fd237464a76c2b5e"},"package":null} {"files":{"Cargo.toml":"fa569d53ba068f1626419e3910775ad6b5fce69f17a41a342640cba42a57f291","src/bin/generate-test-data.rs":"7cc80b56929091d02675b9dd9bf4c657a95cda502656cf2ec8d91f56d7a393c7","src/db.rs":"d9dd44501ee3b19c696d8830d3036f7bfe0e8ad7751d5a057f5d8295ebf0bd4f","src/error.rs":"3a1308e65440769d9435fc95528d4ef42994c84d88e1da04ba058491dea387c4","src/ingest.rs":"09ac45d68470512f13a58f832c64d2a3dd85230b6454b3fd8fbecc6c1c735a7b","src/interest.rs":"e4369a1280867438bca12746f71288a03b4d5e180e156f4bc0335046012565f7","src/lib.rs":"80e69c16d0b84ae4b7434cd7cf43ade1c2f556bfa166bfb72a250b1eca8de075","src/ranker.rs":"e71414fe79ade26f3c79dceb5211af4f37984a9cded8c938dc1da8d8d28c2ad3","src/rs.rs":"3ba6ad925e62bbce1790598cb429328191393ec89f2ebc3d1fbf26b0db5de955","src/schema.rs":"38ea82679da2729a571aad936f96469e732ec1c104d7c21fd869842f7a5f30a3","src/url_hash.rs":"2e908316fb70923644d1990dbf470d69ce2f5e99b0c5c3d95ec691590be8ffa5","test-data":"1ef2cd092d59e7e126cd4a514af983d449ed9f9c98708702fd237464a76c2b5e"},"package":null}

View File

@@ -57,7 +57,7 @@ path = "../support/interrupt"
path = "../remote_settings" path = "../remote_settings"
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = ["bundled"] features = ["bundled"]
[dependencies.serde] [dependencies.serde]

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"cb6d9b970b4d2ac267e218f666c2befdcb07030dbac2c428091f80dbc6f1455f","dumps/main/attachments/regions/world":"00b308033d44f61612b962f572765d14a3999586d92fc8b9fff2217a1ae070e8","dumps/main/attachments/regions/world-buffered":"1d3ed6954fac2a5b31302f5d3e8186c5fa08a20239afc0643ca5dfbb4d8a86fc","dumps/main/attachments/regions/world-buffered.meta.json":"914a71376a152036aceccb6877e079fbb9e3373c6219f24f00dd30e901a72cce","dumps/main/attachments/regions/world.meta.json":"2a47d77834997b98e563265d299723e7f7fd64c8c7a5731afc722862333d6fbd","dumps/main/regions.json":"e8990158373f82d3f89fed5089cf29e4177cc85904479128728e05025e9a0c0c","dumps/main/search-config-v2.json":"c33698dd66ed7f9dbbda857cad4f890455189e932e24c0d3b335e3e95b65239f","dumps/main/search-telemetry-v2.json":"140b3d322d6e317d97542725920be9f29c6b1d9c5f224e8c31995dddfec6bf1b","src/cache.rs":"c6179802017b43885136e7d64004890cc13e8c2d4742e04073cf404b578f63db","src/client.rs":"2399ec403771e2a4552d9ea513e3dcca449f45391eeb6bd838b272fc0085bc3b","src/config.rs":"603c7241483861a8c690464f4b50dd3dc281da7edf8aa522f90f175b85a7fa5f","src/error.rs":"20e40a0229842e12888bc43c4159e078f1d09272a43c51dae87989f76952f93b","src/jexl_filter.rs":"e4a9e29a80b216d777771434aaa6c58f627288e4b59ffa11c83dbd8e37889aa5","src/lib.rs":"464157ddf3b906c8f480c73dc3161890c8bc76cc95345c6857fee7a57385dc29","src/macros.rs":"6b06d0ba42ee95235bfd71bac1a0eed02f60c894775ebee64165648b10e932c4","src/schema.rs":"348e0d5ad1840aaae796b537d21381ef91bd75be262138bfec376d9f88d205b3","src/service.rs":"73da6cecc8c804b8e55d35ea3c71c1dd1e4099ad60532b7b0da153f9cde1eb21","src/signatures.rs":"baa2dae76abd8166158fea4676e67e17c17b65af6968de52768350409dbd7092","src/storage.rs":"5ae489964d82a0305a6b250d92f4c1925cc722e44890c24f681dd97b0258b9f4","uniffi.toml":"bd7cc0e7c1981f53938f429c4f2541ac454ed4160a8a0b4670659e38acd23ee5"},"package":null} {"files":{"Cargo.toml":"0f5097808e590bac3311526817410172f85d1549d4dfc3a2075333a67f7b7393","dumps/main/attachments/regions/world":"00b308033d44f61612b962f572765d14a3999586d92fc8b9fff2217a1ae070e8","dumps/main/attachments/regions/world-buffered":"1d3ed6954fac2a5b31302f5d3e8186c5fa08a20239afc0643ca5dfbb4d8a86fc","dumps/main/attachments/regions/world-buffered.meta.json":"914a71376a152036aceccb6877e079fbb9e3373c6219f24f00dd30e901a72cce","dumps/main/attachments/regions/world.meta.json":"2a47d77834997b98e563265d299723e7f7fd64c8c7a5731afc722862333d6fbd","dumps/main/regions.json":"e8990158373f82d3f89fed5089cf29e4177cc85904479128728e05025e9a0c0c","dumps/main/search-config-v2.json":"c33698dd66ed7f9dbbda857cad4f890455189e932e24c0d3b335e3e95b65239f","dumps/main/search-telemetry-v2.json":"140b3d322d6e317d97542725920be9f29c6b1d9c5f224e8c31995dddfec6bf1b","src/cache.rs":"c6179802017b43885136e7d64004890cc13e8c2d4742e04073cf404b578f63db","src/client.rs":"2399ec403771e2a4552d9ea513e3dcca449f45391eeb6bd838b272fc0085bc3b","src/config.rs":"603c7241483861a8c690464f4b50dd3dc281da7edf8aa522f90f175b85a7fa5f","src/error.rs":"20e40a0229842e12888bc43c4159e078f1d09272a43c51dae87989f76952f93b","src/jexl_filter.rs":"e4a9e29a80b216d777771434aaa6c58f627288e4b59ffa11c83dbd8e37889aa5","src/lib.rs":"464157ddf3b906c8f480c73dc3161890c8bc76cc95345c6857fee7a57385dc29","src/macros.rs":"6b06d0ba42ee95235bfd71bac1a0eed02f60c894775ebee64165648b10e932c4","src/schema.rs":"348e0d5ad1840aaae796b537d21381ef91bd75be262138bfec376d9f88d205b3","src/service.rs":"73da6cecc8c804b8e55d35ea3c71c1dd1e4099ad60532b7b0da153f9cde1eb21","src/signatures.rs":"baa2dae76abd8166158fea4676e67e17c17b65af6968de52768350409dbd7092","src/storage.rs":"5ae489964d82a0305a6b250d92f4c1925cc722e44890c24f681dd97b0258b9f4","uniffi.toml":"bd7cc0e7c1981f53938f429c4f2541ac454ed4160a8a0b4670659e38acd23ee5"},"package":null}

View File

@@ -71,7 +71,7 @@ path = "../support/rc_crypto"
optional = true optional = true
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = ["bundled"] features = ["bundled"]
[dependencies.serde] [dependencies.serde]

File diff suppressed because one or more lines are too long

852
third_party/rust/rusqlite/Cargo.lock generated vendored

File diff suppressed because it is too large Load Diff

View File

@@ -12,8 +12,9 @@
[package] [package]
edition = "2021" edition = "2021"
name = "rusqlite" name = "rusqlite"
version = "0.31.0" version = "0.33.0"
authors = ["The rusqlite developers"] authors = ["The rusqlite developers"]
build = false
exclude = [ exclude = [
"/.github/*", "/.github/*",
"/.gitattributes", "/.gitattributes",
@@ -22,6 +23,11 @@ exclude = [
"/clippy.toml", "/clippy.toml",
"/codecov.yml", "/codecov.yml",
] ]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Ergonomic wrapper for SQLite" description = "Ergonomic wrapper for SQLite"
documentation = "https://docs.rs/rusqlite/" documentation = "https://docs.rs/rusqlite/"
readme = "README.md" readme = "README.md"
@@ -51,119 +57,14 @@ rustdoc-args = [
all-features = false all-features = false
features = ["bundled-full"] features = ["bundled-full"]
[lib] [badges.appveyor]
name = "rusqlite" repository = "rusqlite/rusqlite"
[[example]] [badges.codecov]
name = "loadable_extension" repository = "rusqlite/rusqlite"
crate-type = ["cdylib"]
required-features = [
"loadable_extension",
"functions",
"trace",
]
[[example]] [badges.maintenance]
name = "load_extension" status = "actively-developed"
required-features = [
"load_extension",
"bundled",
"functions",
"trace",
]
[[test]]
name = "config_log"
harness = false
[[test]]
name = "deny_single_threaded_sqlite_config"
[[test]]
name = "vtab"
[[bench]]
name = "cache"
harness = false
[[bench]]
name = "exec"
harness = false
[dependencies.bitflags]
version = "2.0"
[dependencies.chrono]
version = "0.4"
features = ["clock"]
optional = true
default-features = false
[dependencies.csv]
version = "1.1"
optional = true
[dependencies.fallible-iterator]
version = "0.3"
[dependencies.fallible-streaming-iterator]
version = "0.1"
[dependencies.hashlink]
version = "0.9"
[dependencies.libsqlite3-sys]
version = "0.28.0"
[dependencies.rusqlite-macros]
version = "0.2.0"
optional = true
[dependencies.serde_json]
version = "1.0"
optional = true
[dependencies.smallvec]
version = "1.6.1"
[dependencies.time]
version = "0.3.0"
features = [
"formatting",
"macros",
"parsing",
]
optional = true
[dependencies.url]
version = "2.1"
optional = true
[dependencies.uuid]
version = "1.0"
optional = true
[dev-dependencies.bencher]
version = "0.1"
[dev-dependencies.doc-comment]
version = "0.3"
[dev-dependencies.lazy_static]
version = "1.4"
[dev-dependencies.regex]
version = "1.5.5"
[dev-dependencies.tempfile]
version = "3.1.0"
[dev-dependencies.unicase]
version = "2.6.0"
[dev-dependencies.uuid]
version = "1.0"
features = ["v4"]
[features] [features]
array = ["vtab"] array = ["vtab"]
@@ -217,9 +118,11 @@ modern-full = [
"functions", "functions",
"hooks", "hooks",
"i128_blob", "i128_blob",
"jiff",
"limits", "limits",
"load_extension", "load_extension",
"serde_json", "serde_json",
"serialize",
"series", "series",
"time", "time",
"trace", "trace",
@@ -230,7 +133,10 @@ modern-full = [
"window", "window",
] ]
modern_sqlite = ["libsqlite3-sys/bundled_bindings"] modern_sqlite = ["libsqlite3-sys/bundled_bindings"]
release_memory = [] preupdate_hook = [
"libsqlite3-sys/preupdate_hook",
"hooks",
]
serialize = ["modern_sqlite"] serialize = ["modern_sqlite"]
series = ["vtab"] series = ["vtab"]
session = [ session = [
@@ -245,11 +151,153 @@ wasm32-wasi-vfs = ["libsqlite3-sys/wasm32-wasi-vfs"]
window = ["functions"] window = ["functions"]
with-asan = ["libsqlite3-sys/with-asan"] with-asan = ["libsqlite3-sys/with-asan"]
[badges.appveyor] [lib]
repository = "rusqlite/rusqlite" name = "rusqlite"
path = "src/lib.rs"
[badges.codecov] [[example]]
repository = "rusqlite/rusqlite" name = "load_extension"
path = "examples/load_extension.rs"
required-features = [
"load_extension",
"bundled",
"functions",
"trace",
]
[badges.maintenance] [[example]]
status = "actively-developed" name = "loadable_extension"
crate-type = ["cdylib"]
path = "examples/loadable_extension.rs"
required-features = [
"loadable_extension",
"functions",
"trace",
]
[[example]]
name = "owning_rows"
path = "examples/owning_rows.rs"
[[example]]
name = "owning_rows_self_cell"
path = "examples/owning_rows_self_cell.rs"
[[example]]
name = "owning_statement"
path = "examples/owning_statement.rs"
[[example]]
name = "persons"
path = "examples/persons/main.rs"
[[test]]
name = "auto_ext"
path = "tests/auto_ext.rs"
[[test]]
name = "config_log"
path = "tests/config_log.rs"
harness = false
[[test]]
name = "deny_single_threaded_sqlite_config"
path = "tests/deny_single_threaded_sqlite_config.rs"
[[test]]
name = "vtab"
path = "tests/vtab.rs"
[[bench]]
name = "cache"
path = "benches/cache.rs"
harness = false
[[bench]]
name = "exec"
path = "benches/exec.rs"
harness = false
[dependencies.bitflags]
version = "2.6.0"
[dependencies.chrono]
version = "0.4.38"
features = ["clock"]
optional = true
default-features = false
[dependencies.csv]
version = "1.1"
optional = true
[dependencies.fallible-iterator]
version = "0.3"
[dependencies.fallible-streaming-iterator]
version = "0.1"
[dependencies.hashlink]
version = "0.10"
[dependencies.jiff]
version = "0.1"
features = ["std"]
optional = true
default-features = false
[dependencies.libsqlite3-sys]
version = "0.31.0"
[dependencies.rusqlite-macros]
version = "0.4.0"
optional = true
[dependencies.serde_json]
version = "1.0"
optional = true
[dependencies.smallvec]
version = "1.6.1"
[dependencies.time]
version = "0.3.36"
features = [
"formatting",
"macros",
"parsing",
]
optional = true
[dependencies.url]
version = "2.1"
optional = true
[dependencies.uuid]
version = "1.0"
optional = true
[dev-dependencies.bencher]
version = "0.1"
[dev-dependencies.doc-comment]
version = "0.3"
[dev-dependencies.ouroboros]
version = "0.18"
[dev-dependencies.regex]
version = "1.5.5"
[dev-dependencies.self_cell]
version = "1.1.0"
[dev-dependencies.tempfile]
version = "3.1.0"
[dev-dependencies.unicase]
version = "2.6.0"
[dev-dependencies.uuid]
version = "1.0"
features = ["v4"]

View File

@@ -27,7 +27,7 @@ In your Cargo.toml:
# That said, it's not ideal for all scenarios and in particular, generic # That said, it's not ideal for all scenarios and in particular, generic
# libraries built around `rusqlite` should probably not enable it, which # libraries built around `rusqlite` should probably not enable it, which
# is why it is not a default feature -- it could become hard to disable. # is why it is not a default feature -- it could become hard to disable.
rusqlite = { version = "0.31.0", features = ["bundled"] } rusqlite = { version = "0.33.0", features = ["bundled"] }
``` ```
Simple example usage: Simple example usage:
@@ -94,17 +94,14 @@ features](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-s
allows loading dynamic library-based SQLite extensions. allows loading dynamic library-based SQLite extensions.
* `loadable_extension` to program [loadable extension](https://sqlite.org/loadext.html) in Rust. * `loadable_extension` to program [loadable extension](https://sqlite.org/loadext.html) in Rust.
* [`backup`](https://docs.rs/rusqlite/~0/rusqlite/backup/index.html) * [`backup`](https://docs.rs/rusqlite/~0/rusqlite/backup/index.html)
allows use of SQLite's online backup API. Note: This feature requires SQLite 3.6.11 or later. allows use of SQLite's online backup API.
* [`functions`](https://docs.rs/rusqlite/~0/rusqlite/functions/index.html) * [`functions`](https://docs.rs/rusqlite/~0/rusqlite/functions/index.html)
allows you to load Rust closures into SQLite connections for use in queries. allows you to load Rust closures into SQLite connections for use in queries.
Note: This feature requires SQLite 3.7.3 or later.
* `window` for [window function](https://www.sqlite.org/windowfunctions.html) support (`fun(...) OVER ...`). (Implies `functions`.) * `window` for [window function](https://www.sqlite.org/windowfunctions.html) support (`fun(...) OVER ...`). (Implies `functions`.)
* [`trace`](https://docs.rs/rusqlite/~0/rusqlite/trace/index.html) * [`trace`](https://docs.rs/rusqlite/~0/rusqlite/trace/index.html)
allows hooks into SQLite's tracing and profiling APIs. Note: This feature allows hooks into SQLite's tracing and profiling APIs.
requires SQLite 3.6.23 or later.
* [`blob`](https://docs.rs/rusqlite/~0/rusqlite/blob/index.html) * [`blob`](https://docs.rs/rusqlite/~0/rusqlite/blob/index.html)
gives `std::io::{Read, Write, Seek}` access to SQL BLOBs. Note: This feature gives `std::io::{Read, Write, Seek}` access to SQL BLOBs.
requires SQLite 3.7.4 or later.
* [`limits`](https://docs.rs/rusqlite/~0/rusqlite/struct.Connection.html#method.limit) * [`limits`](https://docs.rs/rusqlite/~0/rusqlite/struct.Connection.html#method.limit)
allows you to set and retrieve SQLite's per connection limits. allows you to set and retrieve SQLite's per connection limits.
* `chrono` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html) * `chrono` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html)
@@ -126,6 +123,7 @@ features](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-s
- As the name implies this depends on the `bundled-sqlcipher` feature, and automatically turns it on. - As the name implies this depends on the `bundled-sqlcipher` feature, and automatically turns it on.
- If turned on, this uses the [`openssl-sys`](https://crates.io/crates/openssl-sys) crate, with the `vendored` feature enabled in order to build and bundle the OpenSSL crypto library. - If turned on, this uses the [`openssl-sys`](https://crates.io/crates/openssl-sys) crate, with the `vendored` feature enabled in order to build and bundle the OpenSSL crypto library.
* `hooks` for [Commit, Rollback](http://sqlite.org/c3ref/commit_hook.html) and [Data Change](http://sqlite.org/c3ref/update_hook.html) notification callbacks. * `hooks` for [Commit, Rollback](http://sqlite.org/c3ref/commit_hook.html) and [Data Change](http://sqlite.org/c3ref/update_hook.html) notification callbacks.
* `preupdate_hook` for [preupdate](https://sqlite.org/c3ref/preupdate_count.html) notification callbacks. (Implies `hooks`.)
* `unlock_notify` for [Unlock](https://sqlite.org/unlock_notify.html) notification. * `unlock_notify` for [Unlock](https://sqlite.org/unlock_notify.html) notification.
* `vtab` for [virtual table](https://sqlite.org/vtab.html) support (allows you to write virtual table implementations in Rust). Currently, only read-only virtual tables are supported. * `vtab` for [virtual table](https://sqlite.org/vtab.html) support (allows you to write virtual table implementations in Rust). Currently, only read-only virtual tables are supported.
* `series` exposes [`generate_series(...)`](https://www.sqlite.org/series.html) Table-Valued Function. (Implies `vtab`.) * `series` exposes [`generate_series(...)`](https://www.sqlite.org/series.html) Table-Valued Function. (Implies `vtab`.)
@@ -150,11 +148,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 * 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 [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 link against that. This source is embedded in the `libsqlite3-sys` crate and
is currently SQLite 3.45.1 (as of `rusqlite` 0.31.0 / `libsqlite3-sys` is currently SQLite 3.48.0 (as of `rusqlite` 0.33.0 / `libsqlite3-sys`
0.28.0). This is probably the simplest solution to any build problems. You can enable this by adding the following in your `Cargo.toml` file: 0.31.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 ```toml
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = ["bundled"] 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.) * 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.)
@@ -247,3 +245,8 @@ Depending on the set of enabled cargo `features`, rusqlite and libsqlite3-sys wi
- If `--features=bundled` is enabled, the vendored source of SQLite will be compiled and linked in. SQLite is in the public domain, as described [here](https://www.sqlite.org/copyright.html). - If `--features=bundled` is enabled, the vendored source of SQLite will be compiled and linked in. SQLite is in the public domain, as described [here](https://www.sqlite.org/copyright.html).
Both of these are quite permissive, have no bearing on the license of the code in `rusqlite` or `libsqlite3-sys` themselves, and can be entirely ignored if you do not use the feature in question. Both of these are quite permissive, have no bearing on the license of the code in `rusqlite` or `libsqlite3-sys` themselves, and can be entirely ignored if you do not use the feature in question.
## Minimum supported Rust version (MSRV)
Latest stable Rust version at the time of release. It might compile with older versions.

View File

@@ -1,4 +1,4 @@
//! Ensure loadable_extension.rs works. //! Ensure `loadable_extension.rs` works.
use rusqlite::{Connection, Result}; use rusqlite::{Connection, Result};
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
@@ -9,10 +9,7 @@ fn main() -> Result<()> {
unsafe { unsafe {
db.load_extension_enable()?; db.load_extension_enable()?;
db.load_extension( db.load_extension(
format!( format!("target/debug/examples/{DLL_PREFIX}loadable_extension{DLL_SUFFIX}"),
"target/debug/examples/{}loadable_extension{}",
DLL_PREFIX, DLL_SUFFIX
),
None, None,
)?; )?;
db.load_extension_disable()?; db.load_extension_disable()?;

View File

@@ -1,40 +1,40 @@
//! Adaptation of https://sqlite.org/loadext.html#programming_loadable_extensions //! Adaptation of https://sqlite.org/loadext.html#programming_loadable_extensions
//!
//! # build
//! ```sh
//! cargo build --example loadable_extension --features "loadable_extension functions trace"
//! ```
//!
//! # test
//! ```sh
//! sqlite> .log on
//! sqlite> .load target/debug/examples/libloadable_extension.so
//! (28) Rusqlite extension initialized
//! sqlite> SELECT rusqlite_test_function();
//! Rusqlite extension loaded correctly!
//! ```
use std::os::raw::{c_char, c_int}; use std::os::raw::{c_char, c_int};
use rusqlite::ffi; use rusqlite::ffi;
use rusqlite::functions::FunctionFlags; use rusqlite::functions::FunctionFlags;
use rusqlite::types::{ToSqlOutput, Value}; use rusqlite::types::{ToSqlOutput, Value};
use rusqlite::{to_sqlite_error, Connection, Result}; use rusqlite::{Connection, Result};
/// # build /// Entry point for SQLite to load the extension.
/// ```sh /// See <https://sqlite.org/c3ref/load_extension.html> on this function's name and usage.
/// cargo build --example loadable_extension --features "loadable_extension functions trace" /// # Safety
/// ``` /// This function is called by SQLite and must be safe to call.
/// # test #[expect(clippy::not_unsafe_ptr_arg_deref)]
/// ```sh
/// sqlite> .log on
/// sqlite> .load target/debug/examples/libloadable_extension.so
/// (28) Rusqlite extension initialized
/// sqlite> SELECT rusqlite_test_function();
/// Rusqlite extension loaded correctly!
/// ```
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle] #[no_mangle]
pub extern "C" fn sqlite3_extension_init( pub unsafe extern "C" fn sqlite3_extension_init(
db: *mut ffi::sqlite3, db: *mut ffi::sqlite3,
pz_err_msg: *mut *mut c_char, pz_err_msg: *mut *mut c_char,
p_api: *mut ffi::sqlite3_api_routines, p_api: *mut ffi::sqlite3_api_routines,
) -> c_int { ) -> c_int {
if p_api.is_null() { Connection::extension_init2(db, pz_err_msg, p_api, extension_init)
return ffi::SQLITE_ERROR;
} else if let Err(err) = extension_init(db, p_api) {
return unsafe { to_sqlite_error(&err, pz_err_msg) };
}
ffi::SQLITE_OK
} }
fn extension_init(db: *mut ffi::sqlite3, p_api: *mut ffi::sqlite3_api_routines) -> Result<()> { fn extension_init(db: Connection) -> Result<bool> {
let db = unsafe { Connection::extension_init2(db, p_api)? };
db.create_scalar_function( db.create_scalar_function(
"rusqlite_test_function", "rusqlite_test_function",
0, 0,
@@ -46,5 +46,5 @@ fn extension_init(db: *mut ffi::sqlite3, p_api: *mut ffi::sqlite3_api_routines)
}, },
)?; )?;
rusqlite::trace::log(ffi::SQLITE_WARNING, "Rusqlite extension initialized"); rusqlite::trace::log(ffi::SQLITE_WARNING, "Rusqlite extension initialized");
Ok(()) Ok(false)
} }

View File

@@ -0,0 +1,29 @@
extern crate rusqlite;
use ouroboros::self_referencing;
use rusqlite::{CachedStatement, Connection, Result, Rows};
#[self_referencing]
struct OwningRows<'conn> {
stmt: CachedStatement<'conn>,
#[borrows(mut stmt)]
#[covariant]
rows: Rows<'this>,
}
fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;
let stmt = conn.prepare_cached("SELECT 1")?;
let mut or = OwningRowsTryBuilder {
stmt,
rows_builder: |s| s.query([]),
}
.try_build()?;
or.with_rows_mut(|rows| -> Result<()> {
while let Some(row) = rows.next()? {
assert_eq!(Ok(1), row.get(0));
}
Ok(())
})?;
Ok(())
}

View File

@@ -0,0 +1,27 @@
extern crate rusqlite;
use rusqlite::{CachedStatement, Connection, Result, Rows};
use self_cell::{self_cell, MutBorrow};
type RowsRef<'a> = Rows<'a>;
self_cell!(
struct OwningRows<'conn> {
owner: MutBorrow<CachedStatement<'conn>>,
#[covariant]
dependent: RowsRef,
}
);
fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;
let stmt = conn.prepare_cached("SELECT 1")?;
let mut or = OwningRows::try_new(MutBorrow::new(stmt), |s| s.borrow_mut().query([]))?;
or.with_dependent_mut(|_stmt, rows| -> Result<()> {
while let Some(row) = rows.next()? {
assert_eq!(Ok(1), row.get(0));
}
Ok(())
})?;
Ok(())
}

View File

@@ -0,0 +1,30 @@
extern crate rusqlite;
use ouroboros::self_referencing;
use rusqlite::{CachedStatement, Connection, Result, Rows};
/// Caveat: single statement at a time for one connection.
/// But if you need multiple statements, you can still create your own struct
/// with multiple fields (one for each statement).
#[self_referencing]
struct OwningStatement {
conn: Connection,
#[borrows(conn)]
#[covariant]
stmt: CachedStatement<'this>,
}
fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;
let mut os = OwningStatementTryBuilder {
conn,
stmt_builder: |c| c.prepare_cached("SELECT 1"),
}
.try_build()?;
let mut rows = os.with_stmt_mut(|stmt| -> Result<Rows<'_>> { stmt.query([]) })?;
while let Some(row) = rows.next()? {
assert_eq!(Ok(1), row.get(0));
}
Ok(())
}

View File

@@ -0,0 +1,62 @@
//! Automatic extension loading
use super::ffi;
use crate::error::{check, to_sqlite_error};
use crate::{Connection, Error, Result};
use std::os::raw::{c_char, c_int};
use std::panic::catch_unwind;
/// Automatic extension initialization routine
pub type AutoExtension = fn(Connection) -> Result<()>;
/// Raw automatic extension initialization routine
pub type RawAutoExtension = unsafe extern "C" fn(
db: *mut ffi::sqlite3,
pz_err_msg: *mut *mut c_char,
_: *const ffi::sqlite3_api_routines,
) -> c_int;
/// Bridge between `RawAutoExtension` and `AutoExtension`
///
/// # Safety
/// * Opening a database from an auto-extension handler will lead to
/// an endless recursion of the auto-handler triggering itself
/// indirectly for each newly-opened database.
/// * Results are undefined if the given db is closed by an auto-extension.
/// * The list of auto-extensions should not be manipulated from an auto-extension.
pub unsafe fn init_auto_extension(
db: *mut ffi::sqlite3,
pz_err_msg: *mut *mut c_char,
ax: AutoExtension,
) -> c_int {
let r = catch_unwind(|| {
let c = Connection::from_handle(db);
c.and_then(ax)
})
.unwrap_or_else(|_| Err(Error::UnwindingPanic));
match r {
Err(e) => to_sqlite_error(&e, pz_err_msg),
_ => ffi::SQLITE_OK,
}
}
/// Register au auto-extension
///
/// # Safety
/// * Opening a database from an auto-extension handler will lead to
/// an endless recursion of the auto-handler triggering itself
/// indirectly for each newly-opened database.
/// * Results are undefined if the given db is closed by an auto-extension.
/// * The list of auto-extensions should not be manipulated from an auto-extension.
pub unsafe fn register_auto_extension(ax: RawAutoExtension) -> Result<()> {
check(ffi::sqlite3_auto_extension(Some(ax)))
}
/// Unregister the initialization routine
pub fn cancel_auto_extension(ax: RawAutoExtension) -> bool {
unsafe { ffi::sqlite3_cancel_auto_extension(Some(ax)) == 1 }
}
/// Disable all automatic extensions previously registered
pub fn reset_auto_extension() {
unsafe { ffi::sqlite3_reset_auto_extension() }
}

View File

@@ -1,5 +1,8 @@
//! Online SQLite backup API. //! Online SQLite backup API.
//! //!
//! Alternatively, you can create a backup with a simple
//! [`VACUUM INTO <backup_path>`](https://sqlite.org/lang_vacuum.html#vacuuminto).
//!
//! To create a [`Backup`], you must have two distinct [`Connection`]s - one //! To create a [`Backup`], you must have two distinct [`Connection`]s - one
//! for the source (which can be used while the backup is running) and one for //! for the source (which can be used while the backup is running) and one for
//! the destination (which cannot). A [`Backup`] handle exposes three methods: //! the destination (which cannot). A [`Backup`] handle exposes three methods:
@@ -65,7 +68,7 @@ impl Connection {
progress: Option<fn(Progress)>, progress: Option<fn(Progress)>,
) -> Result<()> { ) -> Result<()> {
use self::StepResult::{Busy, Done, Locked, More}; use self::StepResult::{Busy, Done, Locked, More};
let mut dst = Connection::open(dst_path)?; let mut dst = Self::open(dst_path)?;
let backup = Backup::new_with_names(self, name, &mut dst, DatabaseName::Main)?; let backup = Backup::new_with_names(self, name, &mut dst, DatabaseName::Main)?;
let mut r = More; let mut r = More;
@@ -103,7 +106,7 @@ impl Connection {
progress: Option<F>, progress: Option<F>,
) -> Result<()> { ) -> Result<()> {
use self::StepResult::{Busy, Done, Locked, More}; use self::StepResult::{Busy, Done, Locked, More};
let src = Connection::open(src_path)?; let src = Self::open(src_path)?;
let restore = Backup::new_with_names(&src, DatabaseName::Main, self, name)?; let restore = Backup::new_with_names(&src, DatabaseName::Main, self, name)?;
let mut r = More; let mut r = More;
@@ -152,8 +155,9 @@ pub enum StepResult {
Locked, Locked,
} }
/// Struct specifying the progress of a backup. The /// Struct specifying the progress of a backup.
/// percentage completion can be calculated as `(pagecount - remaining) / ///
/// The percentage completion can be calculated as `(pagecount - remaining) /
/// pagecount`. The progress of a backup is as of the last call to /// pagecount`. The progress of a backup is as of the last call to
/// [`step`](Backup::step) - if the source database is modified after a call to /// [`step`](Backup::step) - if the source database is modified after a call to
/// [`step`](Backup::step), the progress value will become outdated and /// [`step`](Backup::step), the progress value will become outdated and
@@ -203,8 +207,8 @@ impl Backup<'_, '_> {
to: &'b mut Connection, to: &'b mut Connection,
to_name: DatabaseName<'_>, to_name: DatabaseName<'_>,
) -> Result<Backup<'a, 'b>> { ) -> Result<Backup<'a, 'b>> {
let to_name = to_name.as_cstring()?; let to_name = to_name.as_cstr()?;
let from_name = from_name.as_cstring()?; let from_name = from_name.as_cstr()?;
let to_db = to.db.borrow_mut().db; let to_db = to.db.borrow_mut().db;
@@ -316,10 +320,28 @@ impl Drop for Backup<'_, '_> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Backup; use super::{Backup, Progress};
use crate::{Connection, DatabaseName, Result}; use crate::{Connection, DatabaseName, Result};
use std::time::Duration; use std::time::Duration;
#[test]
fn backup_to_path() -> Result<()> {
let src = Connection::open_in_memory()?;
src.execute_batch("CREATE TABLE foo AS SELECT 42 AS x")?;
let temp_dir = tempfile::tempdir().unwrap();
let path = temp_dir.path().join("test.db3");
fn progress(_: Progress) {}
src.backup(DatabaseName::Main, path.as_path(), Some(progress))?;
let mut dst = Connection::open_in_memory()?;
dst.restore(DatabaseName::Main, path, Some(progress))?;
Ok(())
}
#[test] #[test]
fn test_backup() -> Result<()> { fn test_backup() -> Result<()> {
let src = Connection::open_in_memory()?; let src = Connection::open_in_memory()?;

View File

@@ -50,7 +50,7 @@
//! Using `MaybeUninit` here can be more efficient in some cases, but is //! Using `MaybeUninit` here can be more efficient in some cases, but is
//! often inconvenient, so both are provided. //! often inconvenient, so both are provided.
//! //!
//! 2. Exact/inexact refers to to whether or not the entire buffer must be //! 2. Exact/inexact refers to whether or not the entire buffer must be
//! filled in order for the call to be considered a success. //! filled in order for the call to be considered a success.
//! //!
//! The "exact" functions require the provided buffer be entirely filled, or //! The "exact" functions require the provided buffer be entirely filled, or
@@ -225,7 +225,7 @@ impl Connection {
) -> Result<Blob<'a>> { ) -> Result<Blob<'a>> {
let c = self.db.borrow_mut(); let c = self.db.borrow_mut();
let mut blob = ptr::null_mut(); let mut blob = ptr::null_mut();
let db = db.as_cstring()?; let db = db.as_cstr()?;
let table = super::str_to_cstring(table)?; let table = super::str_to_cstring(table)?;
let column = super::str_to_cstring(column)?; let column = super::str_to_cstring(column)?;
let rc = unsafe { let rc = unsafe {
@@ -287,7 +287,7 @@ impl Blob<'_> {
/// Close a BLOB handle. /// Close a BLOB handle.
/// ///
/// Calling `close` explicitly is not required (the BLOB will be closed /// Calling `close` explicitly is not required (the BLOB will be closed
/// when the `Blob` is dropped), but it is available so you can get any /// when the `Blob` is dropped), but it is available, so you can get any
/// errors that occur. /// errors that occur.
/// ///
/// # Failure /// # Failure
@@ -393,7 +393,7 @@ impl io::Seek for Blob<'_> {
} }
} }
#[allow(unused_must_use)] #[expect(unused_must_use)]
impl Drop for Blob<'_> { impl Drop for Blob<'_> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
@@ -413,7 +413,7 @@ pub struct ZeroBlob(pub i32);
impl ToSql for ZeroBlob { impl ToSql for ZeroBlob {
#[inline] #[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> { fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let ZeroBlob(length) = *self; let Self(length) = *self;
Ok(ToSqlOutput::ZeroBlob(length)) Ok(ToSqlOutput::ZeroBlob(length))
} }
} }
@@ -439,9 +439,12 @@ mod test {
let (db, rowid) = db_with_test_blob()?; let (db, rowid) = db_with_test_blob()?;
let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?; let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
assert!(!blob.is_empty());
assert_eq!(10, blob.len());
assert_eq!(4, blob.write(b"Clob").unwrap()); assert_eq!(4, blob.write(b"Clob").unwrap());
assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10 assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
assert_eq!(0, blob.write(b"5678").unwrap()); // still cannot write past 10 assert_eq!(0, blob.write(b"5678").unwrap()); // still cannot write past 10
blob.flush().unwrap();
blob.reopen(rowid)?; blob.reopen(rowid)?;
blob.close()?; blob.close()?;
@@ -547,4 +550,12 @@ mod test {
Ok(()) Ok(())
} }
} }
#[test]
fn zero_blob() -> Result<()> {
use crate::types::ToSql;
let zb = super::ZeroBlob(1);
assert!(zb.to_sql().is_ok());
Ok(())
}
} }

View File

@@ -1,13 +1,12 @@
use super::Blob; use super::Blob;
use std::convert::TryFrom;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::slice::from_raw_parts_mut; use std::slice::from_raw_parts_mut;
use crate::ffi; use crate::ffi;
use crate::{Error, Result}; use crate::{Error, Result};
impl<'conn> Blob<'conn> { impl Blob<'_> {
/// Write `buf` to `self` starting at `write_start`, returning an error if /// Write `buf` to `self` starting at `write_start`, returning an error if
/// `write_start + buf.len()` is past the end of the blob. /// `write_start + buf.len()` is past the end of the blob.
/// ///
@@ -117,7 +116,7 @@ impl<'conn> Blob<'conn> {
if read_len == 0 { if read_len == 0 {
// We could return `Ok(&mut [])`, but it seems confusing that the // We could return `Ok(&mut [])`, but it seems confusing that the
// pointers don't match, so fabricate a empty slice of u8 with the // pointers don't match, so fabricate an empty slice of u8 with the
// same base pointer as `buf`. // same base pointer as `buf`.
let empty = unsafe { from_raw_parts_mut(buf.as_mut_ptr().cast::<u8>(), 0) }; let empty = unsafe { from_raw_parts_mut(buf.as_mut_ptr().cast::<u8>(), 0) };
return Ok(empty); return Ok(empty);
@@ -209,21 +208,21 @@ mod test {
blob.seek(std::io::SeekFrom::Start(1)).unwrap(); blob.seek(std::io::SeekFrom::Start(1)).unwrap();
let one2ten: [u8; 10] = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let one2ten: [u8; 10] = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
blob.write_at(&one2ten, 0).unwrap(); blob.write_at(&one2ten, 0)?;
let mut s = [0u8; 10]; let mut s = [0u8; 10];
blob.read_at_exact(&mut s, 0).unwrap(); blob.read_at_exact(&mut s, 0)?;
assert_eq!(&s, &one2ten, "write should go through"); assert_eq!(&s, &one2ten, "write should go through");
blob.read_at_exact(&mut s, 1).unwrap_err(); blob.read_at_exact(&mut s, 1).unwrap_err();
blob.read_at_exact(&mut s, 0).unwrap(); blob.read_at_exact(&mut s, 0)?;
assert_eq!(&s, &one2ten, "should be unchanged"); assert_eq!(&s, &one2ten, "should be unchanged");
let mut fives = [0u8; 5]; let mut fives = [0u8; 5];
blob.read_at_exact(&mut fives, 0).unwrap(); blob.read_at_exact(&mut fives, 0)?;
assert_eq!(&fives, &[1u8, 2, 3, 4, 5]); assert_eq!(&fives, &[1u8, 2, 3, 4, 5]);
blob.read_at_exact(&mut fives, 5).unwrap(); blob.read_at_exact(&mut fives, 5)?;
assert_eq!(&fives, &[6u8, 7, 8, 9, 10]); assert_eq!(&fives, &[6u8, 7, 8, 9, 10]);
blob.read_at_exact(&mut fives, 7).unwrap_err(); blob.read_at_exact(&mut fives, 7).unwrap_err();
blob.read_at_exact(&mut fives, 12).unwrap_err(); blob.read_at_exact(&mut fives, 12).unwrap_err();
@@ -234,12 +233,12 @@ mod test {
.unwrap_err(); .unwrap_err();
// zero length writes are fine if in bounds // zero length writes are fine if in bounds
blob.read_at_exact(&mut [], 10).unwrap(); blob.read_at_exact(&mut [], 10)?;
blob.read_at_exact(&mut [], 0).unwrap(); blob.read_at_exact(&mut [], 0)?;
blob.read_at_exact(&mut [], 5).unwrap(); blob.read_at_exact(&mut [], 5)?;
blob.write_all_at(&[16, 17, 18, 19, 20], 5).unwrap(); blob.write_all_at(&[16, 17, 18, 19, 20], 5)?;
blob.read_at_exact(&mut s, 0).unwrap(); blob.read_at_exact(&mut s, 0)?;
assert_eq!(&s, &[1u8, 2, 3, 4, 5, 16, 17, 18, 19, 20]); assert_eq!(&s, &[1u8, 2, 3, 4, 5, 16, 17, 18, 19, 20]);
blob.write_at(&[100, 99, 98, 97, 96], 6).unwrap_err(); blob.write_at(&[100, 99, 98, 97, 96], 6).unwrap_err();
@@ -248,19 +247,19 @@ mod test {
blob.write_at(&[100, 99, 98, 97, 96], i32::MAX as usize + 1) blob.write_at(&[100, 99, 98, 97, 96], i32::MAX as usize + 1)
.unwrap_err(); .unwrap_err();
blob.read_at_exact(&mut s, 0).unwrap(); blob.read_at_exact(&mut s, 0)?;
assert_eq!(&s, &[1u8, 2, 3, 4, 5, 16, 17, 18, 19, 20]); assert_eq!(&s, &[1u8, 2, 3, 4, 5, 16, 17, 18, 19, 20]);
let mut s2: [std::mem::MaybeUninit<u8>; 10] = [std::mem::MaybeUninit::uninit(); 10]; let mut s2: [std::mem::MaybeUninit<u8>; 10] = [std::mem::MaybeUninit::uninit(); 10];
{ {
let read = blob.raw_read_at_exact(&mut s2, 0).unwrap(); let read = blob.raw_read_at_exact(&mut s2, 0)?;
assert_eq!(read, &s); assert_eq!(read, &s);
assert!(std::ptr::eq(read.as_ptr(), s2.as_ptr().cast())); assert!(std::ptr::eq(read.as_ptr(), s2.as_ptr().cast()));
} }
let mut empty = []; let mut empty = [];
assert!(std::ptr::eq( assert!(std::ptr::eq(
blob.raw_read_at_exact(&mut empty, 0).unwrap().as_ptr(), blob.raw_read_at_exact(&mut empty, 0)?.as_ptr(),
empty.as_ptr().cast(), empty.as_ptr().cast(),
)); ));
blob.raw_read_at_exact(&mut s2, 5).unwrap_err(); blob.raw_read_at_exact(&mut s2, 5).unwrap_err();

View File

@@ -1,5 +1,4 @@
//! Busy handler (when the database is locked) //! Busy handler (when the database is locked)
use std::convert::TryInto;
use std::mem; use std::mem;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
use std::panic::catch_unwind; use std::panic::catch_unwind;
@@ -81,12 +80,8 @@ impl InnerConnection {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::sync_channel;
use std::thread;
use std::time::Duration;
use crate::{Connection, ErrorCode, Result, TransactionBehavior}; use crate::{Connection, ErrorCode, Result, TransactionBehavior};
use std::sync::atomic::{AtomicBool, Ordering};
#[test] #[test]
fn test_default_busy() -> Result<()> { fn test_default_busy() -> Result<()> {
@@ -105,66 +100,28 @@ mod test {
} }
#[test] #[test]
#[ignore] // FIXME: unstable fn test_busy_handler() -> Result<()> {
fn test_busy_timeout() {
let temp_dir = tempfile::tempdir().unwrap();
let path = temp_dir.path().join("test.db3");
let db2 = Connection::open(&path).unwrap();
db2.busy_timeout(Duration::from_secs(1)).unwrap();
let (rx, tx) = sync_channel(0);
let child = thread::spawn(move || {
let mut db1 = Connection::open(&path).unwrap();
let tx1 = db1
.transaction_with_behavior(TransactionBehavior::Exclusive)
.unwrap();
rx.send(1).unwrap();
thread::sleep(Duration::from_millis(100));
tx1.rollback().unwrap();
});
assert_eq!(tx.recv().unwrap(), 1);
let _ = db2
.query_row("PRAGMA schema_version", [], |row| row.get::<_, i32>(0))
.expect("unexpected error");
child.join().unwrap();
}
#[test]
#[ignore] // FIXME: unstable
fn test_busy_handler() {
static CALLED: AtomicBool = AtomicBool::new(false); static CALLED: AtomicBool = AtomicBool::new(false);
fn busy_handler(_: i32) -> bool { fn busy_handler(n: i32) -> bool {
CALLED.store(true, Ordering::Relaxed); if n > 2 {
thread::sleep(Duration::from_millis(100)); false
true } else {
CALLED.swap(true, Ordering::Relaxed)
}
} }
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
let path = temp_dir.path().join("test.db3"); let path = temp_dir.path().join("busy-handler.db3");
let db2 = Connection::open(&path).unwrap(); let db1 = Connection::open(&path)?;
db2.busy_handler(Some(busy_handler)).unwrap(); db1.execute_batch("CREATE TABLE IF NOT EXISTS t(a)")?;
let db2 = Connection::open(&path)?;
let (rx, tx) = sync_channel(0); db2.busy_handler(Some(busy_handler))?;
let child = thread::spawn(move || { db1.execute_batch("BEGIN EXCLUSIVE")?;
let mut db1 = Connection::open(&path).unwrap(); let err = db2.prepare("SELECT * FROM t").unwrap_err();
let tx1 = db1 assert_eq!(err.sqlite_error_code(), Some(ErrorCode::DatabaseBusy));
.transaction_with_behavior(TransactionBehavior::Exclusive)
.unwrap();
rx.send(1).unwrap();
thread::sleep(Duration::from_millis(100));
tx1.rollback().unwrap();
});
assert_eq!(tx.recv().unwrap(), 1);
let _ = db2
.query_row("PRAGMA schema_version", [], |row| row.get::<_, i32>(0))
.expect("unexpected error");
assert!(CALLED.load(Ordering::Relaxed)); assert!(CALLED.load(Ordering::Relaxed));
db1.busy_handler(None)?;
child.join().unwrap(); Ok(())
} }
} }

View File

@@ -60,7 +60,6 @@ impl Connection {
#[derive(Debug)] #[derive(Debug)]
pub struct StatementCache(RefCell<LruCache<Arc<str>, RawStatement>>); pub struct StatementCache(RefCell<LruCache<Arc<str>, RawStatement>>);
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl Send for StatementCache {} unsafe impl Send for StatementCache {}
/// Cacheable statement. /// Cacheable statement.
@@ -90,7 +89,6 @@ impl<'conn> DerefMut for CachedStatement<'conn> {
} }
impl Drop for CachedStatement<'_> { impl Drop for CachedStatement<'_> {
#[allow(unused_must_use)]
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
if let Some(stmt) = self.stmt.take() { if let Some(stmt) = self.stmt.take() {
@@ -119,8 +117,8 @@ impl CachedStatement<'_> {
impl StatementCache { impl StatementCache {
/// Create a statement cache. /// Create a statement cache.
#[inline] #[inline]
pub fn with_capacity(capacity: usize) -> StatementCache { pub fn with_capacity(capacity: usize) -> Self {
StatementCache(RefCell::new(LruCache::new(capacity))) Self(RefCell::new(LruCache::new(capacity)))
} }
#[inline] #[inline]
@@ -153,7 +151,7 @@ impl StatementCache {
} }
// Return a statement to the cache. // Return a statement to the cache.
fn cache_stmt(&self, stmt: RawStatement) { fn cache_stmt(&self, mut stmt: RawStatement) {
if stmt.is_null() { if stmt.is_null() {
return; return;
} }
@@ -278,10 +276,10 @@ mod test {
fn test_ddl() -> Result<()> { fn test_ddl() -> Result<()> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch( db.execute_batch(
r#" r"
CREATE TABLE foo (x INT); CREATE TABLE foo (x INT);
INSERT INTO foo VALUES (1); INSERT INTO foo VALUES (1);
"#, ",
)?; )?;
let sql = "SELECT * FROM foo"; let sql = "SELECT * FROM foo";
@@ -292,10 +290,10 @@ mod test {
} }
db.execute_batch( db.execute_batch(
r#" r"
ALTER TABLE foo ADD COLUMN y INT; ALTER TABLE foo ADD COLUMN y INT;
UPDATE foo SET y = 2; UPDATE foo SET y = 2;
"#, ",
)?; )?;
{ {

View File

@@ -1,7 +1,7 @@
//! Add, remove, or modify a collation //! Add, remove, or modify a collation
use std::cmp::Ordering; use std::cmp::Ordering;
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::panic::{catch_unwind, UnwindSafe}; use std::panic::catch_unwind;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
@@ -18,7 +18,7 @@ impl Connection {
#[inline] #[inline]
pub fn create_collation<C>(&self, collation_name: &str, x_compare: C) -> Result<()> pub fn create_collation<C>(&self, collation_name: &str, x_compare: C) -> Result<()>
where where
C: Fn(&str, &str) -> Ordering + Send + UnwindSafe + 'static, C: Fn(&str, &str) -> Ordering + Send + 'static,
{ {
self.db self.db
.borrow_mut() .borrow_mut()
@@ -27,10 +27,7 @@ impl Connection {
/// Collation needed callback /// Collation needed callback
#[inline] #[inline]
pub fn collation_needed( pub fn collation_needed(&self, x_coll_needed: fn(&Self, &str) -> Result<()>) -> Result<()> {
&self,
x_coll_needed: fn(&Connection, &str) -> Result<()>,
) -> Result<()> {
self.db.borrow_mut().collation_needed(x_coll_needed) self.db.borrow_mut().collation_needed(x_coll_needed)
} }
@@ -42,9 +39,31 @@ impl Connection {
} }
impl InnerConnection { impl InnerConnection {
/// ```compile_fail
/// use rusqlite::{Connection, Result};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.create_collation("foo", |_, _| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// std::cmp::Ordering::Equal
/// })?;
/// }
/// let value: String = db.query_row(
/// "WITH cte(bar) AS
/// (VALUES ('v1'),('v2'),('v3'),('v4'),('v5'))
/// SELECT DISTINCT bar COLLATE foo FROM cte;",
/// [],
/// |row| row.get(0),
/// )?;
/// assert_eq!(value, "v1");
/// Ok(())
/// }
/// ```
fn create_collation<C>(&mut self, collation_name: &str, x_compare: C) -> Result<()> fn create_collation<C>(&mut self, collation_name: &str, x_compare: C) -> Result<()>
where where
C: Fn(&str, &str) -> Ordering + Send + UnwindSafe + 'static, C: Fn(&str, &str) -> Ordering + Send + 'static,
{ {
unsafe extern "C" fn call_boxed_closure<C>( unsafe extern "C" fn call_boxed_closure<C>(
arg1: *mut c_void, arg1: *mut c_void,
@@ -110,7 +129,7 @@ impl InnerConnection {
x_coll_needed: fn(&Connection, &str) -> Result<()>, x_coll_needed: fn(&Connection, &str) -> Result<()>,
) -> Result<()> { ) -> Result<()> {
use std::mem; use std::mem;
#[allow(clippy::needless_return)] #[expect(clippy::needless_return)]
unsafe extern "C" fn collation_needed_callback( unsafe extern "C" fn collation_needed_callback(
arg1: *mut c_void, arg1: *mut c_void,
arg2: *mut ffi::sqlite3, arg2: *mut ffi::sqlite3,
@@ -128,10 +147,9 @@ impl InnerConnection {
let callback: fn(&Connection, &str) -> Result<()> = mem::transmute(arg1); let callback: fn(&Connection, &str) -> Result<()> = mem::transmute(arg1);
let res = catch_unwind(|| { let res = catch_unwind(|| {
let conn = Connection::from_handle(arg2).unwrap(); let conn = Connection::from_handle(arg2).unwrap();
let collation_name = { let collation_name = CStr::from_ptr(arg3)
let c_slice = CStr::from_ptr(arg3).to_bytes(); .to_str()
str::from_utf8(c_slice).expect("illegal collation sequence name") .expect("illegal collation sequence name");
};
callback(&conn, collation_name) callback(&conn, collation_name)
}); });
if res.is_err() { if res.is_err() {
@@ -180,9 +198,7 @@ mod test {
#[test] #[test]
fn test_unicase() -> Result<()> { fn test_unicase() -> Result<()> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.create_collation("unicase", unicase_compare)?; db.create_collation("unicase", unicase_compare)?;
collate(db) collate(db)
} }
@@ -212,4 +228,11 @@ mod test {
db.collation_needed(collation_needed)?; db.collation_needed(collation_needed)?;
collate(db) collate(db)
} }
#[test]
fn remove_collation() -> Result<()> {
let db = Connection::open_in_memory()?;
db.create_collation("unicase", unicase_compare)?;
db.remove_collation("unicase")
}
} }

View File

@@ -57,7 +57,7 @@ impl Statement<'_> {
} }
/// Check that column name reference lifetime is limited: /// Check that column name reference lifetime is limited:
/// https://www.sqlite.org/c3ref/column_name.html /// <https://www.sqlite.org/c3ref/column_name.html>
/// > The returned string pointer is valid... /// > The returned string pointer is valid...
/// ///
/// `column_name` reference can become invalid if `stmt` is reprepared /// `column_name` reference can become invalid if `stmt` is reprepared
@@ -104,7 +104,9 @@ impl Statement<'_> {
// clippy::or_fun_call (nightly) vs clippy::unnecessary-lazy-evaluations (stable) // clippy::or_fun_call (nightly) vs clippy::unnecessary-lazy-evaluations (stable)
.ok_or(Error::InvalidColumnIndex(col)) .ok_or(Error::InvalidColumnIndex(col))
.map(|slice| { .map(|slice| {
str::from_utf8(slice.to_bytes()).expect("Invalid UTF-8 sequence in column name") slice
.to_str()
.expect("Invalid UTF-8 sequence in column name")
}) })
} }
@@ -149,7 +151,8 @@ impl Statement<'_> {
let name = self.column_name_unwrap(i); let name = self.column_name_unwrap(i);
let slice = self.stmt.column_decltype(i); let slice = self.stmt.column_decltype(i);
let decl_type = slice.map(|s| { let decl_type = slice.map(|s| {
str::from_utf8(s.to_bytes()).expect("Invalid UTF-8 sequence in column declaration") s.to_str()
.expect("Invalid UTF-8 sequence in column declaration")
}); });
cols.push(Column { name, decl_type }); cols.push(Column { name, decl_type });
} }
@@ -228,7 +231,7 @@ mod test {
/// `column_name` reference should stay valid until `stmt` is reprepared (or /// `column_name` reference should stay valid until `stmt` is reprepared (or
/// reset) even if DB schema is altered (SQLite documentation is /// reset) even if DB schema is altered (SQLite documentation is
/// ambiguous here because it says reference "is valid until (...) the next /// ambiguous here because it says reference "is valid until (...) the next
/// call to sqlite3_column_name() or sqlite3_column_name16() on the same /// call to `sqlite3_column_name()` or `sqlite3_column_name16()` on the same
/// column.". We assume that reference is valid if only /// column.". We assume that reference is valid if only
/// `sqlite3_column_name()` is used): /// `sqlite3_column_name()` is used):
#[test] #[test]

View File

@@ -10,9 +10,8 @@ use crate::{Connection, Result};
/// See [Database Connection Configuration Options](https://sqlite.org/c3ref/c_dbconfig_enable_fkey.html) for details. /// See [Database Connection Configuration Options](https://sqlite.org/c3ref/c_dbconfig_enable_fkey.html) for details.
#[repr(i32)] #[repr(i32)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[allow(non_snake_case, non_camel_case_types)] #[expect(non_camel_case_types)]
#[non_exhaustive] #[non_exhaustive]
#[allow(clippy::upper_case_acronyms)]
pub enum DbConfig { pub enum DbConfig {
//SQLITE_DBCONFIG_MAINDBNAME = 1000, /* const char* */ //SQLITE_DBCONFIG_MAINDBNAME = 1000, /* const char* */
//SQLITE_DBCONFIG_LOOKASIDE = 1001, /* void* int int */ //SQLITE_DBCONFIG_LOOKASIDE = 1001, /* void* int int */
@@ -20,7 +19,7 @@ pub enum DbConfig {
SQLITE_DBCONFIG_ENABLE_FKEY = ffi::SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_DBCONFIG_ENABLE_FKEY = ffi::SQLITE_DBCONFIG_ENABLE_FKEY,
/// Enable or disable triggers. /// Enable or disable triggers.
SQLITE_DBCONFIG_ENABLE_TRIGGER = ffi::SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_DBCONFIG_ENABLE_TRIGGER = ffi::SQLITE_DBCONFIG_ENABLE_TRIGGER,
/// Enable or disable the fts3_tokenizer() function which is part of the /// Enable or disable the `fts3_tokenizer()` function which is part of the
/// FTS3 full-text search engine extension. /// FTS3 full-text search engine extension.
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, // 3.12.0 SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, // 3.12.0
//SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005, //SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005,
@@ -37,7 +36,7 @@ pub enum DbConfig {
SQLITE_DBCONFIG_RESET_DATABASE = 1009, // 3.24.0 SQLITE_DBCONFIG_RESET_DATABASE = 1009, // 3.24.0
/// Activates or deactivates the "defensive" flag for a database connection. /// Activates or deactivates the "defensive" flag for a database connection.
SQLITE_DBCONFIG_DEFENSIVE = 1010, // 3.26.0 SQLITE_DBCONFIG_DEFENSIVE = 1010, // 3.26.0
/// Activates or deactivates the "writable_schema" flag. /// Activates or deactivates the `writable_schema` flag.
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1011, // 3.28.0 SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1011, // 3.28.0
/// Activates or deactivates the legacy behavior of the ALTER TABLE RENAME /// Activates or deactivates the legacy behavior of the ALTER TABLE RENAME
@@ -59,11 +58,11 @@ pub enum DbConfig {
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT = 1016, // 3.31.0 SQLITE_DBCONFIG_LEGACY_FILE_FORMAT = 1016, // 3.31.0
/// Tells SQLite to assume that database schemas (the contents of the /// Tells SQLite to assume that database schemas (the contents of the
/// sqlite_master tables) are untainted by malicious content. /// `sqlite_master` tables) are untainted by malicious content.
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017, // 3.31.0 SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017, // 3.31.0
/// Sets or clears a flag that enables collection of the /// Sets or clears a flag that enables collection of the
/// sqlite3_stmt_scanstatus_v2() statistics /// `sqlite3_stmt_scanstatus_v2()` statistics
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
SQLITE_DBCONFIG_STMT_SCANSTATUS = 1018, // 3.42.0 SQLITE_DBCONFIG_STMT_SCANSTATUS = 1018, // 3.42.0
/// Changes the default order in which tables and indexes are scanned /// Changes the default order in which tables and indexes are scanned

View File

@@ -19,7 +19,7 @@ use crate::vtab::array::{free_array, ARRAY_TYPE};
#[inline] #[inline]
pub(super) unsafe fn set_result( pub(super) unsafe fn set_result(
ctx: *mut sqlite3_context, ctx: *mut sqlite3_context,
args: &[*mut sqlite3_value], #[allow(unused_variables)] args: &[*mut sqlite3_value],
result: &ToSqlOutput<'_>, result: &ToSqlOutput<'_>,
) { ) {
let value = match *result { let value = match *result {
@@ -55,10 +55,9 @@ pub(super) unsafe fn set_result(
if length > c_int::MAX as usize { if length > c_int::MAX as usize {
ffi::sqlite3_result_error_toobig(ctx); ffi::sqlite3_result_error_toobig(ctx);
} else { } else {
let (c_str, len, destructor) = match str_for_sqlite(s) { let Ok((c_str, len, destructor)) = str_for_sqlite(s) else {
Ok(c_str) => c_str,
// TODO sqlite3_result_error // TODO sqlite3_result_error
Err(_) => return ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), return ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE);
}; };
// TODO sqlite3_result_text64 // 3.8.7 // TODO sqlite3_result_text64 // 3.8.7
ffi::sqlite3_result_text(ctx, c_str, len, destructor); ffi::sqlite3_result_text(ctx, c_str, len, destructor);

View File

@@ -9,7 +9,6 @@ use std::str;
/// Enum listing possible errors from rusqlite. /// Enum listing possible errors from rusqlite.
#[derive(Debug)] #[derive(Debug)]
#[allow(clippy::enum_variant_names)]
#[non_exhaustive] #[non_exhaustive]
pub enum Error { pub enum Error {
/// An error from an underlying SQLite call. /// An error from an underlying SQLite call.
@@ -84,7 +83,6 @@ pub enum Error {
/// [`create_scalar_function`](crate::Connection::create_scalar_function)). /// [`create_scalar_function`](crate::Connection::create_scalar_function)).
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
#[cfg_attr(docsrs, doc(cfg(feature = "functions")))] #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
#[allow(dead_code)]
UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>), UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
/// Error available for the implementors of the /// Error available for the implementors of the
@@ -98,12 +96,9 @@ pub enum Error {
/// [`create_module`](crate::Connection::create_module)). /// [`create_module`](crate::Connection::create_module)).
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
#[cfg_attr(docsrs, doc(cfg(feature = "vtab")))] #[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
#[allow(dead_code)]
ModuleError(String), ModuleError(String),
/// An unwinding panic occurs in an UDF (user-defined function). /// An unwinding panic occurs in a UDF (user-defined function).
#[cfg(feature = "functions")]
#[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
UnwindingPanic, UnwindingPanic,
/// An error returned when /// An error returned when
@@ -145,59 +140,63 @@ pub enum Error {
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
#[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))] #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))]
InitError(ffi::InitError), InitError(ffi::InitError),
/// Error when the schema of a particular database is requested, but the index
/// is out of range.
#[cfg(feature = "modern_sqlite")] // 3.39.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
InvalidDatabaseIndex(usize),
} }
impl PartialEq for Error { impl PartialEq for Error {
fn eq(&self, other: &Error) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2, (Self::SqliteFailure(e1, s1), Self::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
(Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true, (Self::SqliteSingleThreadedMode, Self::SqliteSingleThreadedMode) => true,
(Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => { (Self::IntegralValueOutOfRange(i1, n1), Self::IntegralValueOutOfRange(i2, n2)) => {
i1 == i2 && n1 == n2 i1 == i2 && n1 == n2
} }
(Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2, (Self::Utf8Error(e1), Self::Utf8Error(e2)) => e1 == e2,
(Error::NulError(e1), Error::NulError(e2)) => e1 == e2, (Self::NulError(e1), Self::NulError(e2)) => e1 == e2,
(Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2, (Self::InvalidParameterName(n1), Self::InvalidParameterName(n2)) => n1 == n2,
(Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2, (Self::InvalidPath(p1), Self::InvalidPath(p2)) => p1 == p2,
(Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true, (Self::ExecuteReturnedResults, Self::ExecuteReturnedResults) => true,
(Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true, (Self::QueryReturnedNoRows, Self::QueryReturnedNoRows) => true,
(Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2, (Self::InvalidColumnIndex(i1), Self::InvalidColumnIndex(i2)) => i1 == i2,
(Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2, (Self::InvalidColumnName(n1), Self::InvalidColumnName(n2)) => n1 == n2,
(Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => { (Self::InvalidColumnType(i1, n1, t1), Self::InvalidColumnType(i2, n2, t2)) => {
i1 == i2 && t1 == t2 && n1 == n2 i1 == i2 && t1 == t2 && n1 == n2
} }
(Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2, (Self::StatementChangedRows(n1), Self::StatementChangedRows(n2)) => n1 == n2,
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
( (
Error::InvalidFunctionParameterType(i1, t1), Self::InvalidFunctionParameterType(i1, t1),
Error::InvalidFunctionParameterType(i2, t2), Self::InvalidFunctionParameterType(i2, t2),
) => i1 == i2 && t1 == t2, ) => i1 == i2 && t1 == t2,
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
( (
Error::InvalidFilterParameterType(i1, t1), Self::InvalidFilterParameterType(i1, t1),
Error::InvalidFilterParameterType(i2, t2), Self::InvalidFilterParameterType(i2, t2),
) => i1 == i2 && t1 == t2, ) => i1 == i2 && t1 == t2,
(Error::InvalidQuery, Error::InvalidQuery) => true, (Self::InvalidQuery, Self::InvalidQuery) => true,
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
(Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2, (Self::ModuleError(s1), Self::ModuleError(s2)) => s1 == s2,
(Self::UnwindingPanic, Self::UnwindingPanic) => true,
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
(Error::UnwindingPanic, Error::UnwindingPanic) => true, (Self::GetAuxWrongType, Self::GetAuxWrongType) => true,
#[cfg(feature = "functions")] (Self::InvalidParameterCount(i1, n1), Self::InvalidParameterCount(i2, n2)) => {
(Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
(Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
i1 == i2 && n1 == n2 i1 == i2 && n1 == n2
} }
#[cfg(feature = "blob")] #[cfg(feature = "blob")]
(Error::BlobSizeError, Error::BlobSizeError) => true, (Self::BlobSizeError, Self::BlobSizeError) => true,
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
( (
Error::SqlInputError { Self::SqlInputError {
error: e1, error: e1,
msg: m1, msg: m1,
sql: s1, sql: s1,
offset: o1, offset: o1,
}, },
Error::SqlInputError { Self::SqlInputError {
error: e2, error: e2,
msg: m2, msg: m2,
sql: s2, sql: s2,
@@ -205,7 +204,9 @@ impl PartialEq for Error {
}, },
) => e1 == e2 && m1 == m2 && s1 == s2 && o1 == o2, ) => e1 == e2 && m1 == m2 && s1 == s2 && o1 == o2,
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
(Error::InitError(e1), Error::InitError(e2)) => e1 == e2, (Self::InitError(e1), Self::InitError(e2)) => e1 == e2,
#[cfg(feature = "modern_sqlite")]
(Self::InvalidDatabaseIndex(i1), Self::InvalidDatabaseIndex(i2)) => i1 == i2,
(..) => false, (..) => false,
} }
} }
@@ -213,15 +214,15 @@ impl PartialEq for Error {
impl From<str::Utf8Error> for Error { impl From<str::Utf8Error> for Error {
#[cold] #[cold]
fn from(err: str::Utf8Error) -> Error { fn from(err: str::Utf8Error) -> Self {
Error::Utf8Error(err) Self::Utf8Error(err)
} }
} }
impl From<std::ffi::NulError> for Error { impl From<std::ffi::NulError> for Error {
#[cold] #[cold]
fn from(err: std::ffi::NulError) -> Error { fn from(err: std::ffi::NulError) -> Self {
Error::NulError(err) Self::NulError(err)
} }
} }
@@ -231,18 +232,18 @@ const UNKNOWN_COLUMN: usize = usize::MAX;
/// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`. /// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
impl From<FromSqlError> for Error { impl From<FromSqlError> for Error {
#[cold] #[cold]
fn from(err: FromSqlError) -> Error { fn from(err: FromSqlError) -> Self {
// The error type requires index and type fields, but they aren't known in this // The error type requires index and type fields, but they aren't known in this
// context. // context.
match err { match err {
FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val), FromSqlError::OutOfRange(val) => Self::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
FromSqlError::InvalidBlobSize { .. } => { FromSqlError::InvalidBlobSize { .. } => {
Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err)) Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
} }
FromSqlError::Other(source) => { FromSqlError::Other(source) => {
Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source) Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
} }
_ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)), _ => Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
} }
} }
} }
@@ -250,83 +251,84 @@ impl From<FromSqlError> for Error {
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
impl From<ffi::InitError> for Error { impl From<ffi::InitError> for Error {
#[cold] #[cold]
fn from(err: ffi::InitError) -> Error { fn from(err: ffi::InitError) -> Self {
Error::InitError(err) Self::InitError(err)
} }
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {
Error::SqliteFailure(ref err, None) => err.fmt(f), Self::SqliteFailure(ref err, None) => err.fmt(f),
Error::SqliteFailure(_, Some(ref s)) => write!(f, "{s}"), Self::SqliteFailure(_, Some(ref s)) => write!(f, "{s}"),
Error::SqliteSingleThreadedMode => write!( Self::SqliteSingleThreadedMode => write!(
f, f,
"SQLite was compiled or configured for single-threaded use only" "SQLite was compiled or configured for single-threaded use only"
), ),
Error::FromSqlConversionFailure(i, ref t, ref err) => { Self::FromSqlConversionFailure(i, ref t, ref err) => {
if i != UNKNOWN_COLUMN { if i != UNKNOWN_COLUMN {
write!(f, "Conversion error from type {t} at index: {i}, {err}") write!(f, "Conversion error from type {t} at index: {i}, {err}")
} else { } else {
err.fmt(f) err.fmt(f)
} }
} }
Error::IntegralValueOutOfRange(col, val) => { Self::IntegralValueOutOfRange(col, val) => {
if col != UNKNOWN_COLUMN { if col != UNKNOWN_COLUMN {
write!(f, "Integer {val} out of range at index {col}") write!(f, "Integer {val} out of range at index {col}")
} else { } else {
write!(f, "Integer {val} out of range") write!(f, "Integer {val} out of range")
} }
} }
Error::Utf8Error(ref err) => err.fmt(f), Self::Utf8Error(ref err) => err.fmt(f),
Error::NulError(ref err) => err.fmt(f), Self::NulError(ref err) => err.fmt(f),
Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {name}"), Self::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {name}"),
Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()), Self::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
Error::ExecuteReturnedResults => { Self::ExecuteReturnedResults => {
write!(f, "Execute returned results - did you mean to call query?") write!(f, "Execute returned results - did you mean to call query?")
} }
Error::QueryReturnedNoRows => write!(f, "Query returned no rows"), Self::QueryReturnedNoRows => write!(f, "Query returned no rows"),
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"), Self::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"),
Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"), Self::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"),
Error::InvalidColumnType(i, ref name, ref t) => { Self::InvalidColumnType(i, ref name, ref t) => {
write!(f, "Invalid column type {t} at index: {i}, name: {name}") write!(f, "Invalid column type {t} at index: {i}, name: {name}")
} }
Error::InvalidParameterCount(i1, n1) => write!( Self::InvalidParameterCount(i1, n1) => write!(
f, f,
"Wrong number of parameters passed to query. Got {i1}, needed {n1}" "Wrong number of parameters passed to query. Got {i1}, needed {n1}"
), ),
Error::StatementChangedRows(i) => write!(f, "Query changed {i} rows"), Self::StatementChangedRows(i) => write!(f, "Query changed {i} rows"),
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::InvalidFunctionParameterType(i, ref t) => { Self::InvalidFunctionParameterType(i, ref t) => {
write!(f, "Invalid function parameter type {t} at index {i}") write!(f, "Invalid function parameter type {t} at index {i}")
} }
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
Error::InvalidFilterParameterType(i, ref t) => { Self::InvalidFilterParameterType(i, ref t) => {
write!(f, "Invalid filter parameter type {t} at index {i}") write!(f, "Invalid filter parameter type {t} at index {i}")
} }
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::UserFunctionError(ref err) => err.fmt(f), Self::UserFunctionError(ref err) => err.fmt(f),
Error::ToSqlConversionFailure(ref err) => err.fmt(f), Self::ToSqlConversionFailure(ref err) => err.fmt(f),
Error::InvalidQuery => write!(f, "Query is not read-only"), Self::InvalidQuery => write!(f, "Query is not read-only"),
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
Error::ModuleError(ref desc) => write!(f, "{desc}"), Self::ModuleError(ref desc) => write!(f, "{desc}"),
Self::UnwindingPanic => write!(f, "unwinding panic"),
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::UnwindingPanic => write!(f, "unwinding panic"), Self::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
#[cfg(feature = "functions")] Self::MultipleStatement => write!(f, "Multiple statements provided"),
Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
Error::MultipleStatement => write!(f, "Multiple statements provided"),
#[cfg(feature = "blob")] #[cfg(feature = "blob")]
Error::BlobSizeError => "Blob size is insufficient".fmt(f), Self::BlobSizeError => "Blob size is insufficient".fmt(f),
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
Error::SqlInputError { Self::SqlInputError {
ref msg, ref msg,
offset, offset,
ref sql, ref sql,
.. ..
} => write!(f, "{msg} in {sql} at offset {offset}"), } => write!(f, "{msg} in {sql} at offset {offset}"),
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
Error::InitError(ref err) => err.fmt(f), Self::InitError(ref err) => err.fmt(f),
#[cfg(feature = "modern_sqlite")]
Self::InvalidDatabaseIndex(i) => write!(f, "Invalid database index: {i}"),
} }
} }
} }
@@ -334,50 +336,51 @@ impl fmt::Display for Error {
impl error::Error for Error { impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> { fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self { match *self {
Error::SqliteFailure(ref err, _) => Some(err), Self::SqliteFailure(ref err, _) => Some(err),
Error::Utf8Error(ref err) => Some(err), Self::Utf8Error(ref err) => Some(err),
Error::NulError(ref err) => Some(err), Self::NulError(ref err) => Some(err),
Error::IntegralValueOutOfRange(..) Self::IntegralValueOutOfRange(..)
| Error::SqliteSingleThreadedMode | Self::SqliteSingleThreadedMode
| Error::InvalidParameterName(_) | Self::InvalidParameterName(_)
| Error::ExecuteReturnedResults | Self::ExecuteReturnedResults
| Error::QueryReturnedNoRows | Self::QueryReturnedNoRows
| Error::InvalidColumnIndex(_) | Self::InvalidColumnIndex(_)
| Error::InvalidColumnName(_) | Self::InvalidColumnName(_)
| Error::InvalidColumnType(..) | Self::InvalidColumnType(..)
| Error::InvalidPath(_) | Self::InvalidPath(_)
| Error::InvalidParameterCount(..) | Self::InvalidParameterCount(..)
| Error::StatementChangedRows(_) | Self::StatementChangedRows(_)
| Error::InvalidQuery | Self::InvalidQuery
| Error::MultipleStatement => None, | Self::MultipleStatement => None,
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::InvalidFunctionParameterType(..) => None, Self::InvalidFunctionParameterType(..) => None,
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
Error::InvalidFilterParameterType(..) => None, Self::InvalidFilterParameterType(..) => None,
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::UserFunctionError(ref err) => Some(&**err), Self::UserFunctionError(ref err) => Some(&**err),
Error::FromSqlConversionFailure(_, _, ref err) Self::FromSqlConversionFailure(_, _, ref err)
| Error::ToSqlConversionFailure(ref err) => Some(&**err), | Self::ToSqlConversionFailure(ref err) => Some(&**err),
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
Error::ModuleError(_) => None, Self::ModuleError(_) => None,
Self::UnwindingPanic => None,
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::UnwindingPanic => None, Self::GetAuxWrongType => None,
#[cfg(feature = "functions")]
Error::GetAuxWrongType => None,
#[cfg(feature = "blob")] #[cfg(feature = "blob")]
Error::BlobSizeError => None, Self::BlobSizeError => None,
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
Error::SqlInputError { ref error, .. } => Some(error), Self::SqlInputError { ref error, .. } => Some(error),
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
Error::InitError(ref err) => Some(err), Self::InitError(ref err) => Some(err),
#[cfg(feature = "modern_sqlite")]
Self::InvalidDatabaseIndex(_) => None,
} }
} }
} }
@@ -409,14 +412,45 @@ pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
Error::SqliteFailure(ffi::Error::new(code), message) Error::SqliteFailure(ffi::Error::new(code), message)
} }
macro_rules! err {
($code:expr $(,)?) => {
$crate::error::error_from_sqlite_code($code, None)
};
($code:expr, $msg:literal $(,)?) => {
$crate::error::error_from_sqlite_code($code, Some(format!($msg)))
};
($code:expr, $err:expr $(,)?) => {
$crate::error::error_from_sqlite_code($code, Some(format!($err)))
};
($code:expr, $fmt:expr, $($arg:tt)*) => {
$crate::error::error_from_sqlite_code($code, Some(format!($fmt, $($arg)*)))
};
}
#[cold] #[cold]
pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error { pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
let message = if db.is_null() { error_from_sqlite_code(code, error_msg(db, code))
None }
unsafe fn error_msg(db: *mut ffi::sqlite3, code: c_int) -> Option<String> {
if db.is_null() || ffi::sqlite3_errcode(db) != code {
let err_str = ffi::sqlite3_errstr(code);
if err_str.is_null() {
None
} else {
Some(errmsg_to_string(err_str))
}
} else { } else {
Some(errmsg_to_string(ffi::sqlite3_errmsg(db))) Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
}; }
error_from_sqlite_code(code, message) }
pub unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
if code == ffi::SQLITE_OK {
Ok(())
} else {
Err(error_from_handle(db, code))
}
} }
#[cold] #[cold]
@@ -432,24 +466,24 @@ pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -
error_from_sqlite_code(code, None) error_from_sqlite_code(code, None)
} else { } else {
let error = ffi::Error::new(code); let error = ffi::Error::new(code);
let msg = errmsg_to_string(ffi::sqlite3_errmsg(db)); let msg = error_msg(db, code);
if ffi::ErrorCode::Unknown == error.code { if ffi::ErrorCode::Unknown == error.code {
let offset = ffi::sqlite3_error_offset(db); let offset = ffi::sqlite3_error_offset(db);
if offset >= 0 { if offset >= 0 {
return Error::SqlInputError { return Error::SqlInputError {
error, error,
msg, msg: msg.unwrap_or("error".to_owned()),
sql: sql.to_owned(), sql: sql.to_owned(),
offset, offset,
}; };
} }
} }
Error::SqliteFailure(error, Some(msg)) Error::SqliteFailure(error, msg)
} }
} }
pub fn check(code: c_int) -> Result<()> { pub fn check(code: c_int) -> Result<()> {
if code != crate::ffi::SQLITE_OK { if code != ffi::SQLITE_OK {
Err(error_from_sqlite_code(code, None)) Err(error_from_sqlite_code(code, None))
} else { } else {
Ok(()) Ok(())

View File

@@ -176,6 +176,11 @@ impl Context<'_> {
/// ///
/// See `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of /// See `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of
/// this feature, or the unit tests of this module for an example. /// this feature, or the unit tests of this module for an example.
///
/// # Failure
///
/// Will panic if `arg` is greater than or equal to
/// [`self.len()`](Context::len).
pub fn get_or_create_aux<T, E, F>(&self, arg: c_int, func: F) -> Result<Arc<T>> pub fn get_or_create_aux<T, E, F>(&self, arg: c_int, func: F) -> Result<Arc<T>>
where where
T: Send + Sync + 'static, T: Send + Sync + 'static,
@@ -196,7 +201,13 @@ impl Context<'_> {
/// Sets the auxiliary data associated with a particular parameter. See /// Sets the auxiliary data associated with a particular parameter. See
/// `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of /// `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of
/// this feature, or the unit tests of this module for an example. /// this feature, or the unit tests of this module for an example.
///
/// # Failure
///
/// Will panic if `arg` is greater than or equal to
/// [`self.len()`](Context::len).
pub fn set_aux<T: Send + Sync + 'static>(&self, arg: c_int, value: T) -> Result<Arc<T>> { pub fn set_aux<T: Send + Sync + 'static>(&self, arg: c_int, value: T) -> Result<Arc<T>> {
assert!(arg < self.len() as i32);
let orig: Arc<T> = Arc::new(value); let orig: Arc<T> = Arc::new(value);
let inner: AuxInner = orig.clone(); let inner: AuxInner = orig.clone();
let outer = Box::new(inner); let outer = Box::new(inner);
@@ -216,7 +227,13 @@ impl Context<'_> {
/// [`set_aux`](Context::set_aux). Returns `Ok(None)` if no data has been /// [`set_aux`](Context::set_aux). Returns `Ok(None)` if no data has been
/// associated, and Ok(Some(v)) if it has. Returns an error if the /// associated, and Ok(Some(v)) if it has. Returns an error if the
/// requested type does not match. /// requested type does not match.
///
/// # Failure
///
/// Will panic if `arg` is greater than or equal to
/// [`self.len()`](Context::len).
pub fn get_aux<T: Send + Sync + 'static>(&self, arg: c_int) -> Result<Option<Arc<T>>> { pub fn get_aux<T: Send + Sync + 'static>(&self, arg: c_int) -> Result<Option<Arc<T>>> {
assert!(arg < self.len() as i32);
let p = unsafe { ffi::sqlite3_get_auxdata(self.ctx, arg) as *const AuxInner }; let p = unsafe { ffi::sqlite3_get_auxdata(self.ctx, arg) as *const AuxInner };
if p.is_null() { if p.is_null() {
Ok(None) Ok(None)
@@ -267,7 +284,7 @@ pub type SubType = Option<std::os::raw::c_uint>;
/// Result of an SQL function /// Result of an SQL function
pub trait SqlFnOutput { pub trait SqlFnOutput {
/// Converts Rust value to SQLite value with an optional sub-type /// Converts Rust value to SQLite value with an optional subtype
fn to_sql(&self) -> Result<(ToSqlOutput<'_>, SubType)>; fn to_sql(&self) -> Result<(ToSqlOutput<'_>, SubType)>;
} }
@@ -368,7 +385,7 @@ bitflags::bitflags! {
/// and [Function Flags](https://sqlite.org/c3ref/c_deterministic.html) for details. /// and [Function Flags](https://sqlite.org/c3ref/c_deterministic.html) for details.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct FunctionFlags: ::std::os::raw::c_int { pub struct FunctionFlags: c_int {
/// Specifies UTF-8 as the text encoding this SQL function prefers for its parameters. /// Specifies UTF-8 as the text encoding this SQL function prefers for its parameters.
const SQLITE_UTF8 = ffi::SQLITE_UTF8; const SQLITE_UTF8 = ffi::SQLITE_UTF8;
/// Specifies UTF-16 using little-endian byte order as the text encoding this SQL function prefers for its parameters. /// Specifies UTF-16 using little-endian byte order as the text encoding this SQL function prefers for its parameters.
@@ -381,19 +398,21 @@ bitflags::bitflags! {
const SQLITE_DETERMINISTIC = ffi::SQLITE_DETERMINISTIC; // 3.8.3 const SQLITE_DETERMINISTIC = ffi::SQLITE_DETERMINISTIC; // 3.8.3
/// Means that the function may only be invoked from top-level SQL. /// Means that the function may only be invoked from top-level SQL.
const SQLITE_DIRECTONLY = 0x0000_0008_0000; // 3.30.0 const SQLITE_DIRECTONLY = 0x0000_0008_0000; // 3.30.0
/// Indicates to SQLite that a function may call `sqlite3_value_subtype()` to inspect the sub-types of its arguments. /// Indicates to SQLite that a function may call `sqlite3_value_subtype()` to inspect the subtypes of its arguments.
const SQLITE_SUBTYPE = 0x0000_0010_0000; // 3.30.0 const SQLITE_SUBTYPE = 0x0000_0010_0000; // 3.30.0
/// Means that the function is unlikely to cause problems even if misused. /// Means that the function is unlikely to cause problems even if misused.
const SQLITE_INNOCUOUS = 0x0000_0020_0000; // 3.31.0 const SQLITE_INNOCUOUS = 0x0000_0020_0000; // 3.31.0
/// Indicates to SQLite that a function might call `sqlite3_result_subtype()` to cause a sub-type to be associated with its result. /// Indicates to SQLite that a function might call `sqlite3_result_subtype()` to cause a subtype to be associated with its result.
const SQLITE_RESULT_SUBTYPE = 0x0000_0100_0000; // 3.45.0 const SQLITE_RESULT_SUBTYPE = 0x0000_0100_0000; // 3.45.0
/// Indicates that the function is an aggregate that internally orders the values provided to the first argument.
const SQLITE_SELFORDER1 = 0x0000_0200_0000; // 3.47.0
} }
} }
impl Default for FunctionFlags { impl Default for FunctionFlags {
#[inline] #[inline]
fn default() -> FunctionFlags { fn default() -> Self {
FunctionFlags::SQLITE_UTF8 Self::SQLITE_UTF8
} }
} }
@@ -444,7 +463,7 @@ impl Connection {
x_func: F, x_func: F,
) -> Result<()> ) -> Result<()>
where where
F: FnMut(&Context<'_>) -> Result<T> + Send + UnwindSafe + 'static, F: Fn(&Context<'_>) -> Result<T> + Send + 'static,
T: SqlFnOutput, T: SqlFnOutput,
{ {
self.db self.db
@@ -518,6 +537,27 @@ impl Connection {
} }
impl InnerConnection { impl InnerConnection {
/// ```compile_fail
/// use rusqlite::{functions::FunctionFlags, Connection, Result};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.create_scalar_function(
/// "test",
/// 0,
/// FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
/// |_| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// Ok(true)
/// },
/// );
/// }
/// let result: Result<bool> = db.query_row("SELECT test()", [], |r| r.get(0));
/// assert!(result?);
/// Ok(())
/// }
/// ```
fn create_scalar_function<F, T>( fn create_scalar_function<F, T>(
&mut self, &mut self,
fn_name: &str, fn_name: &str,
@@ -526,7 +566,7 @@ impl InnerConnection {
x_func: F, x_func: F,
) -> Result<()> ) -> Result<()>
where where
F: FnMut(&Context<'_>) -> Result<T> + Send + UnwindSafe + 'static, F: Fn(&Context<'_>) -> Result<T> + Send + 'static,
T: SqlFnOutput, T: SqlFnOutput,
{ {
unsafe extern "C" fn call_boxed_closure<F, T>( unsafe extern "C" fn call_boxed_closure<F, T>(
@@ -534,12 +574,12 @@ impl InnerConnection {
argc: c_int, argc: c_int,
argv: *mut *mut sqlite3_value, argv: *mut *mut sqlite3_value,
) where ) where
F: FnMut(&Context<'_>) -> Result<T>, F: Fn(&Context<'_>) -> Result<T>,
T: SqlFnOutput, T: SqlFnOutput,
{ {
let args = slice::from_raw_parts(argv, argc as usize); let args = slice::from_raw_parts(argv, argc as usize);
let r = catch_unwind(|| { let r = catch_unwind(|| {
let boxed_f: *mut F = ffi::sqlite3_user_data(ctx).cast::<F>(); let boxed_f: *const F = ffi::sqlite3_user_data(ctx).cast::<F>();
assert!(!boxed_f.is_null(), "Internal error - null function pointer"); assert!(!boxed_f.is_null(), "Internal error - null function pointer");
let ctx = Context { ctx, args }; let ctx = Context { ctx, args };
(*boxed_f)(&ctx) (*boxed_f)(&ctx)
@@ -670,9 +710,7 @@ unsafe extern "C" fn call_boxed_step<A, D, T>(
D: Aggregate<A, T>, D: Aggregate<A, T>,
T: SqlFnOutput, T: SqlFnOutput,
{ {
let pac = if let Some(pac) = aggregate_context(ctx, std::mem::size_of::<*mut A>()) { let Some(pac) = aggregate_context(ctx, size_of::<*mut A>()) else {
pac
} else {
ffi::sqlite3_result_error_nomem(ctx); ffi::sqlite3_result_error_nomem(ctx);
return; return;
}; };
@@ -688,7 +726,7 @@ unsafe extern "C" fn call_boxed_step<A, D, T>(
args: slice::from_raw_parts(argv, argc as usize), args: slice::from_raw_parts(argv, argc as usize),
}; };
#[allow(clippy::unnecessary_cast)] #[expect(clippy::unnecessary_cast)]
if (*pac as *mut A).is_null() { if (*pac as *mut A).is_null() {
*pac = Box::into_raw(Box::new((*boxed_aggr).init(&mut ctx)?)); *pac = Box::into_raw(Box::new((*boxed_aggr).init(&mut ctx)?));
} }
@@ -718,9 +756,7 @@ unsafe extern "C" fn call_boxed_inverse<A, W, T>(
W: WindowAggregate<A, T>, W: WindowAggregate<A, T>,
T: SqlFnOutput, T: SqlFnOutput,
{ {
let pac = if let Some(pac) = aggregate_context(ctx, std::mem::size_of::<*mut A>()) { let Some(pac) = aggregate_context(ctx, size_of::<*mut A>()) else {
pac
} else {
ffi::sqlite3_result_error_nomem(ctx); ffi::sqlite3_result_error_nomem(ctx);
return; return;
}; };
@@ -761,7 +797,7 @@ where
let a: Option<A> = match aggregate_context(ctx, 0) { let a: Option<A> = match aggregate_context(ctx, 0) {
Some(pac) => Some(pac) =>
{ {
#[allow(clippy::unnecessary_cast)] #[expect(clippy::unnecessary_cast)]
if (*pac as *mut A).is_null() { if (*pac as *mut A).is_null() {
None None
} else { } else {
@@ -801,7 +837,7 @@ where
// Within the xValue callback, it is customary to set N=0 in calls to // Within the xValue callback, it is customary to set N=0 in calls to
// sqlite3_aggregate_context(C,N) so that no pointless memory allocations occur. // sqlite3_aggregate_context(C,N) so that no pointless memory allocations occur.
let pac = aggregate_context(ctx, 0).filter(|&pac| { let pac = aggregate_context(ctx, 0).filter(|&pac| {
#[allow(clippy::unnecessary_cast)] #[expect(clippy::unnecessary_cast)]
!(*pac as *mut A).is_null() !(*pac as *mut A).is_null()
}); });
@@ -834,7 +870,14 @@ mod test {
use crate::{Connection, Error, Result}; use crate::{Connection, Error, Result};
fn half(ctx: &Context<'_>) -> Result<c_double> { fn half(ctx: &Context<'_>) -> Result<c_double> {
assert!(!ctx.is_empty());
assert_eq!(ctx.len(), 1, "called with unexpected number of arguments"); assert_eq!(ctx.len(), 1, "called with unexpected number of arguments");
assert!(unsafe {
ctx.get_connection()
.as_ref()
.map(::std::ops::Deref::deref)
.is_ok()
});
let value = ctx.get::<c_double>(0)?; let value = ctx.get::<c_double>(0)?;
Ok(value / 2f64) Ok(value / 2f64)
} }

View File

@@ -1,19 +1,24 @@
//! Commit, Data Change and Rollback Notification Callbacks //! Commit, Data Change and Rollback Notification Callbacks
#![allow(non_camel_case_types)] #![expect(non_camel_case_types)]
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::panic::{catch_unwind, RefUnwindSafe}; use std::panic::catch_unwind;
use std::ptr; use std::ptr;
use crate::ffi; use crate::ffi;
use crate::{Connection, InnerConnection}; use crate::{error::decode_result_raw, Connection, DatabaseName, InnerConnection, Result};
#[cfg(feature = "preupdate_hook")]
pub use preupdate_hook::*;
#[cfg(feature = "preupdate_hook")]
mod preupdate_hook;
/// Action Codes /// Action Codes
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(i32)] #[repr(i32)]
#[non_exhaustive] #[non_exhaustive]
#[allow(clippy::upper_case_acronyms)]
pub enum Action { pub enum Action {
/// Unsupported / unexpected action /// Unsupported / unexpected action
UNKNOWN = -1, UNKNOWN = -1,
@@ -27,12 +32,12 @@ pub enum Action {
impl From<i32> for Action { impl From<i32> for Action {
#[inline] #[inline]
fn from(code: i32) -> Action { fn from(code: i32) -> Self {
match code { match code {
ffi::SQLITE_DELETE => Action::SQLITE_DELETE, ffi::SQLITE_DELETE => Self::SQLITE_DELETE,
ffi::SQLITE_INSERT => Action::SQLITE_INSERT, ffi::SQLITE_INSERT => Self::SQLITE_INSERT,
ffi::SQLITE_UPDATE => Action::SQLITE_UPDATE, ffi::SQLITE_UPDATE => Self::SQLITE_UPDATE,
_ => Action::UNKNOWN, _ => Self::UNKNOWN,
} }
} }
} }
@@ -366,7 +371,7 @@ impl Connection {
/// The callback parameters are: /// The callback parameters are:
/// ///
/// - the type of database update (`SQLITE_INSERT`, `SQLITE_UPDATE` or /// - the type of database update (`SQLITE_INSERT`, `SQLITE_UPDATE` or
/// `SQLITE_DELETE`), /// `SQLITE_DELETE`),
/// - the name of the database ("main", "temp", ...), /// - the name of the database ("main", "temp", ...),
/// - the name of the table that is updated, /// - the name of the table that is updated,
/// - the ROWID of the row that is updated. /// - the ROWID of the row that is updated.
@@ -378,6 +383,38 @@ impl Connection {
self.db.borrow_mut().update_hook(hook); self.db.borrow_mut().update_hook(hook);
} }
/// Register a callback that is invoked each time data is committed to a database in wal mode.
///
/// A single database handle may have at most a single write-ahead log callback registered at one time.
/// Calling `wal_hook` replaces any previously registered write-ahead log callback.
/// Note that the `sqlite3_wal_autocheckpoint()` interface and the `wal_autocheckpoint` pragma
/// both invoke `sqlite3_wal_hook()` and will overwrite any prior `sqlite3_wal_hook()` settings.
pub fn wal_hook(&self, hook: Option<fn(&Wal, c_int) -> Result<()>>) {
unsafe extern "C" fn wal_hook_callback(
client_data: *mut c_void,
db: *mut ffi::sqlite3,
db_name: *const c_char,
pages: c_int,
) -> c_int {
let hook_fn: fn(&Wal, c_int) -> Result<()> = std::mem::transmute(client_data);
let wal = Wal { db, db_name };
catch_unwind(|| match hook_fn(&wal, pages) {
Ok(_) => ffi::SQLITE_OK,
Err(e) => e
.sqlite_error()
.map_or(ffi::SQLITE_ERROR, |x| x.extended_code),
})
.unwrap_or_default()
}
let c = self.db.borrow_mut();
match hook {
Some(f) => unsafe {
ffi::sqlite3_wal_hook(c.db(), Some(wal_hook_callback), f as *mut c_void)
},
None => unsafe { ffi::sqlite3_wal_hook(c.db(), None, ptr::null_mut()) },
};
}
/// Register a query progress callback. /// Register a query progress callback.
/// ///
/// The parameter `num_ops` is the approximate number of virtual machine /// The parameter `num_ops` is the approximate number of virtual machine
@@ -388,7 +425,7 @@ impl Connection {
/// If the progress callback returns `true`, the operation is interrupted. /// If the progress callback returns `true`, the operation is interrupted.
pub fn progress_handler<F>(&self, num_ops: c_int, handler: Option<F>) pub fn progress_handler<F>(&self, num_ops: c_int, handler: Option<F>)
where where
F: FnMut() -> bool + Send + RefUnwindSafe + 'static, F: FnMut() -> bool + Send + 'static,
{ {
self.db.borrow_mut().progress_handler(num_ops, handler); self.db.borrow_mut().progress_handler(num_ops, handler);
} }
@@ -398,12 +435,63 @@ impl Connection {
#[inline] #[inline]
pub fn authorizer<'c, F>(&self, hook: Option<F>) pub fn authorizer<'c, F>(&self, hook: Option<F>)
where where
F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + RefUnwindSafe + 'static, F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + 'static,
{ {
self.db.borrow_mut().authorizer(hook); self.db.borrow_mut().authorizer(hook);
} }
} }
/// Checkpoint mode
#[derive(Clone, Copy)]
#[repr(i32)]
#[non_exhaustive]
pub enum CheckpointMode {
/// Do as much as possible w/o blocking
PASSIVE = ffi::SQLITE_CHECKPOINT_PASSIVE,
/// Wait for writers, then checkpoint
FULL = ffi::SQLITE_CHECKPOINT_FULL,
/// Like FULL but wait for readers
RESTART = ffi::SQLITE_CHECKPOINT_RESTART,
/// Like RESTART but also truncate WAL
TRUNCATE = ffi::SQLITE_CHECKPOINT_TRUNCATE,
}
/// Write-Ahead Log
pub struct Wal {
db: *mut ffi::sqlite3,
db_name: *const c_char,
}
impl Wal {
/// Checkpoint a database
pub fn checkpoint(&self) -> Result<()> {
unsafe { decode_result_raw(self.db, ffi::sqlite3_wal_checkpoint(self.db, self.db_name)) }
}
/// Checkpoint a database
pub fn checkpoint_v2(&self, mode: CheckpointMode) -> Result<(c_int, c_int)> {
let mut n_log = 0;
let mut n_ckpt = 0;
unsafe {
decode_result_raw(
self.db,
ffi::sqlite3_wal_checkpoint_v2(
self.db,
self.db_name,
mode as c_int,
&mut n_log,
&mut n_ckpt,
),
)?
};
Ok((n_log, n_ckpt))
}
/// Name of the database that was written to
pub fn name(&self) -> DatabaseName<'_> {
DatabaseName::from_cstr(unsafe { std::ffi::CStr::from_ptr(self.db_name) })
}
}
impl InnerConnection { impl InnerConnection {
#[inline] #[inline]
pub fn remove_hooks(&mut self) { pub fn remove_hooks(&mut self) {
@@ -414,6 +502,27 @@ impl InnerConnection {
self.authorizer(None::<fn(AuthContext<'_>) -> Authorization>); self.authorizer(None::<fn(AuthContext<'_>) -> Authorization>);
} }
/// ```compile_fail
/// use rusqlite::{Connection, Result};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.commit_hook(Some(|| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// true
/// }));
/// }
/// assert!(db
/// .execute_batch(
/// "BEGIN;
/// CREATE TABLE foo (t TEXT);
/// COMMIT;",
/// )
/// .is_err());
/// Ok(())
/// }
/// ```
fn commit_hook<F>(&mut self, hook: Option<F>) fn commit_hook<F>(&mut self, hook: Option<F>)
where where
F: FnMut() -> bool + Send + 'static, F: FnMut() -> bool + Send + 'static,
@@ -459,6 +568,26 @@ impl InnerConnection {
self.free_commit_hook = free_commit_hook; self.free_commit_hook = free_commit_hook;
} }
/// ```compile_fail
/// use rusqlite::{Connection, Result};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.rollback_hook(Some(|| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// }));
/// }
/// assert!(db
/// .execute_batch(
/// "BEGIN;
/// CREATE TABLE foo (t TEXT);
/// ROLLBACK;",
/// )
/// .is_err());
/// Ok(())
/// }
/// ```
fn rollback_hook<F>(&mut self, hook: Option<F>) fn rollback_hook<F>(&mut self, hook: Option<F>)
where where
F: FnMut() + Send + 'static, F: FnMut() + Send + 'static,
@@ -500,6 +629,19 @@ impl InnerConnection {
self.free_rollback_hook = free_rollback_hook; self.free_rollback_hook = free_rollback_hook;
} }
/// ```compile_fail
/// use rusqlite::{Connection, Result};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.update_hook(Some(|_, _: &str, _: &str, _| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// }));
/// }
/// db.execute_batch("CREATE TABLE foo AS SELECT 1 AS bar;")
/// }
/// ```
fn update_hook<F>(&mut self, hook: Option<F>) fn update_hook<F>(&mut self, hook: Option<F>)
where where
F: FnMut(Action, &str, &str, i64) + Send + 'static, F: FnMut(Action, &str, &str, i64) + Send + 'static,
@@ -552,9 +694,29 @@ impl InnerConnection {
self.free_update_hook = free_update_hook; self.free_update_hook = free_update_hook;
} }
/// ```compile_fail
/// use rusqlite::{Connection, Result};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.progress_handler(
/// 1,
/// Some(|| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// true
/// }),
/// );
/// }
/// assert!(db
/// .execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
/// .is_err());
/// Ok(())
/// }
/// ```
fn progress_handler<F>(&mut self, num_ops: c_int, handler: Option<F>) fn progress_handler<F>(&mut self, num_ops: c_int, handler: Option<F>)
where where
F: FnMut() -> bool + Send + RefUnwindSafe + 'static, F: FnMut() -> bool + Send + 'static,
{ {
unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void) -> c_int unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void) -> c_int
where where
@@ -584,9 +746,26 @@ impl InnerConnection {
}; };
} }
/// ```compile_fail
/// use rusqlite::{Connection, Result};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.authorizer(Some(|_: rusqlite::hooks::AuthContext<'_>| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// rusqlite::hooks::Authorization::Deny
/// }));
/// }
/// assert!(db
/// .execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
/// .is_err());
/// Ok(())
/// }
/// ```
fn authorizer<'c, F>(&'c mut self, authorizer: Option<F>) fn authorizer<'c, F>(&'c mut self, authorizer: Option<F>)
where where
F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + RefUnwindSafe + 'static, F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + 'static,
{ {
unsafe extern "C" fn call_boxed_closure<'c, F>( unsafe extern "C" fn call_boxed_closure<'c, F>(
p_arg: *mut c_void, p_arg: *mut c_void,
@@ -666,7 +845,8 @@ unsafe fn expect_optional_utf8<'a>(
if p_str.is_null() { if p_str.is_null() {
return None; return None;
} }
std::str::from_utf8(std::ffi::CStr::from_ptr(p_str).to_bytes()) std::ffi::CStr::from_ptr(p_str)
.to_str()
.unwrap_or_else(|_| panic!("received non-utf8 string as {description}")) .unwrap_or_else(|_| panic!("received non-utf8 string as {description}"))
.into() .into()
} }
@@ -674,7 +854,7 @@ unsafe fn expect_optional_utf8<'a>(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Action; use super::Action;
use crate::{Connection, Result}; use crate::{Connection, DatabaseName, Result};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
#[test] #[test]
@@ -772,8 +952,7 @@ mod test {
use super::{AuthAction, AuthContext, Authorization}; use super::{AuthAction, AuthContext, Authorization};
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (public TEXT, private TEXT)") db.execute_batch("CREATE TABLE foo (public TEXT, private TEXT)")?;
.unwrap();
let authorizer = move |ctx: AuthContext<'_>| match ctx.action { let authorizer = move |ctx: AuthContext<'_>| match ctx.action {
AuthAction::Read { AuthAction::Read {
@@ -788,19 +967,50 @@ mod test {
db.authorizer(Some(authorizer)); db.authorizer(Some(authorizer));
db.execute_batch( db.execute_batch(
"BEGIN TRANSACTION; INSERT INTO foo VALUES ('pub txt', 'priv txt'); COMMIT;", "BEGIN TRANSACTION; INSERT INTO foo VALUES ('pub txt', 'priv txt'); COMMIT;",
) )?;
.unwrap();
db.query_row_and_then("SELECT * FROM foo", [], |row| -> Result<()> { db.query_row_and_then("SELECT * FROM foo", [], |row| -> Result<()> {
assert_eq!(row.get::<_, String>("public")?, "pub txt"); assert_eq!(row.get::<_, String>("public")?, "pub txt");
assert!(row.get::<_, Option<String>>("private")?.is_none()); assert!(row.get::<_, Option<String>>("private")?.is_none());
Ok(()) Ok(())
}) })?;
.unwrap();
db.execute_batch("DROP TABLE foo").unwrap_err(); db.execute_batch("DROP TABLE foo").unwrap_err();
db.authorizer(None::<fn(AuthContext<'_>) -> Authorization>); db.authorizer(None::<fn(AuthContext<'_>) -> Authorization>);
db.execute_batch("PRAGMA user_version=1").unwrap(); // Disallowed by first authorizer, but it's now removed. db.execute_batch("PRAGMA user_version=1")?; // Disallowed by first authorizer, but it's now removed.
Ok(()) Ok(())
} }
#[test]
fn wal_hook() -> Result<()> {
let temp_dir = tempfile::tempdir().unwrap();
let path = temp_dir.path().join("wal-hook.db3");
let db = Connection::open(&path)?;
let journal_mode: String =
db.pragma_update_and_check(None, "journal_mode", "wal", |row| row.get(0))?;
assert_eq!(journal_mode, "wal");
static CALLED: AtomicBool = AtomicBool::new(false);
db.wal_hook(Some(|wal, pages| {
assert_eq!(wal.name(), DatabaseName::Main);
assert!(pages > 0);
CALLED.swap(true, Ordering::Relaxed);
wal.checkpoint()
}));
db.execute_batch("CREATE TABLE x(c);")?;
assert!(CALLED.load(Ordering::Relaxed));
db.wal_hook(Some(|wal, pages| {
assert!(pages > 0);
let (log, ckpt) = wal.checkpoint_v2(super::CheckpointMode::TRUNCATE)?;
assert_eq!(log, 0);
assert_eq!(ckpt, 0);
Ok(())
}));
db.execute_batch("CREATE TABLE y(c);")?;
db.wal_hook(None);
Ok(())
}
} }

View File

@@ -0,0 +1,372 @@
use std::fmt::Debug;
use std::os::raw::{c_char, c_int, c_void};
use std::panic::catch_unwind;
use std::ptr;
use super::expect_utf8;
use super::free_boxed_hook;
use super::Action;
use crate::error::check;
use crate::ffi;
use crate::inner_connection::InnerConnection;
use crate::types::ValueRef;
use crate::Connection;
use crate::Result;
/// The possible cases for when a PreUpdateHook gets triggered. Allows access to the relevant
/// functions for each case through the contained values.
#[derive(Debug)]
pub enum PreUpdateCase {
/// Pre-update hook was triggered by an insert.
Insert(PreUpdateNewValueAccessor),
/// Pre-update hook was triggered by a delete.
Delete(PreUpdateOldValueAccessor),
/// Pre-update hook was triggered by an update.
Update {
#[allow(missing_docs)]
old_value_accessor: PreUpdateOldValueAccessor,
#[allow(missing_docs)]
new_value_accessor: PreUpdateNewValueAccessor,
},
/// This variant is not normally produced by SQLite. You may encounter it
/// if you're using a different version than what's supported by this library.
Unknown,
}
impl From<PreUpdateCase> for Action {
fn from(puc: PreUpdateCase) -> Action {
match puc {
PreUpdateCase::Insert(_) => Action::SQLITE_INSERT,
PreUpdateCase::Delete(_) => Action::SQLITE_DELETE,
PreUpdateCase::Update { .. } => Action::SQLITE_UPDATE,
PreUpdateCase::Unknown => Action::UNKNOWN,
}
}
}
/// An accessor to access the old values of the row being deleted/updated during the preupdate callback.
#[derive(Debug)]
pub struct PreUpdateOldValueAccessor {
db: *mut ffi::sqlite3,
old_row_id: i64,
}
impl PreUpdateOldValueAccessor {
/// Get the amount of columns in the row being deleted/updated.
pub fn get_column_count(&self) -> i32 {
unsafe { ffi::sqlite3_preupdate_count(self.db) }
}
/// Get the depth of the query that triggered the preupdate hook.
/// Returns 0 if the preupdate callback was invoked as a result of
/// a direct insert, update, or delete operation;
/// 1 for inserts, updates, or deletes invoked by top-level triggers;
/// 2 for changes resulting from triggers called by top-level triggers; and so forth.
pub fn get_query_depth(&self) -> i32 {
unsafe { ffi::sqlite3_preupdate_depth(self.db) }
}
/// Get the row id of the row being updated/deleted.
pub fn get_old_row_id(&self) -> i64 {
self.old_row_id
}
/// Get the value of the row being updated/deleted at the specified index.
pub fn get_old_column_value(&self, i: i32) -> Result<ValueRef> {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
unsafe {
check(ffi::sqlite3_preupdate_old(self.db, i, &mut p_value))?;
Ok(ValueRef::from_value(p_value))
}
}
}
/// An accessor to access the new values of the row being inserted/updated
/// during the preupdate callback.
#[derive(Debug)]
pub struct PreUpdateNewValueAccessor {
db: *mut ffi::sqlite3,
new_row_id: i64,
}
impl PreUpdateNewValueAccessor {
/// Get the amount of columns in the row being inserted/updated.
pub fn get_column_count(&self) -> i32 {
unsafe { ffi::sqlite3_preupdate_count(self.db) }
}
/// Get the depth of the query that triggered the preupdate hook.
/// Returns 0 if the preupdate callback was invoked as a result of
/// a direct insert, update, or delete operation;
/// 1 for inserts, updates, or deletes invoked by top-level triggers;
/// 2 for changes resulting from triggers called by top-level triggers; and so forth.
pub fn get_query_depth(&self) -> i32 {
unsafe { ffi::sqlite3_preupdate_depth(self.db) }
}
/// Get the row id of the row being inserted/updated.
pub fn get_new_row_id(&self) -> i64 {
self.new_row_id
}
/// Get the value of the row being updated/deleted at the specified index.
pub fn get_new_column_value(&self, i: i32) -> Result<ValueRef> {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
unsafe {
check(ffi::sqlite3_preupdate_new(self.db, i, &mut p_value))?;
Ok(ValueRef::from_value(p_value))
}
}
}
impl Connection {
/// Register a callback function to be invoked before
/// a row is updated, inserted or deleted.
///
/// The callback parameters are:
///
/// - the name of the database ("main", "temp", ...),
/// - the name of the table that is updated,
/// - a variant of the PreUpdateCase enum which allows access to extra functions depending
/// on whether it's an update, delete or insert.
#[inline]
pub fn preupdate_hook<F>(&self, hook: Option<F>)
where
F: FnMut(Action, &str, &str, &PreUpdateCase) + Send + 'static,
{
self.db.borrow_mut().preupdate_hook(hook);
}
}
impl InnerConnection {
#[inline]
pub fn remove_preupdate_hook(&mut self) {
self.preupdate_hook(None::<fn(Action, &str, &str, &PreUpdateCase)>);
}
/// ```compile_fail
/// use rusqlite::{Connection, Result, hooks::PreUpdateCase};
/// fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// {
/// let mut called = std::sync::atomic::AtomicBool::new(false);
/// db.preupdate_hook(Some(|action, db: &str, tbl: &str, case: &PreUpdateCase| {
/// called.store(true, std::sync::atomic::Ordering::Relaxed);
/// }));
/// }
/// db.execute_batch("CREATE TABLE foo AS SELECT 1 AS bar;")
/// }
/// ```
fn preupdate_hook<F>(&mut self, hook: Option<F>)
where
F: FnMut(Action, &str, &str, &PreUpdateCase) + Send + 'static,
{
unsafe extern "C" fn call_boxed_closure<F>(
p_arg: *mut c_void,
sqlite: *mut ffi::sqlite3,
action_code: c_int,
db_name: *const c_char,
tbl_name: *const c_char,
old_row_id: i64,
new_row_id: i64,
) where
F: FnMut(Action, &str, &str, &PreUpdateCase),
{
let action = Action::from(action_code);
let preupdate_case = match action {
Action::SQLITE_INSERT => PreUpdateCase::Insert(PreUpdateNewValueAccessor {
db: sqlite,
new_row_id,
}),
Action::SQLITE_DELETE => PreUpdateCase::Delete(PreUpdateOldValueAccessor {
db: sqlite,
old_row_id,
}),
Action::SQLITE_UPDATE => PreUpdateCase::Update {
old_value_accessor: PreUpdateOldValueAccessor {
db: sqlite,
old_row_id,
},
new_value_accessor: PreUpdateNewValueAccessor {
db: sqlite,
new_row_id,
},
},
Action::UNKNOWN => PreUpdateCase::Unknown,
};
drop(catch_unwind(|| {
let boxed_hook: *mut F = p_arg.cast::<F>();
(*boxed_hook)(
action,
expect_utf8(db_name, "database name"),
expect_utf8(tbl_name, "table name"),
&preupdate_case,
);
}));
}
let free_preupdate_hook = if hook.is_some() {
Some(free_boxed_hook::<F> as unsafe fn(*mut c_void))
} else {
None
};
let previous_hook = match hook {
Some(hook) => {
let boxed_hook: *mut F = Box::into_raw(Box::new(hook));
unsafe {
ffi::sqlite3_preupdate_hook(
self.db(),
Some(call_boxed_closure::<F>),
boxed_hook.cast(),
)
}
}
_ => unsafe { ffi::sqlite3_preupdate_hook(self.db(), None, ptr::null_mut()) },
};
if !previous_hook.is_null() {
if let Some(free_boxed_hook) = self.free_preupdate_hook {
unsafe { free_boxed_hook(previous_hook) };
}
}
self.free_preupdate_hook = free_preupdate_hook;
}
}
#[cfg(test)]
mod test {
use std::sync::atomic::{AtomicBool, Ordering};
use super::super::Action;
use super::PreUpdateCase;
use crate::{Connection, Result};
#[test]
fn test_preupdate_hook_insert() -> Result<()> {
let db = Connection::open_in_memory()?;
static CALLED: AtomicBool = AtomicBool::new(false);
db.preupdate_hook(Some(|action, db: &str, tbl: &str, case: &PreUpdateCase| {
assert_eq!(Action::SQLITE_INSERT, action);
assert_eq!("main", db);
assert_eq!("foo", tbl);
match case {
PreUpdateCase::Insert(accessor) => {
assert_eq!(1, accessor.get_column_count());
assert_eq!(1, accessor.get_new_row_id());
assert_eq!(0, accessor.get_query_depth());
// out of bounds access should return an error
assert!(accessor.get_new_column_value(1).is_err());
assert_eq!(
"lisa",
accessor.get_new_column_value(0).unwrap().as_str().unwrap()
);
assert_eq!(0, accessor.get_query_depth());
}
_ => panic!("wrong preupdate case"),
}
CALLED.store(true, Ordering::Relaxed);
}));
db.execute_batch("CREATE TABLE foo (t TEXT)")?;
db.execute_batch("INSERT INTO foo VALUES ('lisa')")?;
assert!(CALLED.load(Ordering::Relaxed));
Ok(())
}
#[test]
fn test_preupdate_hook_delete() -> Result<()> {
let db = Connection::open_in_memory()?;
static CALLED: AtomicBool = AtomicBool::new(false);
db.execute_batch("CREATE TABLE foo (t TEXT)")?;
db.execute_batch("INSERT INTO foo VALUES ('lisa')")?;
db.preupdate_hook(Some(|action, db: &str, tbl: &str, case: &PreUpdateCase| {
assert_eq!(Action::SQLITE_DELETE, action);
assert_eq!("main", db);
assert_eq!("foo", tbl);
match case {
PreUpdateCase::Delete(accessor) => {
assert_eq!(1, accessor.get_column_count());
assert_eq!(1, accessor.get_old_row_id());
assert_eq!(0, accessor.get_query_depth());
// out of bounds access should return an error
assert!(accessor.get_old_column_value(1).is_err());
assert_eq!(
"lisa",
accessor.get_old_column_value(0).unwrap().as_str().unwrap()
);
assert_eq!(0, accessor.get_query_depth());
}
_ => panic!("wrong preupdate case"),
}
CALLED.store(true, Ordering::Relaxed);
}));
db.execute_batch("DELETE from foo")?;
assert!(CALLED.load(Ordering::Relaxed));
Ok(())
}
#[test]
fn test_preupdate_hook_update() -> Result<()> {
let db = Connection::open_in_memory()?;
static CALLED: AtomicBool = AtomicBool::new(false);
db.execute_batch("CREATE TABLE foo (t TEXT)")?;
db.execute_batch("INSERT INTO foo VALUES ('lisa')")?;
db.preupdate_hook(Some(|action, db: &str, tbl: &str, case: &PreUpdateCase| {
assert_eq!(Action::SQLITE_UPDATE, action);
assert_eq!("main", db);
assert_eq!("foo", tbl);
match case {
PreUpdateCase::Update {
old_value_accessor,
new_value_accessor,
} => {
assert_eq!(1, old_value_accessor.get_column_count());
assert_eq!(1, old_value_accessor.get_old_row_id());
assert_eq!(0, old_value_accessor.get_query_depth());
// out of bounds access should return an error
assert!(old_value_accessor.get_old_column_value(1).is_err());
assert_eq!(
"lisa",
old_value_accessor
.get_old_column_value(0)
.unwrap()
.as_str()
.unwrap()
);
assert_eq!(0, old_value_accessor.get_query_depth());
assert_eq!(1, new_value_accessor.get_column_count());
assert_eq!(1, new_value_accessor.get_new_row_id());
assert_eq!(0, new_value_accessor.get_query_depth());
// out of bounds access should return an error
assert!(new_value_accessor.get_new_column_value(1).is_err());
assert_eq!(
"janice",
new_value_accessor
.get_new_column_value(0)
.unwrap()
.as_str()
.unwrap()
);
assert_eq!(0, new_value_accessor.get_query_depth());
}
_ => panic!("wrong preupdate case"),
}
CALLED.store(true, Ordering::Relaxed);
}));
db.execute_batch("UPDATE foo SET t = 'janice'")?;
assert!(CALLED.load(Ordering::Relaxed));
Ok(())
}
}

View File

@@ -4,16 +4,15 @@ use std::os::raw::{c_char, c_int};
use std::path::Path; use std::path::Path;
use std::ptr; use std::ptr;
use std::str; use std::str;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use super::ffi; use super::ffi;
use super::str_for_sqlite; use super::str_for_sqlite;
use super::{Connection, InterruptHandle, OpenFlags, PrepFlags, Result}; use super::{Connection, InterruptHandle, OpenFlags, PrepFlags, Result};
use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error}; use crate::error::{decode_result_raw, error_from_handle, error_with_offset, Error};
use crate::raw_statement::RawStatement; use crate::raw_statement::RawStatement;
use crate::statement::Statement; use crate::statement::Statement;
use crate::version::version_number; use crate::version_number;
pub struct InnerConnection { pub struct InnerConnection {
pub db: *mut ffi::sqlite3, pub db: *mut ffi::sqlite3,
@@ -21,7 +20,7 @@ pub struct InnerConnection {
// a `sqlite3_interrupt`, and vice versa, so we take this mutex during // a `sqlite3_interrupt`, and vice versa, so we take this mutex during
// those functions. This protects a copy of the `db` pointer (which is // those functions. This protects a copy of the `db` pointer (which is
// cleared on closing), however the main copy, `db`, is unprotected. // cleared on closing), however the main copy, `db`, is unprotected.
// Otherwise, a long running query would prevent calling interrupt, as // Otherwise, a long-running query would prevent calling interrupt, as
// interrupt would only acquire the lock after the query's completion. // interrupt would only acquire the lock after the query's completion.
interrupt_lock: Arc<Mutex<*mut ffi::sqlite3>>, interrupt_lock: Arc<Mutex<*mut ffi::sqlite3>>,
#[cfg(feature = "hooks")] #[cfg(feature = "hooks")]
@@ -34,18 +33,20 @@ pub struct InnerConnection {
pub progress_handler: Option<Box<dyn FnMut() -> bool + Send>>, pub progress_handler: Option<Box<dyn FnMut() -> bool + Send>>,
#[cfg(feature = "hooks")] #[cfg(feature = "hooks")]
pub authorizer: Option<crate::hooks::BoxedAuthorizer>, pub authorizer: Option<crate::hooks::BoxedAuthorizer>,
#[cfg(feature = "preupdate_hook")]
pub free_preupdate_hook: Option<unsafe fn(*mut std::os::raw::c_void)>,
owned: bool, owned: bool,
} }
unsafe impl Send for InnerConnection {} unsafe impl Send for InnerConnection {}
impl InnerConnection { impl InnerConnection {
#[allow(clippy::mutex_atomic, clippy::arc_with_non_send_sync)] // See unsafe impl Send / Sync for InterruptHandle #[expect(clippy::mutex_atomic, clippy::arc_with_non_send_sync)] // See unsafe impl Send / Sync for InterruptHandle
#[inline] #[inline]
pub unsafe fn new(db: *mut ffi::sqlite3, owned: bool) -> InnerConnection { pub unsafe fn new(db: *mut ffi::sqlite3, owned: bool) -> Self {
InnerConnection { Self {
db, db,
interrupt_lock: Arc::new(Mutex::new(db)), interrupt_lock: Arc::new(Mutex::new(if owned { db } else { ptr::null_mut() })),
#[cfg(feature = "hooks")] #[cfg(feature = "hooks")]
free_commit_hook: None, free_commit_hook: None,
#[cfg(feature = "hooks")] #[cfg(feature = "hooks")]
@@ -56,43 +57,38 @@ impl InnerConnection {
progress_handler: None, progress_handler: None,
#[cfg(feature = "hooks")] #[cfg(feature = "hooks")]
authorizer: None, authorizer: None,
#[cfg(feature = "preupdate_hook")]
free_preupdate_hook: None,
owned, owned,
} }
} }
pub fn open_with_flags( pub fn open_with_flags(
c_path: &CStr, c_path: &CStr,
flags: OpenFlags, mut flags: OpenFlags,
vfs: Option<&CStr>, vfs: Option<&CStr>,
) -> Result<InnerConnection> { ) -> Result<Self> {
ensure_safe_sqlite_threading_mode()?; ensure_safe_sqlite_threading_mode()?;
// 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_WRITE | OpenFlags::SQLITE_OPEN_CREATE).bits(),
0x40
);
if (1 << (flags.bits() & 0x7)) & 0x46 == 0 {
return Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
None,
));
}
let z_vfs = match vfs { let z_vfs = match vfs {
Some(c_vfs) => c_vfs.as_ptr(), Some(c_vfs) => c_vfs.as_ptr(),
None => ptr::null(), None => ptr::null(),
}; };
// turn on extended results code before opening database to have a better diagnostic if a failure happens
let exrescode = if version_number() >= 3_037_000 {
flags |= OpenFlags::SQLITE_OPEN_EXRESCODE;
true
} else {
false // flag SQLITE_OPEN_EXRESCODE is ignored by SQLite version < 3.37.0
};
unsafe { unsafe {
let mut db: *mut ffi::sqlite3 = ptr::null_mut(); let mut db: *mut ffi::sqlite3 = ptr::null_mut();
let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), z_vfs); let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), z_vfs);
if r != ffi::SQLITE_OK { if r != ffi::SQLITE_OK {
let e = if db.is_null() { let e = if db.is_null() {
error_from_sqlite_code(r, Some(c_path.to_string_lossy().to_string())) err!(r, "{}", c_path.to_string_lossy())
} else { } else {
let mut e = error_from_handle(db, r); let mut e = error_from_handle(db, r);
if let Error::SqliteFailure( if let Error::SqliteFailure(
@@ -103,10 +99,7 @@ impl InnerConnection {
Some(msg), Some(msg),
) = e ) = e
{ {
e = Error::SqliteFailure( e = err!(r, "{msg}: {}", c_path.to_string_lossy());
ffi::Error::new(r),
Some(format!("{msg}: {}", c_path.to_string_lossy())),
);
} }
ffi::sqlite3_close(db); ffi::sqlite3_close(db);
e e
@@ -116,7 +109,9 @@ impl InnerConnection {
} }
// attempt to turn on extended results code; don't fail if we can't. // attempt to turn on extended results code; don't fail if we can't.
ffi::sqlite3_extended_result_codes(db, 1); if !exrescode {
ffi::sqlite3_extended_result_codes(db, 1);
}
let r = ffi::sqlite3_busy_timeout(db, 5000); let r = ffi::sqlite3_busy_timeout(db, 5000);
if r != ffi::SQLITE_OK { if r != ffi::SQLITE_OK {
@@ -125,7 +120,7 @@ impl InnerConnection {
return Err(e); return Err(e);
} }
Ok(InnerConnection::new(db, true)) Ok(Self::new(db, true))
} }
} }
@@ -136,27 +131,18 @@ impl InnerConnection {
#[inline] #[inline]
pub fn decode_result(&self, code: c_int) -> Result<()> { pub fn decode_result(&self, code: c_int) -> Result<()> {
unsafe { InnerConnection::decode_result_raw(self.db(), code) } unsafe { decode_result_raw(self.db(), code) }
} }
#[inline]
unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
if code == ffi::SQLITE_OK {
Ok(())
} else {
Err(error_from_handle(db, code))
}
}
#[allow(clippy::mutex_atomic)]
pub fn close(&mut self) -> Result<()> { pub fn close(&mut self) -> Result<()> {
if self.db.is_null() { if self.db.is_null() {
return Ok(()); return Ok(());
} }
self.remove_hooks(); self.remove_hooks();
self.remove_preupdate_hook();
let mut shared_handle = self.interrupt_lock.lock().unwrap(); let mut shared_handle = self.interrupt_lock.lock().unwrap();
assert!( assert!(
!shared_handle.is_null(), !self.owned || !shared_handle.is_null(),
"Bug: Somehow interrupt_lock was cleared before the DB was closed" "Bug: Somehow interrupt_lock was cleared before the DB was closed"
); );
if !self.owned { if !self.owned {
@@ -167,7 +153,7 @@ impl InnerConnection {
let r = ffi::sqlite3_close(self.db); let r = ffi::sqlite3_close(self.db);
// Need to use _raw because _guard has a reference out, and // Need to use _raw because _guard has a reference out, and
// decode_result takes &mut self. // decode_result takes &mut self.
let r = InnerConnection::decode_result_raw(self.db, r); let r = decode_result_raw(self.db, r);
if r.is_ok() { if r.is_ok() {
*shared_handle = ptr::null_mut(); *shared_handle = ptr::null_mut();
self.db = ptr::null_mut(); self.db = ptr::null_mut();
@@ -209,7 +195,7 @@ impl InnerConnection {
} else { } else {
let message = super::errmsg_to_string(errmsg); let message = super::errmsg_to_string(errmsg);
ffi::sqlite3_free(errmsg.cast::<std::os::raw::c_void>()); ffi::sqlite3_free(errmsg.cast::<std::os::raw::c_void>());
Err(error_from_sqlite_code(r, Some(message))) Err(crate::error::error_from_sqlite_code(r, Some(message)))
} }
} }
@@ -227,7 +213,6 @@ impl InnerConnection {
let mut c_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut(); let mut c_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?; let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?;
let mut c_tail: *const c_char = ptr::null(); let mut c_tail: *const c_char = ptr::null();
// TODO sqlite3_prepare_v3 (https://sqlite.org/c3ref/c_prepare_normalize.html) // 3.20.0, #728
#[cfg(not(feature = "unlock_notify"))] #[cfg(not(feature = "unlock_notify"))]
let r = unsafe { self.prepare_(c_sql, len, flags, &mut c_stmt, &mut c_tail) }; let r = unsafe { self.prepare_(c_sql, len, flags, &mut c_stmt, &mut c_tail) };
#[cfg(feature = "unlock_notify")] #[cfg(feature = "unlock_notify")]
@@ -305,9 +290,21 @@ impl InnerConnection {
} }
} }
#[inline]
pub fn total_changes(&self) -> u64 {
#[cfg(not(feature = "modern_sqlite"))]
unsafe {
ffi::sqlite3_total_changes(self.db()) as u64
}
#[cfg(feature = "modern_sqlite")] // 3.37.0
unsafe {
ffi::sqlite3_total_changes64(self.db()) as u64
}
}
#[inline] #[inline]
pub fn is_autocommit(&self) -> bool { pub fn is_autocommit(&self) -> bool {
unsafe { ffi::sqlite3_get_autocommit(self.db()) != 0 } unsafe { get_autocommit(self.db()) }
} }
pub fn is_busy(&self) -> bool { pub fn is_busy(&self) -> bool {
@@ -332,20 +329,21 @@ impl InnerConnection {
#[inline] #[inline]
fn remove_hooks(&mut self) {} fn remove_hooks(&mut self) {}
#[cfg(not(feature = "preupdate_hook"))]
#[inline]
fn remove_preupdate_hook(&mut self) {}
pub fn db_readonly(&self, db_name: super::DatabaseName<'_>) -> Result<bool> { pub fn db_readonly(&self, db_name: super::DatabaseName<'_>) -> Result<bool> {
let name = db_name.as_cstring()?; let name = db_name.as_cstr()?;
let r = unsafe { ffi::sqlite3_db_readonly(self.db, name.as_ptr()) }; let r = unsafe { ffi::sqlite3_db_readonly(self.db, name.as_ptr()) };
match r { match r {
0 => Ok(false), 0 => Ok(false),
1 => Ok(true), 1 => Ok(true),
-1 => Err(Error::SqliteFailure( -1 => Err(err!(
ffi::Error::new(ffi::SQLITE_MISUSE), ffi::SQLITE_MISUSE,
Some(format!("{db_name:?} is not the name of a database")), "{db_name:?} is not the name of a database"
)),
_ => Err(error_from_sqlite_code(
r,
Some("Unexpected result".to_owned()),
)), )),
_ => Err(err!(r, "Unexpected result")),
} }
} }
@@ -355,7 +353,7 @@ impl InnerConnection {
db_name: Option<super::DatabaseName<'_>>, db_name: Option<super::DatabaseName<'_>>,
) -> Result<super::transaction::TransactionState> { ) -> Result<super::transaction::TransactionState> {
let r = if let Some(ref name) = db_name { let r = if let Some(ref name) = db_name {
let name = name.as_cstring()?; let name = name.as_cstr()?;
unsafe { ffi::sqlite3_txn_state(self.db, name.as_ptr()) } unsafe { ffi::sqlite3_txn_state(self.db, name.as_ptr()) }
} else { } else {
unsafe { ffi::sqlite3_txn_state(self.db, ptr::null()) } unsafe { ffi::sqlite3_txn_state(self.db, ptr::null()) }
@@ -364,37 +362,52 @@ impl InnerConnection {
0 => Ok(super::transaction::TransactionState::None), 0 => Ok(super::transaction::TransactionState::None),
1 => Ok(super::transaction::TransactionState::Read), 1 => Ok(super::transaction::TransactionState::Read),
2 => Ok(super::transaction::TransactionState::Write), 2 => Ok(super::transaction::TransactionState::Write),
-1 => Err(Error::SqliteFailure( -1 => Err(err!(
ffi::Error::new(ffi::SQLITE_MISUSE), ffi::SQLITE_MISUSE,
Some(format!("{db_name:?} is not the name of a valid schema")), "{db_name:?} is not the name of a valid schema"
)),
_ => Err(error_from_sqlite_code(
r,
Some("Unexpected result".to_owned()),
)), )),
_ => Err(err!(r, "Unexpected result")),
} }
} }
#[inline] #[inline]
#[cfg(feature = "release_memory")]
pub fn release_memory(&self) -> Result<()> { pub fn release_memory(&self) -> Result<()> {
self.decode_result(unsafe { ffi::sqlite3_db_release_memory(self.db) }) self.decode_result(unsafe { ffi::sqlite3_db_release_memory(self.db) })
} }
#[cfg(feature = "modern_sqlite")] // 3.41.0
pub fn is_interrupted(&self) -> bool {
unsafe { ffi::sqlite3_is_interrupted(self.db) == 1 }
}
}
#[inline]
pub(crate) unsafe fn get_autocommit(ptr: *mut ffi::sqlite3) -> bool {
ffi::sqlite3_get_autocommit(ptr) != 0
}
#[inline]
pub(crate) unsafe fn db_filename(
ptr: *mut ffi::sqlite3,
db_name: crate::DatabaseName<'_>,
) -> Option<&str> {
let db_name = db_name.as_cstr().unwrap();
let db_filename = ffi::sqlite3_db_filename(ptr, db_name.as_ptr());
if db_filename.is_null() {
None
} else {
CStr::from_ptr(db_filename).to_str().ok()
}
} }
impl Drop for InnerConnection { impl Drop for InnerConnection {
#[allow(unused_must_use)] #[expect(unused_must_use)]
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
self.close(); self.close();
} }
} }
#[cfg(not(any(target_arch = "wasm32", feature = "loadable_extension")))]
static SQLITE_INIT: std::sync::Once = std::sync::Once::new();
pub static BYPASS_SQLITE_INIT: AtomicBool = AtomicBool::new(false);
// threading mode checks are not necessary (and do not work) on target // threading mode checks are not necessary (and do not work) on target
// platforms that do not have threading (such as webassembly) // platforms that do not have threading (such as webassembly)
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@@ -412,51 +425,21 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> {
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode, // Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode,
// but it's possible someone configured it to be in Single-thread mode // but it's possible someone configured it to be in Single-thread mode
// before calling into us. That would mean we're exposing an unsafe API via // before calling into us. That would mean we're exposing an unsafe API via
// a safe one (in Rust terminology), which is no good. We have two options // a safe one (in Rust terminology).
// to protect against this, depending on the version of SQLite we're linked
// with:
// //
// 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for // We can ask SQLite for a mutex and check for
// the magic value 8. This isn't documented, but it's what SQLite // the magic value 8. This isn't documented, but it's what SQLite
// returns for its mutex allocation function in Single-thread mode. // returns for its mutex allocation function in Single-thread mode.
// 2. If we're prior to SQLite 3.7.0, AFAIK there's no way to check the const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
// threading mode. The check we perform for >= 3.7.0 will segfault. let is_singlethreaded = unsafe {
// Instead, we insist on being able to call sqlite3_config and let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
// sqlite3_initialize ourself, ensuring we know the threading let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
// mode. This will fail if someone else has already initialized SQLite ffi::sqlite3_mutex_free(mutex_ptr);
// even if they initialized it safely. That's not ideal either, which is is_singlethreaded
// why we expose bypass_sqlite_initialization above. };
if version_number() >= 3_007_000 { if is_singlethreaded {
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8; Err(Error::SqliteSingleThreadedMode)
let is_singlethreaded = unsafe {
let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
ffi::sqlite3_mutex_free(mutex_ptr);
is_singlethreaded
};
if is_singlethreaded {
Err(Error::SqliteSingleThreadedMode)
} else {
Ok(())
}
} else { } else {
#[cfg(not(feature = "loadable_extension"))]
SQLITE_INIT.call_once(|| {
use std::sync::atomic::Ordering;
if BYPASS_SQLITE_INIT.load(Ordering::Relaxed) {
return;
}
unsafe {
assert!(ffi::sqlite3_config(ffi::SQLITE_CONFIG_MULTITHREAD) == ffi::SQLITE_OK && ffi::sqlite3_initialize() == ffi::SQLITE_OK,
"Could not ensure safe initialization of SQLite.\n\
To fix this, either:\n\
* Upgrade SQLite to at least version 3.7.0\n\
* Ensure that SQLite has been initialized in Multi-thread or Serialized mode and call\n\
rusqlite::bypass_sqlite_initialization() prior to your first connection attempt."
);
}
});
Ok(()) Ok(())
} }
} }

View File

@@ -46,7 +46,7 @@
//! })?; //! })?;
//! //!
//! for person in person_iter { //! for person in person_iter {
//! println!("Found person {:?}", person.unwrap()); //! println!("Found person {:?}", person?);
//! } //! }
//! Ok(()) //! Ok(())
//! } //! }
@@ -54,6 +54,8 @@
#![warn(missing_docs)] #![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_cfg))]
pub use fallible_iterator;
pub use fallible_streaming_iterator;
pub use libsqlite3_sys as ffi; pub use libsqlite3_sys as ffi;
use std::cell::RefCell; use std::cell::RefCell;
@@ -65,11 +67,10 @@ use std::os::raw::{c_char, c_int};
use std::path::Path; use std::path::Path;
use std::result; use std::result;
use std::str; use std::str;
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crate::cache::StatementCache; use crate::cache::StatementCache;
use crate::inner_connection::{InnerConnection, BYPASS_SQLITE_INIT}; use crate::inner_connection::InnerConnection;
use crate::raw_statement::RawStatement; use crate::raw_statement::RawStatement;
use crate::types::ValueRef; use crate::types::ValueRef;
@@ -92,8 +93,11 @@ pub use crate::version::*;
#[doc(hidden)] #[doc(hidden)]
pub use rusqlite_macros::__bind; pub use rusqlite_macros::__bind;
#[macro_use]
mod error; mod error;
#[cfg(not(feature = "loadable_extension"))]
pub mod auto_extension;
#[cfg(feature = "backup")] #[cfg(feature = "backup")]
#[cfg_attr(docsrs, doc(cfg(feature = "backup")))] #[cfg_attr(docsrs, doc(cfg(feature = "backup")))]
pub mod backup; pub mod backup;
@@ -150,7 +154,7 @@ pub(crate) use util::SmallCString;
// Number of cached prepared statements we'll hold on to. // Number of cached prepared statements we'll hold on to.
const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16; const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
/// A macro making it more convenient to longer lists of /// A macro making it more convenient to pass longer lists of
/// parameters as a `&[&dyn ToSql]`. /// parameters as a `&[&dyn ToSql]`.
/// ///
/// # Example /// # Example
@@ -290,8 +294,7 @@ impl<T> OptionalExtension<T> for Result<T> {
} }
unsafe fn errmsg_to_string(errmsg: *const c_char) -> String { unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
let c_slice = CStr::from_ptr(errmsg).to_bytes(); CStr::from_ptr(errmsg).to_string_lossy().into_owned()
String::from_utf8_lossy(c_slice).into_owned()
} }
fn str_to_cstring(s: &str) -> Result<SmallCString> { fn str_to_cstring(s: &str) -> Result<SmallCString> {
@@ -319,10 +322,7 @@ fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destru
// failed. // failed.
fn len_as_c_int(len: usize) -> Result<c_int> { fn len_as_c_int(len: usize) -> Result<c_int> {
if len >= (c_int::MAX as usize) { if len >= (c_int::MAX as usize) {
Err(Error::SqliteFailure( Err(err!(ffi::SQLITE_TOOBIG))
ffi::Error::new(ffi::SQLITE_TOOBIG),
None,
))
} else { } else {
Ok(len as c_int) Ok(len as c_int)
} }
@@ -341,16 +341,16 @@ fn path_to_cstring(p: &Path) -> Result<CString> {
} }
/// Name for a database within a SQLite connection. /// Name for a database within a SQLite connection.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DatabaseName<'a> { pub enum DatabaseName<'a> {
/// The main database. /// The main database.
Main, Main,
/// The temporary database (e.g., any "CREATE TEMPORARY TABLE" tables). /// The temporary database (e.g., any "CREATE TEMPORARY TABLE" tables).
Temp, Temp,
/// A database that has been attached via "ATTACH DATABASE ...". /// A database that has been attached via "ATTACH DATABASE ...".
Attached(&'a str), Attached(&'a str),
/// Optim
C(&'a CStr),
} }
/// Shorthand for [`DatabaseName::Main`]. /// Shorthand for [`DatabaseName::Main`].
@@ -359,16 +359,24 @@ pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
/// Shorthand for [`DatabaseName::Temp`]. /// Shorthand for [`DatabaseName::Temp`].
pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp; pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
// Currently DatabaseName is only used by the backup and blob mods, so hide
// this (private) impl to avoid dead code warnings.
impl DatabaseName<'_> { impl DatabaseName<'_> {
#[inline] #[inline]
fn as_cstring(&self) -> Result<SmallCString> { fn as_cstr(&self) -> Result<std::borrow::Cow<'_, CStr>> {
use self::DatabaseName::{Attached, Main, Temp}; Ok(match *self {
match *self { DatabaseName::Main => std::borrow::Cow::Borrowed(c"main"),
Main => str_to_cstring("main"), DatabaseName::Temp => std::borrow::Cow::Borrowed(c"temp"),
Temp => str_to_cstring("temp"), DatabaseName::Attached(s) => std::borrow::Cow::Owned(CString::new(s)?),
Attached(s) => str_to_cstring(s), DatabaseName::C(s) => std::borrow::Cow::Borrowed(s),
})
}
#[cfg(feature = "hooks")]
pub(crate) fn from_cstr(cs: &std::ffi::CStr) -> DatabaseName<'_> {
if cs == c"main" {
DatabaseName::Main
} else if cs == c"temp" {
DatabaseName::Temp
} else {
DatabaseName::C(cs)
} }
} }
} }
@@ -377,6 +385,7 @@ impl DatabaseName<'_> {
pub struct Connection { pub struct Connection {
db: RefCell<InnerConnection>, db: RefCell<InnerConnection>,
cache: StatementCache, cache: StatementCache,
transaction_behavior: TransactionBehavior,
} }
unsafe impl Send for Connection {} unsafe impl Send for Connection {}
@@ -442,9 +451,9 @@ impl Connection {
/// Will return `Err` if `path` cannot be converted to a C-compatible string /// Will return `Err` if `path` cannot be converted to a C-compatible string
/// or if the underlying SQLite open call fails. /// or if the underlying SQLite open call fails.
#[inline] #[inline]
pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> { pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
let flags = OpenFlags::default(); let flags = OpenFlags::default();
Connection::open_with_flags(path, flags) Self::open_with_flags(path, flags)
} }
/// Open a new connection to an in-memory SQLite database. /// Open a new connection to an in-memory SQLite database.
@@ -453,9 +462,9 @@ impl Connection {
/// ///
/// Will return `Err` if the underlying SQLite open call fails. /// Will return `Err` if the underlying SQLite open call fails.
#[inline] #[inline]
pub fn open_in_memory() -> Result<Connection> { pub fn open_in_memory() -> Result<Self> {
let flags = OpenFlags::default(); let flags = OpenFlags::default();
Connection::open_in_memory_with_flags(flags) Self::open_in_memory_with_flags(flags)
} }
/// Open a new connection to a SQLite database. /// Open a new connection to a SQLite database.
@@ -468,11 +477,12 @@ impl Connection {
/// Will return `Err` if `path` cannot be converted to a C-compatible /// Will return `Err` if `path` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails. /// string or if the underlying SQLite open call fails.
#[inline] #[inline]
pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> { pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Self> {
let c_path = path_to_cstring(path.as_ref())?; let c_path = path_to_cstring(path.as_ref())?;
InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection { InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Self {
db: RefCell::new(db), db: RefCell::new(db),
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
transaction_behavior: TransactionBehavior::Deferred,
}) })
} }
@@ -491,12 +501,13 @@ impl Connection {
path: P, path: P,
flags: OpenFlags, flags: OpenFlags,
vfs: &str, vfs: &str,
) -> Result<Connection> { ) -> Result<Self> {
let c_path = path_to_cstring(path.as_ref())?; let c_path = path_to_cstring(path.as_ref())?;
let c_vfs = str_to_cstring(vfs)?; let c_vfs = str_to_cstring(vfs)?;
InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Connection { InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Self {
db: RefCell::new(db), db: RefCell::new(db),
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
transaction_behavior: TransactionBehavior::Deferred,
}) })
} }
@@ -509,8 +520,8 @@ impl Connection {
/// ///
/// Will return `Err` if the underlying SQLite open call fails. /// Will return `Err` if the underlying SQLite open call fails.
#[inline] #[inline]
pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> { pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Self> {
Connection::open_with_flags(":memory:", flags) Self::open_with_flags(":memory:", flags)
} }
/// Open a new connection to an in-memory SQLite database using the specific /// Open a new connection to an in-memory SQLite database using the specific
@@ -524,8 +535,8 @@ impl Connection {
/// Will return `Err` if `vfs` cannot be converted to a C-compatible /// Will return `Err` if `vfs` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails. /// string or if the underlying SQLite open call fails.
#[inline] #[inline]
pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> { pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Self> {
Connection::open_with_flags_and_vfs(":memory:", flags, vfs) Self::open_with_flags_and_vfs(":memory:", flags, vfs)
} }
/// Convenience method to run multiple SQL statements (that cannot take any /// Convenience method to run multiple SQL statements (that cannot take any
@@ -631,16 +642,7 @@ impl Connection {
/// likely to be more robust. /// likely to be more robust.
#[inline] #[inline]
pub fn path(&self) -> Option<&str> { pub fn path(&self) -> Option<&str> {
unsafe { unsafe { crate::inner_connection::db_filename(self.handle(), DatabaseName::Main) }
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 /// Attempts to free as much heap memory as possible from the database
@@ -648,7 +650,6 @@ impl Connection {
/// ///
/// This calls [`sqlite3_db_release_memory`](https://www.sqlite.org/c3ref/db_release_memory.html). /// This calls [`sqlite3_db_release_memory`](https://www.sqlite.org/c3ref/db_release_memory.html).
#[inline] #[inline]
#[cfg(feature = "release_memory")]
pub fn release_memory(&self) -> Result<()> { pub fn release_memory(&self) -> Result<()> {
self.db.borrow_mut().release_memory() self.db.borrow_mut().release_memory()
} }
@@ -789,7 +790,7 @@ impl Connection {
/// ///
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
#[inline] #[inline]
pub fn close(self) -> Result<(), (Connection, Error)> { pub fn close(self) -> Result<(), (Self, Error)> {
self.flush_prepared_statement_cache(); self.flush_prepared_statement_cache();
let r = self.db.borrow_mut().close(); let r = self.db.borrow_mut().close();
r.map_err(move |err| (self, err)) r.map_err(move |err| (self, err))
@@ -944,23 +945,40 @@ impl Connection {
/// ///
/// This function is unsafe because improper use may impact the Connection. /// This function is unsafe because improper use may impact the Connection.
#[inline] #[inline]
pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> { pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Self> {
let db = InnerConnection::new(db, false); let db = InnerConnection::new(db, false);
Ok(Connection { Ok(Self {
db: RefCell::new(db), db: RefCell::new(db),
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
transaction_behavior: TransactionBehavior::Deferred,
}) })
} }
/// Like SQLITE_EXTENSION_INIT2 macro /// Helper to register an SQLite extension written in Rust.
/// For [persistent](https://sqlite.org/loadext.html#persistent_loadable_extensions) extension,
/// `init` should return `Ok(true)`.
/// # Safety
/// * Results are undefined if `init` does not just register features.
#[cfg(feature = "loadable_extension")] #[cfg(feature = "loadable_extension")]
#[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))] #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))]
pub unsafe fn extension_init2( pub unsafe fn extension_init2(
db: *mut ffi::sqlite3, db: *mut ffi::sqlite3,
pz_err_msg: *mut *mut c_char,
p_api: *mut ffi::sqlite3_api_routines, p_api: *mut ffi::sqlite3_api_routines,
) -> Result<Connection> { init: fn(Self) -> Result<bool>,
ffi::rusqlite_extension_init2(p_api)?; ) -> c_int {
Connection::from_handle(db) if p_api.is_null() {
return ffi::SQLITE_ERROR;
}
match ffi::rusqlite_extension_init2(p_api)
.map_err(Error::from)
.and(Self::from_handle(db))
.and_then(init)
{
Err(err) => to_sqlite_error(&err, pz_err_msg),
Ok(true) => ffi::SQLITE_OK_LOAD_PERMANENTLY,
_ => ffi::SQLITE_OK,
}
} }
/// Create a `Connection` from a raw owned handle. /// Create a `Connection` from a raw owned handle.
@@ -976,15 +994,16 @@ impl Connection {
/// and owned by the caller, e.g. as a result of calling /// and owned by the caller, e.g. as a result of calling
/// `ffi::sqlite3_open`(). /// `ffi::sqlite3_open`().
#[inline] #[inline]
pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Connection> { pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Self> {
let db = InnerConnection::new(db, true); let db = InnerConnection::new(db, true);
Ok(Connection { Ok(Self {
db: RefCell::new(db), db: RefCell::new(db),
cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY),
transaction_behavior: TransactionBehavior::Deferred,
}) })
} }
/// Get access to a handle that can be used to interrupt long running /// Get access to a handle that can be used to interrupt long-running
/// queries from another thread. /// queries from another thread.
#[inline] #[inline]
pub fn get_interrupt_handle(&self) -> InterruptHandle { pub fn get_interrupt_handle(&self) -> InterruptHandle {
@@ -1006,6 +1025,16 @@ impl Connection {
self.db.borrow().changes() self.db.borrow().changes()
} }
/// Return the total number of rows modified, inserted or deleted by all
/// completed INSERT, UPDATE or DELETE statements since the database
/// connection was opened, including those executed as part of trigger programs.
///
/// See <https://www.sqlite.org/c3ref/total_changes.html>
#[inline]
pub fn total_changes(&self) -> u64 {
self.db.borrow().total_changes()
}
/// Test for auto-commit mode. /// Test for auto-commit mode.
/// Autocommit mode is on by default. /// Autocommit mode is on by default.
#[inline] #[inline]
@@ -1028,6 +1057,32 @@ impl Connection {
pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> { pub fn is_readonly(&self, db_name: DatabaseName<'_>) -> Result<bool> {
self.db.borrow().db_readonly(db_name) self.db.borrow().db_readonly(db_name)
} }
/// Return the schema name for a database connection
///
/// ## Failure
///
/// Return an `Error::InvalidDatabaseIndex` if `index` is out of range.
#[cfg(feature = "modern_sqlite")] // 3.39.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn db_name(&self, index: usize) -> Result<String> {
unsafe {
let db = self.handle();
let name = ffi::sqlite3_db_name(db, index as c_int);
if name.is_null() {
Err(Error::InvalidDatabaseIndex(index))
} else {
Ok(CStr::from_ptr(name).to_str()?.to_owned())
}
}
}
/// Determine whether an interrupt is currently in effect
#[cfg(feature = "modern_sqlite")] // 3.41.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub fn is_interrupted(&self) -> bool {
self.db.borrow().is_interrupted()
}
} }
impl fmt::Debug for Connection { impl fmt::Debug for Connection {
@@ -1038,8 +1093,15 @@ impl fmt::Debug for Connection {
} }
} }
/// Batch iterator /// Batch fallible iterator
///
/// # Warning
///
/// There is no recovery on parsing error, when a invalid statement is found in `sql`, SQLite cannot jump to the next statement.
/// So you should break the loop when an error is raised by the `next` method.
///
/// ```rust /// ```rust
/// use fallible_iterator::FallibleIterator;
/// use rusqlite::{Batch, Connection, Result}; /// use rusqlite::{Batch, Connection, Result};
/// ///
/// fn main() -> Result<()> { /// fn main() -> Result<()> {
@@ -1064,15 +1126,18 @@ pub struct Batch<'conn, 'sql> {
impl<'conn, 'sql> Batch<'conn, 'sql> { impl<'conn, 'sql> Batch<'conn, 'sql> {
/// Constructor /// Constructor
pub fn new(conn: &'conn Connection, sql: &'sql str) -> Batch<'conn, 'sql> { pub fn new(conn: &'conn Connection, sql: &'sql str) -> Self {
Batch { conn, sql, tail: 0 } Batch { conn, sql, tail: 0 }
} }
}
impl<'conn> fallible_iterator::FallibleIterator for Batch<'conn, '_> {
type Error = Error;
type Item = Statement<'conn>;
/// Iterates on each batch statements. /// Iterates on each batch statements.
/// ///
/// Returns `Ok(None)` when batch is completed. /// Returns `Ok(None)` when batch is completed.
#[allow(clippy::should_implement_trait)] // fallible iterator fn next(&mut self) -> Result<Option<Statement<'conn>>> {
pub fn next(&mut self) -> Result<Option<Statement<'conn>>> {
while self.tail < self.sql.len() { while self.tail < self.sql.len() {
let sql = &self.sql[self.tail..]; let sql = &self.sql[self.tail..];
let next = self.conn.prepare(sql)?; let next = self.conn.prepare(sql)?;
@@ -1091,14 +1156,6 @@ impl<'conn, 'sql> Batch<'conn, 'sql> {
} }
} }
impl<'conn> Iterator for Batch<'conn, '_> {
type Item = Result<Statement<'conn>>;
fn next(&mut self) -> Option<Result<Statement<'conn>>> {
self.next().transpose()
}
}
bitflags::bitflags! { bitflags::bitflags! {
/// Flags for opening SQLite database connections. See /// Flags for opening SQLite database connections. See
/// [sqlite3_open_v2](https://www.sqlite.org/c3ref/open.html) for details. /// [sqlite3_open_v2](https://www.sqlite.org/c3ref/open.html) for details.
@@ -1108,12 +1165,12 @@ bitflags::bitflags! {
/// some discussion about these flags. /// some discussion about these flags.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(C)] #[repr(C)]
pub struct OpenFlags: ::std::os::raw::c_int { pub struct OpenFlags: c_int {
/// The database is opened in read-only mode. /// The database is opened in read-only mode.
/// If the database does not already exist, an error is returned. /// If the database does not already exist, an error is returned.
const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY; const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
/// The database is opened for reading and writing if possible, /// The database is opened for reading and writing if possible,
/// or reading only if the file is write protected by the operating system. /// 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. /// In either case the database must already exist, otherwise an error is returned.
const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE; const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
/// The database is created if it does not already exist /// The database is created if it does not already exist
@@ -1138,7 +1195,7 @@ bitflags::bitflags! {
/// ///
/// This flag should probably never be used with `rusqlite`, as we /// This flag should probably never be used with `rusqlite`, as we
/// ensure thread-safety statically (we implement [`Send`] and not /// ensure thread-safety statically (we implement [`Send`] and not
/// [`Sync`]). That said /// [`Sync`]).
/// ///
/// Critically, even if this flag is used, the [`Connection`] is not /// Critically, even if this flag is used, the [`Connection`] is not
/// safe to use across multiple threads simultaneously. To access a /// safe to use across multiple threads simultaneously. To access a
@@ -1173,13 +1230,13 @@ bitflags::bitflags! {
impl Default for OpenFlags { impl Default for OpenFlags {
#[inline] #[inline]
fn default() -> OpenFlags { fn default() -> Self {
// Note: update the `Connection::open` and top-level `OpenFlags` docs if // Note: update the `Connection::open` and top-level `OpenFlags` docs if
// you change these. // you change these.
OpenFlags::SQLITE_OPEN_READ_WRITE Self::SQLITE_OPEN_READ_WRITE
| OpenFlags::SQLITE_OPEN_CREATE | Self::SQLITE_OPEN_CREATE
| OpenFlags::SQLITE_OPEN_NO_MUTEX | Self::SQLITE_OPEN_NO_MUTEX
| OpenFlags::SQLITE_OPEN_URI | Self::SQLITE_OPEN_URI
} }
} }
@@ -1193,32 +1250,11 @@ bitflags::bitflags! {
const SQLITE_PREPARE_PERSISTENT = 0x01; const SQLITE_PREPARE_PERSISTENT = 0x01;
/// Causes the SQL compiler to return an error (error code SQLITE_ERROR) if the statement uses any virtual tables. /// Causes the SQL compiler to return an error (error code SQLITE_ERROR) if the statement uses any virtual tables.
const SQLITE_PREPARE_NO_VTAB = 0x04; const SQLITE_PREPARE_NO_VTAB = 0x04;
/// Prevents SQL compiler errors from being sent to the error log.
const SQLITE_PREPARE_DONT_LOG = 0x10;
} }
} }
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or
/// later. If you are running against a SQLite older than that, rusqlite
/// attempts to ensure safety by performing configuration and initialization of
/// SQLite itself the first time you
/// attempt to open a connection. By default, rusqlite panics if that
/// initialization fails, since that could mean SQLite has been initialized in
/// single-thread mode.
///
/// If you are encountering that panic _and_ can ensure that SQLite has been
/// initialized in either multi-thread or serialized mode, call this function
/// prior to attempting to open a connection and rusqlite's initialization
/// process will by skipped.
///
/// # Safety
///
/// This function is unsafe because if you call it and SQLite has actually been
/// configured to run in single-thread mode,
/// you may encounter memory errors or data corruption or any number of terrible
/// things that should not be possible when you're using Rust.
pub unsafe fn bypass_sqlite_initialization() {
BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
}
/// Allows interrupting a long-running computation. /// Allows interrupting a long-running computation.
pub struct InterruptHandle { pub struct InterruptHandle {
db_lock: Arc<Mutex<*mut ffi::sqlite3>>, db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
@@ -1244,7 +1280,6 @@ doc_comment::doctest!("../README.md");
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::ffi;
use fallible_iterator::FallibleIterator; use fallible_iterator::FallibleIterator;
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt; use std::fmt;
@@ -1252,21 +1287,15 @@ mod test {
// this function is never called, but is still type checked; in // this function is never called, but is still type checked; in
// particular, calls with specific instantiations will require // particular, calls with specific instantiations will require
// that those types are `Send`. // that those types are `Send`.
#[allow( #[allow(dead_code)]
dead_code, #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
unconditional_recursion,
clippy::extra_unused_type_parameters
)]
fn ensure_send<T: Send>() { fn ensure_send<T: Send>() {
ensure_send::<Connection>(); ensure_send::<Connection>();
ensure_send::<InterruptHandle>(); ensure_send::<InterruptHandle>();
} }
#[allow( #[allow(dead_code)]
dead_code, #[expect(unconditional_recursion, clippy::extra_unused_type_parameters)]
unconditional_recursion,
clippy::extra_unused_type_parameters
)]
fn ensure_sync<T: Sync>() { fn ensure_sync<T: Sync>() {
ensure_sync::<InterruptHandle>(); ensure_sync::<InterruptHandle>();
} }
@@ -1358,7 +1387,7 @@ mod test {
assert_eq!(Some(""), db.path()); assert_eq!(Some(""), db.path());
let path = tmp.path().join("file.db"); let path = tmp.path().join("file.db");
let db = Connection::open(path)?; let db = Connection::open(path)?;
assert!(db.path().map(|p| p.ends_with("file.db")).unwrap_or(false)); assert!(db.path().is_some_and(|p| p.ends_with("file.db")));
Ok(()) Ok(())
} }
@@ -1672,7 +1701,7 @@ mod test {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
assert_eq!("memory", db.one_column::<String>("PRAGMA journal_mode")?); assert_eq!("memory", db.one_column::<String>("PRAGMA journal_mode")?);
let mode = db.one_column::<String>("PRAGMA journal_mode=off")?; let mode = db.one_column::<String>("PRAGMA journal_mode=off")?;
if cfg!(features = "bundled") { if cfg!(feature = "bundled") {
assert_eq!(mode, "off"); assert_eq!(mode, "off");
} else { } else {
// Note: system SQLite on macOS defaults to "off" rather than // Note: system SQLite on macOS defaults to "off" rather than
@@ -1718,6 +1747,29 @@ mod test {
Ok(()) Ok(())
} }
#[test]
fn test_total_changes() -> Result<()> {
let db = Connection::open_in_memory()?;
let sql = "CREATE TABLE foo(x INTEGER PRIMARY KEY, value TEXT default '' NOT NULL,
desc TEXT default '');
CREATE VIEW foo_bar AS SELECT x, desc FROM foo WHERE value = 'bar';
CREATE TRIGGER INSERT_FOOBAR
INSTEAD OF INSERT
ON foo_bar
BEGIN
INSERT INTO foo VALUES(new.x, 'bar', new.desc);
END;";
db.execute_batch(sql)?;
let total_changes_before = db.total_changes();
let changes = db
.prepare("INSERT INTO foo_bar VALUES(null, 'baz');")?
.execute([])?;
let total_changes_after = db.total_changes();
assert_eq!(changes, 0);
assert_eq!(total_changes_after - total_changes_before, 1);
Ok(())
}
#[test] #[test]
fn test_is_autocommit() -> Result<()> { fn test_is_autocommit() -> Result<()> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
@@ -1757,12 +1809,6 @@ mod test {
#[test] #[test]
fn test_notnull_constraint_error() -> Result<()> { fn test_notnull_constraint_error() -> Result<()> {
// extended error codes for constraints were added in SQLite 3.7.16; if we're
// running on our bundled version, we know the extended error code exists.
fn check_extended_code(extended_code: c_int) {
assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
}
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x NOT NULL)")?; db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
@@ -1771,7 +1817,7 @@ mod test {
match result.unwrap_err() { match result.unwrap_err() {
Error::SqliteFailure(err, _) => { Error::SqliteFailure(err, _) => {
assert_eq!(err.code, ErrorCode::ConstraintViolation); assert_eq!(err.code, ErrorCode::ConstraintViolation);
check_extended_code(err.extended_code); assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
} }
err => panic!("Unexpected error {err}"), err => panic!("Unexpected error {err}"),
} }
@@ -1825,7 +1871,7 @@ mod test {
db.close().unwrap(); db.close().unwrap();
handle.interrupt(); handle.interrupt();
// Look at it's internals to see if we cleared it out properly. // Look at its internals to see if we cleared it out properly.
let db_guard = handle.db_lock.lock().unwrap(); let db_guard = handle.db_lock.lock().unwrap();
assert!(db_guard.is_null()); assert!(db_guard.is_null());
// It would be nice to test that we properly handle close/interrupt // It would be nice to test that we properly handle close/interrupt
@@ -1881,7 +1927,7 @@ mod test {
#[test] #[test]
fn test_from_handle_owned() -> Result<()> { fn test_from_handle_owned() -> Result<()> {
let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut(); let mut handle: *mut ffi::sqlite3 = std::ptr::null_mut();
let r = unsafe { ffi::sqlite3_open(":memory:\0".as_ptr() as *const c_char, &mut handle) }; let r = unsafe { ffi::sqlite3_open(c":memory:".as_ptr(), &mut handle) };
assert_eq!(r, ffi::SQLITE_OK); assert_eq!(r, ffi::SQLITE_OK);
let db = unsafe { Connection::from_handle_owned(handle) }?; let db = unsafe { Connection::from_handle_owned(handle) }?;
db.execute_batch("PRAGMA VACUUM")?; db.execute_batch("PRAGMA VACUUM")?;
@@ -1901,8 +1947,8 @@ mod test {
impl fmt::Display for CustomError { impl fmt::Display for CustomError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match *self { match *self {
CustomError::SomeError => write!(f, "my custom error"), Self::SomeError => write!(f, "my custom error"),
CustomError::Sqlite(ref se) => write!(f, "my custom error: {se}"), Self::Sqlite(ref se) => write!(f, "my custom error: {se}"),
} }
} }
} }
@@ -1914,15 +1960,15 @@ mod test {
fn cause(&self) -> Option<&dyn StdError> { fn cause(&self) -> Option<&dyn StdError> {
match *self { match *self {
CustomError::SomeError => None, Self::SomeError => None,
CustomError::Sqlite(ref se) => Some(se), Self::Sqlite(ref se) => Some(se),
} }
} }
} }
impl From<Error> for CustomError { impl From<Error> for CustomError {
fn from(se: Error) -> CustomError { fn from(se: Error) -> Self {
CustomError::Sqlite(se) Self::Sqlite(se)
} }
} }
@@ -2158,14 +2204,29 @@ mod test {
CREATE TABLE tbl1 (col); CREATE TABLE tbl1 (col);
CREATE TABLE tbl2 (col); CREATE TABLE tbl2 (col);
"; ";
let batch = Batch::new(&db, sql); let mut batch = Batch::new(&db, sql);
for stmt in batch { while let Some(mut stmt) = batch.next()? {
let mut stmt = stmt?;
stmt.execute([])?; stmt.execute([])?;
} }
Ok(()) Ok(())
} }
#[test]
fn test_invalid_batch() -> Result<()> {
let db = Connection::open_in_memory()?;
let sql = r"
PRAGMA test1;
PRAGMA test2=?;
PRAGMA test3;
";
let mut batch = Batch::new(&db, sql);
assert!(batch.next().is_ok());
assert!(batch.next().is_err());
assert!(batch.next().is_err());
assert!(Batch::new(&db, sql).count().is_err());
Ok(())
}
#[test] #[test]
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
fn test_returning() -> Result<()> { fn test_returning() -> Result<()> {
@@ -2204,4 +2265,32 @@ mod test {
assert_eq!((v1.as_str(), v2), (name, age)); assert_eq!((v1.as_str(), v2), (name, age));
Ok(()) Ok(())
} }
#[test]
#[cfg(feature = "modern_sqlite")]
fn test_db_name() -> Result<()> {
let db = Connection::open_in_memory()?;
assert_eq!(db.db_name(0)?, "main");
assert_eq!(db.db_name(1)?, "temp");
assert_eq!(db.db_name(2), Err(Error::InvalidDatabaseIndex(2)));
db.execute_batch("ATTACH DATABASE ':memory:' AS xyz;")?;
assert_eq!(db.db_name(2)?, "xyz");
Ok(())
}
#[test]
#[cfg(feature = "modern_sqlite")]
fn test_is_interrupted() -> Result<()> {
let db = Connection::open_in_memory()?;
assert!(!db.is_interrupted());
db.get_interrupt_handle().interrupt();
assert!(db.is_interrupted());
Ok(())
}
#[test]
fn release_memory() -> Result<()> {
let db = Connection::open_in_memory()?;
db.release_memory()
}
} }

View File

@@ -1,6 +1,6 @@
//! Run-Time Limits //! Run-Time Limits
use crate::{ffi, Connection}; use crate::{ffi, Connection, Result};
use std::os::raw::c_int; use std::os::raw::c_int;
/// Run-Time limit categories, for use with [`Connection::limit`] and /// Run-Time limit categories, for use with [`Connection::limit`] and
@@ -12,7 +12,7 @@ use std::os::raw::c_int;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(i32)] #[repr(i32)]
#[non_exhaustive] #[non_exhaustive]
#[allow(clippy::upper_case_acronyms, non_camel_case_types)] #[expect(non_camel_case_types)]
#[cfg_attr(docsrs, doc(cfg(feature = "limits")))] #[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
pub enum Limit { pub enum Limit {
/// The maximum size of any string or BLOB or table row, in bytes. /// The maximum size of any string or BLOB or table row, in bytes.
@@ -44,31 +44,45 @@ pub enum Limit {
/// The maximum number of auxiliary worker threads that a single prepared /// The maximum number of auxiliary worker threads that a single prepared
/// statement may start. /// statement may start.
SQLITE_LIMIT_WORKER_THREADS = ffi::SQLITE_LIMIT_WORKER_THREADS, SQLITE_LIMIT_WORKER_THREADS = ffi::SQLITE_LIMIT_WORKER_THREADS,
/// Only used for testing
#[cfg(test)]
INVALID = -1,
} }
impl Connection { impl Connection {
/// Returns the current value of a [`Limit`]. /// Returns the current value of a [`Limit`].
#[inline] #[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "limits")))] #[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
pub fn limit(&self, limit: Limit) -> i32 { pub fn limit(&self, limit: Limit) -> Result<i32> {
let c = self.db.borrow(); let c = self.db.borrow();
unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, -1) } let rc = unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, -1) };
if rc < 0 {
return Err(err!(ffi::SQLITE_RANGE, "{limit:?} is invalid"));
}
Ok(rc)
} }
/// Changes the [`Limit`] to `new_val`, returning the prior /// Changes the [`Limit`] to `new_val`, returning the prior
/// value of the limit. /// value of the limit.
#[inline] #[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "limits")))] #[cfg_attr(docsrs, doc(cfg(feature = "limits")))]
pub fn set_limit(&self, limit: Limit, new_val: i32) -> i32 { pub fn set_limit(&self, limit: Limit, new_val: i32) -> Result<i32> {
if new_val < 0 {
return Err(err!(ffi::SQLITE_RANGE, "{new_val} is invalid"));
}
let c = self.db.borrow_mut(); let c = self.db.borrow_mut();
unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, new_val) } let rc = unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, new_val) };
if rc < 0 {
return Err(err!(ffi::SQLITE_RANGE, "{limit:?} is invalid"));
}
Ok(rc)
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::{Connection, Result}; use crate::Result;
#[test] #[test]
fn test_limit_values() { fn test_limit_values() {
@@ -106,12 +120,10 @@ mod test {
Limit::SQLITE_LIMIT_VARIABLE_NUMBER as i32, Limit::SQLITE_LIMIT_VARIABLE_NUMBER as i32,
ffi::SQLITE_LIMIT_VARIABLE_NUMBER, ffi::SQLITE_LIMIT_VARIABLE_NUMBER,
); );
#[cfg(feature = "bundled")]
assert_eq!( assert_eq!(
Limit::SQLITE_LIMIT_TRIGGER_DEPTH as i32, Limit::SQLITE_LIMIT_TRIGGER_DEPTH as i32,
ffi::SQLITE_LIMIT_TRIGGER_DEPTH, ffi::SQLITE_LIMIT_TRIGGER_DEPTH,
); );
#[cfg(feature = "bundled")]
assert_eq!( assert_eq!(
Limit::SQLITE_LIMIT_WORKER_THREADS as i32, Limit::SQLITE_LIMIT_WORKER_THREADS as i32,
ffi::SQLITE_LIMIT_WORKER_THREADS, ffi::SQLITE_LIMIT_WORKER_THREADS,
@@ -121,44 +133,44 @@ mod test {
#[test] #[test]
fn test_limit() -> Result<()> { fn test_limit() -> Result<()> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.set_limit(Limit::SQLITE_LIMIT_LENGTH, 1024); db.set_limit(Limit::SQLITE_LIMIT_LENGTH, 1024)?;
assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_LENGTH)); assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_LENGTH)?);
db.set_limit(Limit::SQLITE_LIMIT_SQL_LENGTH, 1024); db.set_limit(Limit::SQLITE_LIMIT_SQL_LENGTH, 1024)?;
assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_SQL_LENGTH)); assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_SQL_LENGTH)?);
db.set_limit(Limit::SQLITE_LIMIT_COLUMN, 64); db.set_limit(Limit::SQLITE_LIMIT_COLUMN, 64)?;
assert_eq!(64, db.limit(Limit::SQLITE_LIMIT_COLUMN)); assert_eq!(64, db.limit(Limit::SQLITE_LIMIT_COLUMN)?);
db.set_limit(Limit::SQLITE_LIMIT_EXPR_DEPTH, 256); db.set_limit(Limit::SQLITE_LIMIT_EXPR_DEPTH, 256)?;
assert_eq!(256, db.limit(Limit::SQLITE_LIMIT_EXPR_DEPTH)); assert_eq!(256, db.limit(Limit::SQLITE_LIMIT_EXPR_DEPTH)?);
db.set_limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT, 32); db.set_limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT, 32)?;
assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT)); assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT)?);
db.set_limit(Limit::SQLITE_LIMIT_FUNCTION_ARG, 32); db.set_limit(Limit::SQLITE_LIMIT_FUNCTION_ARG, 32)?;
assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_FUNCTION_ARG)); assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_FUNCTION_ARG)?);
db.set_limit(Limit::SQLITE_LIMIT_ATTACHED, 2); db.set_limit(Limit::SQLITE_LIMIT_ATTACHED, 2)?;
assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_ATTACHED)); assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_ATTACHED)?);
db.set_limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 128); db.set_limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 128)?;
assert_eq!(128, db.limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH)); assert_eq!(128, db.limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH)?);
db.set_limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER, 99); db.set_limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER, 99)?;
assert_eq!(99, db.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)); assert_eq!(99, db.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)?);
// SQLITE_LIMIT_TRIGGER_DEPTH was added in SQLite 3.6.18. db.set_limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH, 32)?;
if crate::version_number() >= 3_006_018 { assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH)?);
db.set_limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH, 32);
assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH));
}
// SQLITE_LIMIT_WORKER_THREADS was added in SQLite 3.8.7. db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2)?;
if crate::version_number() >= 3_008_007 { assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS)?);
db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2);
assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS)); assert!(db
} .set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, -1)
.is_err());
assert!(db.set_limit(Limit::INVALID, 0).is_err());
assert!(db.limit(Limit::INVALID).is_err());
Ok(()) Ok(())
} }
} }

View File

@@ -37,7 +37,7 @@ impl LoadExtensionGuard<'_> {
} }
} }
#[allow(unused_must_use)] #[expect(unused_must_use)]
impl Drop for LoadExtensionGuard<'_> { impl Drop for LoadExtensionGuard<'_> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {

View File

@@ -53,7 +53,7 @@ use sealed::Sealed;
/// ///
/// (Note: in this case we don't implement this for slices for coherence /// (Note: in this case we don't implement this for slices for coherence
/// reasons, so it really is only for the "reference to array" types — /// reasons, so it really is only for the "reference to array" types —
/// hence why the number of parameters must be <= 32 or you need to /// hence why the number of parameters must be <= 32, or you need to
/// reach for `rusqlite::params!`) /// reach for `rusqlite::params!`)
/// ///
/// Unfortunately, in the current design it's not possible to allow this for /// Unfortunately, in the current design it's not possible to allow this for
@@ -108,7 +108,7 @@ use sealed::Sealed;
/// parameters, or lists where the number of parameters exceeds 32. /// parameters, or lists where the number of parameters exceeds 32.
/// ///
/// - As a slice of `&[(&str, &dyn ToSql)]`. This is what essentially all of /// - As a slice of `&[(&str, &dyn ToSql)]`. This is what essentially all of
/// these boil down to in the end, conceptually at least. In theory you can /// these boil down to in the end, conceptually at least. In theory, you can
/// pass this as `stmt`. /// pass this as `stmt`.
/// ///
/// - As array references, similar to the positional params. This looks like /// - As array references, similar to the positional params. This looks like
@@ -124,7 +124,7 @@ use sealed::Sealed;
/// ```rust,no_run /// ```rust,no_run
/// # use rusqlite::{Connection, Result, named_params}; /// # use rusqlite::{Connection, Result, named_params};
/// fn insert(conn: &Connection) -> Result<()> { /// fn insert(conn: &Connection) -> Result<()> {
/// let mut stmt = conn.prepare("INSERT INTO test (key, value) VALUES (:key, :value)")?; /// let mut stmt = conn.prepare("INSERT INTO test (key, value) VALUES (:key, :val)")?;
/// // Using `rusqlite::params!`: /// // Using `rusqlite::params!`:
/// stmt.execute(named_params! { ":key": "one", ":val": 2 })?; /// stmt.execute(named_params! { ":key": "one", ":val": 2 })?;
/// // Alternatively: /// // Alternatively:
@@ -196,7 +196,7 @@ pub trait Params: Sealed {
// forces people to use `params![...]` or `rusqlite::params_from_iter` for long // forces people to use `params![...]` or `rusqlite::params_from_iter` for long
// homogeneous lists of parameters. This is not that big of a deal, but is // homogeneous lists of parameters. This is not that big of a deal, but is
// unfortunate, especially because I mostly did it because I wanted a simple // unfortunate, especially because I mostly did it because I wanted a simple
// syntax for no-params that didnt require importing -- the empty tuple fits // syntax for no-params that didn't require importing -- the empty tuple fits
// that nicely, but I didn't think of it until much later. // that nicely, but I didn't think of it until much later.
// //
// Admittedly, if we did have the generic impl, then we *wouldn't* support the // Admittedly, if we did have the generic impl, then we *wouldn't* support the
@@ -264,7 +264,7 @@ macro_rules! single_tuple_impl {
} }
} }
// We use a the macro for the rest, but don't bother with trying to implement it // We use a macro for the rest, but don't bother with trying to implement it
// in a single invocation (it's possible to do, but my attempts were almost the // in a single invocation (it's possible to do, but my attempts were almost the
// same amount of code as just writing it out this way, and much more dense -- // same amount of code as just writing it out this way, and much more dense --
// it is a more complicated case than the TryFrom macro we have for row->tuple). // it is a more complicated case than the TryFrom macro we have for row->tuple).
@@ -407,7 +407,7 @@ impl_for_array_ref!(
/// production-ready: /// production-ready:
/// ///
/// - production code should ensure `usernames` isn't so large that it will /// - production code should ensure `usernames` isn't so large that it will
/// surpass [`conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)`][limits]), /// surpass [`conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)`][limits],
/// chunking if too large. (Note that the limits api requires rusqlite to have /// chunking if too large. (Note that the limits api requires rusqlite to have
/// the "limits" feature). /// the "limits" feature).
/// ///

View File

@@ -2,7 +2,6 @@
use std::ops::Deref; use std::ops::Deref;
use crate::error::Error;
use crate::ffi; use crate::ffi;
use crate::types::{ToSql, ToSqlOutput, ValueRef}; use crate::types::{ToSql, ToSqlOutput, ValueRef};
use crate::{Connection, DatabaseName, Result, Row}; use crate::{Connection, DatabaseName, Result, Row};
@@ -12,8 +11,8 @@ pub struct Sql {
} }
impl Sql { impl Sql {
pub fn new() -> Sql { pub fn new() -> Self {
Sql { buf: String::new() } Self { buf: String::new() }
} }
pub fn push_pragma( pub fn push_pragma(
@@ -35,10 +34,7 @@ impl Sql {
self.buf.push_str(keyword); self.buf.push_str(keyword);
Ok(()) Ok(())
} else { } else {
Err(Error::SqliteFailure( Err(err!(ffi::SQLITE_MISUSE, "Invalid keyword \"{keyword}\""))
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Invalid keyword \"{keyword}\"")),
))
} }
} }
@@ -47,6 +43,7 @@ impl Sql {
DatabaseName::Main => self.buf.push_str("main"), DatabaseName::Main => self.buf.push_str("main"),
DatabaseName::Temp => self.buf.push_str("temp"), DatabaseName::Temp => self.buf.push_str("temp"),
DatabaseName::Attached(s) => self.push_identifier(s), DatabaseName::Attached(s) => self.push_identifier(s),
DatabaseName::C(s) => self.push_identifier(s.to_str().expect("invalid database name")),
}; };
} }
@@ -65,24 +62,15 @@ impl Sql {
ToSqlOutput::Owned(ref v) => ValueRef::from(v), ToSqlOutput::Owned(ref v) => ValueRef::from(v),
#[cfg(feature = "blob")] #[cfg(feature = "blob")]
ToSqlOutput::ZeroBlob(_) => { ToSqlOutput::ZeroBlob(_) => {
return Err(Error::SqliteFailure( return Err(err!(ffi::SQLITE_MISUSE, "Unsupported value \"{value:?}\""));
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{value:?}\"")),
));
} }
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
ToSqlOutput::Arg(_) => { ToSqlOutput::Arg(_) => {
return Err(Error::SqliteFailure( return Err(err!(ffi::SQLITE_MISUSE, "Unsupported value \"{value:?}\""));
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{value:?}\"")),
));
} }
#[cfg(feature = "array")] #[cfg(feature = "array")]
ToSqlOutput::Array(_) => { ToSqlOutput::Array(_) => {
return Err(Error::SqliteFailure( return Err(err!(ffi::SQLITE_MISUSE, "Unsupported value \"{value:?}\""));
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{value:?}\"")),
));
} }
}; };
match value { match value {
@@ -97,10 +85,7 @@ impl Sql {
self.push_string_literal(s); self.push_string_literal(s);
} }
_ => { _ => {
return Err(Error::SqliteFailure( return Err(err!(ffi::SQLITE_MISUSE, "Unsupported value \"{value:?}\""));
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{value:?}\"")),
));
} }
}; };
Ok(()) Ok(())

View File

@@ -29,8 +29,8 @@ pub struct RawStatement {
impl RawStatement { impl RawStatement {
#[inline] #[inline]
pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt, tail: usize) -> RawStatement { pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt, tail: usize) -> Self {
RawStatement { Self {
ptr: stmt, ptr: stmt,
tail, tail,
cache: ParamIndexCache::default(), cache: ParamIndexCache::default(),
@@ -169,7 +169,7 @@ impl RawStatement {
} }
#[inline] #[inline]
pub fn clear_bindings(&self) { pub fn clear_bindings(&mut self) {
unsafe { unsafe {
ffi::sqlite3_clear_bindings(self.ptr); ffi::sqlite3_clear_bindings(self.ptr);
} // rc is always SQLITE_OK } // rc is always SQLITE_OK
@@ -204,13 +204,12 @@ impl RawStatement {
#[inline] #[inline]
pub(crate) fn expanded_sql(&self) -> Option<SqliteMallocString> { pub(crate) fn expanded_sql(&self) -> Option<SqliteMallocString> {
unsafe { SqliteMallocString::from_raw(ffi::sqlite3_expanded_sql(self.ptr)) } unsafe { expanded_sql(self.ptr) }
} }
#[inline] #[inline]
pub fn get_status(&self, status: StatementStatus, reset: bool) -> i32 { pub fn get_status(&self, status: StatementStatus, reset: bool) -> i32 {
assert!(!self.ptr.is_null()); unsafe { stmt_status(self.ptr, status, reset) }
unsafe { ffi::sqlite3_stmt_status(self.ptr, status as i32, reset as i32) }
} }
#[inline] #[inline]
@@ -233,6 +232,20 @@ impl RawStatement {
// TODO sqlite3_normalized_sql (https://sqlite.org/c3ref/expanded_sql.html) // 3.27.0 + SQLITE_ENABLE_NORMALIZE // TODO sqlite3_normalized_sql (https://sqlite.org/c3ref/expanded_sql.html) // 3.27.0 + SQLITE_ENABLE_NORMALIZE
} }
#[inline]
pub(crate) unsafe fn expanded_sql(ptr: *mut ffi::sqlite3_stmt) -> Option<SqliteMallocString> {
SqliteMallocString::from_raw(ffi::sqlite3_expanded_sql(ptr))
}
#[inline]
pub(crate) unsafe fn stmt_status(
ptr: *mut ffi::sqlite3_stmt,
status: StatementStatus,
reset: bool,
) -> i32 {
assert!(!ptr.is_null());
ffi::sqlite3_stmt_status(ptr, status as i32, reset as i32)
}
impl Drop for RawStatement { impl Drop for RawStatement {
fn drop(&mut self) { fn drop(&mut self) {
self.finalize_(); self.finalize_();

View File

@@ -5,7 +5,7 @@ use std::convert;
use super::{Error, Result, Statement}; use super::{Error, Result, Statement};
use crate::types::{FromSql, FromSqlError, ValueRef}; use crate::types::{FromSql, FromSqlError, ValueRef};
/// An handle for the resulting rows of a query. /// A handle (lazy fallible streaming iterator) for the resulting rows of a query.
#[must_use = "Rows is lazy and will do nothing unless consumed"] #[must_use = "Rows is lazy and will do nothing unless consumed"]
pub struct Rows<'stmt> { pub struct Rows<'stmt> {
pub(crate) stmt: Option<&'stmt Statement<'stmt>>, pub(crate) stmt: Option<&'stmt Statement<'stmt>>,
@@ -34,7 +34,7 @@ impl<'stmt> Rows<'stmt> {
/// consider using [`query_map`](Statement::query_map) or /// consider using [`query_map`](Statement::query_map) or
/// [`query_and_then`](Statement::query_and_then) instead, which /// [`query_and_then`](Statement::query_and_then) instead, which
/// return types that implement `Iterator`. /// return types that implement `Iterator`.
#[allow(clippy::should_implement_trait)] // cannot implement Iterator #[expect(clippy::should_implement_trait)] // cannot implement Iterator
#[inline] #[inline]
pub fn next(&mut self) -> Result<Option<&Row<'stmt>>> { pub fn next(&mut self) -> Result<Option<&Row<'stmt>>> {
self.advance()?; self.advance()?;
@@ -90,7 +90,7 @@ impl<'stmt> Rows<'stmt> {
impl<'stmt> Rows<'stmt> { impl<'stmt> Rows<'stmt> {
#[inline] #[inline]
pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> { pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Self {
Rows { Rows {
stmt: Some(stmt), stmt: Some(stmt),
row: None, row: None,
@@ -107,7 +107,7 @@ impl<'stmt> Rows<'stmt> {
} }
impl Drop for Rows<'_> { impl Drop for Rows<'_> {
#[allow(unused_must_use)] #[expect(unused_must_use)]
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
self.reset(); self.reset();
@@ -247,7 +247,7 @@ pub struct Row<'stmt> {
pub(crate) stmt: &'stmt Statement<'stmt>, pub(crate) stmt: &'stmt Statement<'stmt>,
} }
impl<'stmt> Row<'stmt> { impl Row<'_> {
/// Get the value of a particular column of the result row. /// Get the value of a particular column of the result row.
/// ///
/// # Panics /// # Panics
@@ -305,7 +305,7 @@ impl<'stmt> Row<'stmt> {
/// allowing data to be read out of a row without copying. /// allowing data to be read out of a row without copying.
/// ///
/// This `ValueRef` is valid only as long as this Row, which is enforced by /// This `ValueRef` is valid only as long as this Row, which is enforced by
/// it's lifetime. This means that while this method is completely safe, /// its lifetime. This means that while this method is completely safe,
/// it can be somewhat difficult to use, and most callers will be better /// it can be somewhat difficult to use, and most callers will be better
/// served by [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap). /// served by [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
/// ///
@@ -329,7 +329,7 @@ impl<'stmt> Row<'stmt> {
/// allowing data to be read out of a row without copying. /// allowing data to be read out of a row without copying.
/// ///
/// This `ValueRef` is valid only as long as this Row, which is enforced by /// This `ValueRef` is valid only as long as this Row, which is enforced by
/// it's lifetime. This means that while this method is completely safe, /// its lifetime. This means that while this method is completely safe,
/// it can be difficult to use, and most callers will be better served by /// it can be difficult to use, and most callers will be better served by
/// [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap). /// [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
/// ///
@@ -355,11 +355,11 @@ impl<'stmt> AsRef<Statement<'stmt>> for Row<'stmt> {
/// Debug `Row` like an ordered `Map<Result<&str>, Result<(Type, ValueRef)>>` /// Debug `Row` like an ordered `Map<Result<&str>, Result<(Type, ValueRef)>>`
/// with column name as key except that for `Type::Blob` only its size is /// with column name as key except that for `Type::Blob` only its size is
/// printed (not its content). /// printed (not its content).
impl<'stmt> std::fmt::Debug for Row<'stmt> { impl std::fmt::Debug for Row<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut dm = f.debug_map(); let mut dm = f.debug_map();
for c in 0..self.stmt.column_count() { for c in 0..self.stmt.column_count() {
let name = self.stmt.column_name(c); let name = self.stmt.column_name(c).expect("valid column index");
dm.key(&name); dm.key(&name);
let value = self.get_ref(c); let value = self.get_ref(c);
match value { match value {
@@ -438,7 +438,7 @@ macro_rules! tuple_try_from_row {
fn try_from(row: &'a Row<'a>) -> Result<Self> { fn try_from(row: &'a Row<'a>) -> Result<Self> {
let mut index = 0; let mut index = 0;
$( $(
#[allow(non_snake_case)] #[expect(non_snake_case)]
let $field = row.get::<_, $field>(index)?; let $field = row.get::<_, $field>(index)?;
index += 1; index += 1;
)* )*
@@ -463,7 +463,6 @@ tuples_try_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::redundant_closure)] // false positives due to lifetime issues; clippy issue #5594
use crate::{Connection, Result}; use crate::{Connection, Result};
#[test] #[test]
@@ -614,4 +613,29 @@ mod tests {
} }
Ok(()) Ok(())
} }
#[test]
fn as_ref() -> Result<()> {
let conn = Connection::open_in_memory()?;
let mut stmt = conn.prepare("SELECT 'Lisa' as name, 1 as id")?;
let rows = stmt.query([])?;
assert_eq!(rows.as_ref().unwrap().column_count(), 2);
Ok(())
}
#[test]
fn debug() -> Result<()> {
let conn = Connection::open_in_memory()?;
let mut stmt = conn.prepare(
"SELECT 'Lisa' as name, 1 as id, 3.14 as pi, X'53514C697465' as blob, NULL as void",
)?;
let mut rows = stmt.query([])?;
let row = rows.next()?.unwrap();
let s = format!("{row:?}");
assert_eq!(
s,
r#"{"name": (Text, "Lisa"), "id": (Integer, 1), "pi": (Real, 3.14), "blob": (Blob, 6), "void": (Null, ())}"#
);
Ok(())
}
} }

View File

@@ -1,5 +1,4 @@
//! Serialize a database. //! Serialize a database.
use std::convert::TryInto;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::Deref; use std::ops::Deref;
use std::ptr::NonNull; use std::ptr::NonNull;
@@ -52,7 +51,7 @@ pub enum Data<'conn> {
Owned(OwnedData), Owned(OwnedData),
} }
impl<'conn> Deref for Data<'conn> { impl Deref for Data<'_> {
type Target = [u8]; type Target = [u8];
fn deref(&self) -> &[u8] { fn deref(&self) -> &[u8] {
@@ -67,7 +66,7 @@ impl<'conn> Deref for Data<'conn> {
impl Connection { impl Connection {
/// Serialize a database. /// Serialize a database.
pub fn serialize(&self, schema: DatabaseName) -> Result<Data> { pub fn serialize(&self, schema: DatabaseName) -> Result<Data> {
let schema = schema.as_cstring()?; let schema = schema.as_cstr()?;
let mut sz = 0; let mut sz = 0;
let mut ptr: *mut u8 = unsafe { let mut ptr: *mut u8 = unsafe {
ffi::sqlite3_serialize( ffi::sqlite3_serialize(
@@ -103,7 +102,7 @@ impl Connection {
data: OwnedData, data: OwnedData,
read_only: bool, read_only: bool,
) -> Result<()> { ) -> Result<()> {
let schema = schema.as_cstring()?; let schema = schema.as_cstr()?;
let (data, sz) = data.into_raw(); let (data, sz) = data.into_raw();
let sz = sz.try_into().unwrap(); let sz = sz.try_into().unwrap();
let flags = if read_only { let flags = if read_only {
@@ -136,7 +135,6 @@ impl Connection {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::{Connection, DatabaseName, Result};
#[test] #[test]
fn serialize() -> Result<()> { fn serialize() -> Result<()> {

View File

@@ -1,17 +1,17 @@
//! [Session Extension](https://sqlite.org/sessionintro.html) //! [Session Extension](https://sqlite.org/sessionintro.html)
#![allow(non_camel_case_types)] #![expect(non_camel_case_types)]
use std::ffi::CStr; use std::ffi::CStr;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::raw::{c_char, c_int, c_uchar, c_void}; use std::os::raw::{c_char, c_int, c_uchar, c_void};
use std::panic::{catch_unwind, RefUnwindSafe}; use std::panic::catch_unwind;
use std::ptr; use std::ptr;
use std::slice::{from_raw_parts, from_raw_parts_mut}; use std::slice::{from_raw_parts, from_raw_parts_mut};
use fallible_streaming_iterator::FallibleStreamingIterator; use fallible_streaming_iterator::FallibleStreamingIterator;
use crate::error::{check, error_from_sqlite_code}; use crate::error::{check, error_from_sqlite_code, Error};
use crate::ffi; use crate::ffi;
use crate::hooks::Action; use crate::hooks::Action;
use crate::types::ValueRef; use crate::types::ValueRef;
@@ -42,7 +42,7 @@ impl Session<'_> {
db: &'conn Connection, db: &'conn Connection,
name: DatabaseName<'_>, name: DatabaseName<'_>,
) -> Result<Session<'conn>> { ) -> Result<Session<'conn>> {
let name = name.as_cstring()?; let name = name.as_cstr()?;
let db = db.db.borrow_mut().db; let db = db.db.borrow_mut().db;
@@ -59,25 +59,22 @@ impl Session<'_> {
/// Set a table filter /// Set a table filter
pub fn table_filter<F>(&mut self, filter: Option<F>) pub fn table_filter<F>(&mut self, filter: Option<F>)
where where
F: Fn(&str) -> bool + Send + RefUnwindSafe + 'static, F: Fn(&str) -> bool + Send + 'static,
{ {
unsafe extern "C" fn call_boxed_closure<F>( unsafe extern "C" fn call_boxed_closure<F>(
p_arg: *mut c_void, p_arg: *mut c_void,
tbl_str: *const c_char, tbl_str: *const c_char,
) -> c_int ) -> c_int
where where
F: Fn(&str) -> bool + RefUnwindSafe, F: Fn(&str) -> bool,
{ {
use std::str; let tbl_name = CStr::from_ptr(tbl_str).to_str();
let boxed_filter: *mut F = p_arg as *mut F;
let tbl_name = {
let c_slice = CStr::from_ptr(tbl_str).to_bytes();
str::from_utf8(c_slice)
};
c_int::from( c_int::from(
catch_unwind(|| (*boxed_filter)(tbl_name.expect("non-utf8 table name"))) catch_unwind(|| {
.unwrap_or_default(), let boxed_filter: *mut F = p_arg.cast::<F>();
(*boxed_filter)(tbl_name.expect("non-utf8 table name"))
})
.unwrap_or_default(),
) )
} }
@@ -157,7 +154,7 @@ impl Session<'_> {
/// Load the difference between tables. /// Load the difference between tables.
pub fn diff(&mut self, from: DatabaseName<'_>, table: &str) -> Result<()> { pub fn diff(&mut self, from: DatabaseName<'_>, table: &str) -> Result<()> {
let from = from.as_cstring()?; let from = from.as_cstr()?;
let table = str_to_cstring(table)?; let table = str_to_cstring(table)?;
let table = table.as_ptr(); let table = table.as_ptr();
unsafe { unsafe {
@@ -336,7 +333,7 @@ impl ChangesetIter<'_> {
} }
impl FallibleStreamingIterator for ChangesetIter<'_> { impl FallibleStreamingIterator for ChangesetIter<'_> {
type Error = crate::error::Error; type Error = Error;
type Item = ChangesetItem; type Item = ChangesetItem;
#[inline] #[inline]
@@ -426,7 +423,11 @@ impl ChangesetItem {
col as i32, col as i32,
&mut p_value, &mut p_value,
))?; ))?;
Ok(ValueRef::from_value(p_value)) if p_value.is_null() {
Err(Error::InvalidColumnIndex(col))
} else {
Ok(ValueRef::from_value(p_value))
}
} }
} }
@@ -452,7 +453,11 @@ impl ChangesetItem {
unsafe { unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut(); let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
check(ffi::sqlite3changeset_new(self.it, col as i32, &mut p_value))?; check(ffi::sqlite3changeset_new(self.it, col as i32, &mut p_value))?;
Ok(ValueRef::from_value(p_value)) if p_value.is_null() {
Err(Error::InvalidColumnIndex(col))
} else {
Ok(ValueRef::from_value(p_value))
}
} }
} }
@@ -465,7 +470,11 @@ impl ChangesetItem {
unsafe { unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut(); let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
check(ffi::sqlite3changeset_old(self.it, col as i32, &mut p_value))?; check(ffi::sqlite3changeset_old(self.it, col as i32, &mut p_value))?;
Ok(ValueRef::from_value(p_value)) if p_value.is_null() {
Err(Error::InvalidColumnIndex(col))
} else {
Ok(ValueRef::from_value(p_value))
}
} }
} }
@@ -581,8 +590,8 @@ impl Connection {
/// Apply a changeset to a database /// Apply a changeset to a database
pub fn apply<F, C>(&self, cs: &Changeset, filter: Option<F>, conflict: C) -> Result<()> pub fn apply<F, C>(&self, cs: &Changeset, filter: Option<F>, conflict: C) -> Result<()>
where where
F: Fn(&str) -> bool + Send + RefUnwindSafe + 'static, F: Fn(&str) -> bool + Send + 'static,
C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + RefUnwindSafe + 'static, C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + 'static,
{ {
let db = self.db.borrow_mut().db; let db = self.db.borrow_mut().db;
@@ -619,8 +628,8 @@ impl Connection {
conflict: C, conflict: C,
) -> Result<()> ) -> Result<()>
where where
F: Fn(&str) -> bool + Send + RefUnwindSafe + 'static, F: Fn(&str) -> bool + Send + 'static,
C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + RefUnwindSafe + 'static, C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + 'static,
{ {
let input_ref = &input; let input_ref = &input;
let db = self.db.borrow_mut().db; let db = self.db.borrow_mut().db;
@@ -657,7 +666,6 @@ impl Connection {
#[repr(i32)] #[repr(i32)]
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
#[allow(clippy::upper_case_acronyms)]
pub enum ConflictType { pub enum ConflictType {
UNKNOWN = -1, UNKNOWN = -1,
SQLITE_CHANGESET_DATA = ffi::SQLITE_CHANGESET_DATA, SQLITE_CHANGESET_DATA = ffi::SQLITE_CHANGESET_DATA,
@@ -685,7 +693,6 @@ impl From<i32> for ConflictType {
#[repr(i32)] #[repr(i32)]
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
#[allow(clippy::upper_case_acronyms)]
pub enum ConflictAction { pub enum ConflictAction {
SQLITE_CHANGESET_OMIT = ffi::SQLITE_CHANGESET_OMIT, SQLITE_CHANGESET_OMIT = ffi::SQLITE_CHANGESET_OMIT,
SQLITE_CHANGESET_REPLACE = ffi::SQLITE_CHANGESET_REPLACE, SQLITE_CHANGESET_REPLACE = ffi::SQLITE_CHANGESET_REPLACE,
@@ -694,22 +701,21 @@ pub enum ConflictAction {
unsafe extern "C" fn call_filter<F, C>(p_ctx: *mut c_void, tbl_str: *const c_char) -> c_int unsafe extern "C" fn call_filter<F, C>(p_ctx: *mut c_void, tbl_str: *const c_char) -> c_int
where where
F: Fn(&str) -> bool + Send + RefUnwindSafe + 'static, F: Fn(&str) -> bool + Send + 'static,
C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + RefUnwindSafe + 'static, C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + 'static,
{ {
use std::str; let tbl_name = CStr::from_ptr(tbl_str).to_str();
c_int::from(
let tuple: *mut (Option<F>, C) = p_ctx as *mut (Option<F>, C); catch_unwind(|| {
let tbl_name = { let tuple: *mut (Option<F>, C) = p_ctx.cast::<(Option<F>, C)>();
let c_slice = CStr::from_ptr(tbl_str).to_bytes(); if let Some(ref filter) = (*tuple).0 {
str::from_utf8(c_slice) filter(tbl_name.expect("illegal table name"))
}; } else {
match *tuple { true
(Some(ref filter), _) => c_int::from( }
catch_unwind(|| filter(tbl_name.expect("illegal table name"))).unwrap_or_default(), })
), .unwrap_or_default(),
_ => unimplemented!(), )
}
} }
unsafe extern "C" fn call_conflict<F, C>( unsafe extern "C" fn call_conflict<F, C>(
@@ -718,13 +724,15 @@ unsafe extern "C" fn call_conflict<F, C>(
p: *mut ffi::sqlite3_changeset_iter, p: *mut ffi::sqlite3_changeset_iter,
) -> c_int ) -> c_int
where where
F: Fn(&str) -> bool + Send + RefUnwindSafe + 'static, F: Fn(&str) -> bool + Send + 'static,
C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + RefUnwindSafe + 'static, C: Fn(ConflictType, ChangesetItem) -> ConflictAction + Send + 'static,
{ {
let tuple: *mut (Option<F>, C) = p_ctx as *mut (Option<F>, C);
let conflict_type = ConflictType::from(e_conflict); let conflict_type = ConflictType::from(e_conflict);
let item = ChangesetItem { it: p }; let item = ChangesetItem { it: p };
if let Ok(action) = catch_unwind(|| (*tuple).1(conflict_type, item)) { if let Ok(action) = catch_unwind(|| {
let tuple: *mut (Option<F>, C) = p_ctx.cast::<(Option<F>, C)>();
(*tuple).1(conflict_type, item)
}) {
action as c_int action as c_int
} else { } else {
ffi::SQLITE_CHANGESET_ABORT ffi::SQLITE_CHANGESET_ABORT
@@ -771,7 +779,7 @@ mod test {
use crate::hooks::Action; use crate::hooks::Action;
use crate::{Connection, Result}; use crate::{Connection, Result};
fn one_changeset() -> Result<Changeset> { fn one_changeset_insert() -> Result<Changeset> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?; db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;
@@ -784,6 +792,20 @@ mod test {
session.changeset() session.changeset()
} }
fn one_changeset_update() -> Result<Changeset> {
let db = Connection::open_in_memory()?;
db.execute_batch(
"CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL, i INTEGER NOT NULL DEFAULT 0);",
)?;
db.execute_batch("INSERT INTO foo (t) VALUES ('bar');")?;
let mut session = Session::new(&db)?;
session.attach(None)?;
db.execute("UPDATE foo SET i=100 WHERE t='bar';", [])?;
session.changeset()
}
fn one_changeset_strm() -> Result<Vec<u8>> { fn one_changeset_strm() -> Result<Vec<u8>> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?; db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;
@@ -801,7 +823,7 @@ mod test {
#[test] #[test]
fn test_changeset() -> Result<()> { fn test_changeset() -> Result<()> {
let changeset = one_changeset()?; let changeset = one_changeset_insert()?;
let mut iter = changeset.iter()?; let mut iter = changeset.iter()?;
let item = iter.next()?; let item = iter.next()?;
assert!(item.is_some()); assert!(item.is_some());
@@ -834,9 +856,22 @@ mod test {
Ok(()) Ok(())
} }
#[test]
fn test_changeset_values() -> Result<()> {
let changeset = one_changeset_update()?;
let mut iter = changeset.iter()?;
let item = iter.next()?.unwrap();
let new_value = item.new_value(0); // unchanged
assert_eq!(Err(crate::Error::InvalidColumnIndex(0)), new_value);
let new_value = item.new_value(1)?; // updated
assert_eq!(Ok(100), new_value.as_i64());
Ok(())
}
#[test] #[test]
fn test_changeset_apply() -> Result<()> { fn test_changeset_apply() -> Result<()> {
let changeset = one_changeset()?; let changeset = one_changeset_insert()?;
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?; db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;

View File

@@ -1,4 +1,3 @@
use std::iter::IntoIterator;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
#[cfg(feature = "array")] #[cfg(feature = "array")]
use std::rc::Rc; use std::rc::Rc;
@@ -442,7 +441,8 @@ impl Statement<'_> {
#[inline] #[inline]
pub fn parameter_name(&self, index: usize) -> Option<&'_ str> { pub fn parameter_name(&self, index: usize) -> Option<&'_ str> {
self.stmt.bind_parameter_name(index as i32).map(|name| { self.stmt.bind_parameter_name(index as i32).map(|name| {
str::from_utf8(name.to_bytes()).expect("Invalid UTF-8 sequence in parameter name") name.to_str()
.expect("Invalid UTF-8 sequence in parameter name")
}) })
} }
@@ -561,7 +561,7 @@ impl Statement<'_> {
/// ///
/// Any unbound parameters will have `NULL` as their value. /// Any unbound parameters will have `NULL` as their value.
/// ///
/// This should not generally be used outside of special cases, and /// This should not generally be used outside special cases, and
/// functions in the [`Statement::execute`] family should be preferred. /// functions in the [`Statement::execute`] family should be preferred.
/// ///
/// # Failure /// # Failure
@@ -580,7 +580,7 @@ impl Statement<'_> {
/// ///
/// Any unbound parameters will have `NULL` as their value. /// Any unbound parameters will have `NULL` as their value.
/// ///
/// This should not generally be used outside of special cases, and /// This should not generally be used outside special cases, and
/// functions in the [`Statement::query`] family should be preferred. /// functions in the [`Statement::query`] family should be preferred.
/// ///
/// Note that if the SQL does not return results, [`Statement::raw_execute`] /// Note that if the SQL does not return results, [`Statement::raw_execute`]
@@ -608,10 +608,7 @@ impl Statement<'_> {
} }
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
ToSqlOutput::Arg(_) => { ToSqlOutput::Arg(_) => {
return Err(Error::SqliteFailure( return Err(err!(ffi::SQLITE_MISUSE, "Unsupported value \"{value:?}\""));
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("Unsupported value \"{value:?}\"")),
));
} }
#[cfg(feature = "array")] #[cfg(feature = "array")]
ToSqlOutput::Array(a) => { ToSqlOutput::Array(a) => {
@@ -687,7 +684,7 @@ impl Statement<'_> {
#[cfg(not(feature = "extra_check"))] #[cfg(not(feature = "extra_check"))]
#[inline] #[inline]
#[allow(clippy::unnecessary_wraps)] #[expect(clippy::unnecessary_wraps)]
fn check_update(&self) -> Result<()> { fn check_update(&self) -> Result<()> {
Ok(()) Ok(())
} }
@@ -741,7 +738,7 @@ impl Statement<'_> {
#[cfg(not(feature = "extra_check"))] #[cfg(not(feature = "extra_check"))]
#[inline] #[inline]
#[allow(clippy::unnecessary_wraps)] #[expect(clippy::unnecessary_wraps)]
pub(crate) fn check_no_tail(&self) -> Result<()> { pub(crate) fn check_no_tail(&self) -> Result<()> {
Ok(()) Ok(())
} }
@@ -767,7 +764,7 @@ impl fmt::Debug for Statement<'_> {
let sql = if self.stmt.is_null() { let sql = if self.stmt.is_null() {
Ok("") Ok("")
} else { } else {
str::from_utf8(self.stmt.sql().unwrap().to_bytes()) self.stmt.sql().unwrap().to_str()
}; };
f.debug_struct("Statement") f.debug_struct("Statement")
.field("conn", self.conn) .field("conn", self.conn)
@@ -778,7 +775,7 @@ impl fmt::Debug for Statement<'_> {
} }
impl Drop for Statement<'_> { impl Drop for Statement<'_> {
#[allow(unused_must_use)] #[expect(unused_must_use)]
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
self.finalize_(); self.finalize_();
@@ -876,23 +873,23 @@ impl Statement<'_> {
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
pub enum StatementStatus { pub enum StatementStatus {
/// Equivalent to SQLITE_STMTSTATUS_FULLSCAN_STEP /// Equivalent to `SQLITE_STMTSTATUS_FULLSCAN_STEP`
FullscanStep = 1, FullscanStep = 1,
/// Equivalent to SQLITE_STMTSTATUS_SORT /// Equivalent to `SQLITE_STMTSTATUS_SORT`
Sort = 2, Sort = 2,
/// Equivalent to SQLITE_STMTSTATUS_AUTOINDEX /// Equivalent to `SQLITE_STMTSTATUS_AUTOINDEX`
AutoIndex = 3, AutoIndex = 3,
/// Equivalent to SQLITE_STMTSTATUS_VM_STEP /// Equivalent to `SQLITE_STMTSTATUS_VM_STEP`
VmStep = 4, VmStep = 4,
/// Equivalent to SQLITE_STMTSTATUS_REPREPARE (3.20.0) /// Equivalent to `SQLITE_STMTSTATUS_REPREPARE` (3.20.0)
RePrepare = 5, RePrepare = 5,
/// Equivalent to SQLITE_STMTSTATUS_RUN (3.20.0) /// Equivalent to `SQLITE_STMTSTATUS_RUN` (3.20.0)
Run = 6, Run = 6,
/// Equivalent to SQLITE_STMTSTATUS_FILTER_MISS /// Equivalent to `SQLITE_STMTSTATUS_FILTER_MISS`
FilterMiss = 7, FilterMiss = 7,
/// Equivalent to SQLITE_STMTSTATUS_FILTER_HIT /// Equivalent to `SQLITE_STMTSTATUS_FILTER_HIT`
FilterHit = 8, FilterHit = 8,
/// Equivalent to SQLITE_STMTSTATUS_MEMUSED (3.20.0) /// Equivalent to `SQLITE_STMTSTATUS_MEMUSED` (3.20.0)
MemUsed = 99, MemUsed = 99,
} }
@@ -1019,8 +1016,8 @@ mod test {
let doubled_id: i32 = rows.next().unwrap()?; let doubled_id: i32 = rows.next().unwrap()?;
assert_eq!(1, doubled_id); assert_eq!(1, doubled_id);
// second row should be Err // second row should be an `Err`
#[allow(clippy::match_wild_err_arm)] #[expect(clippy::match_wild_err_arm)]
match rows.next().unwrap() { match rows.next().unwrap() {
Ok(_) => panic!("invalid Ok"), Ok(_) => panic!("invalid Ok"),
Err(Error::SqliteSingleThreadedMode) => (), Err(Error::SqliteSingleThreadedMode) => (),
@@ -1285,9 +1282,12 @@ mod test {
let conn = Connection::open_in_memory()?; let conn = Connection::open_in_memory()?;
let mut stmt = conn.prepare("")?; let mut stmt = conn.prepare("")?;
assert_eq!(0, stmt.column_count()); assert_eq!(0, stmt.column_count());
stmt.parameter_index("test").unwrap(); stmt.parameter_index("test")?;
stmt.step().unwrap_err(); let err = stmt.step().unwrap_err();
stmt.reset().unwrap(); // SQLITE_OMIT_AUTORESET = false assert_eq!(err.sqlite_error_code(), Some(crate::ErrorCode::ApiMisuse));
// error msg is different with sqlcipher, so we use assert_ne:
assert_ne!(err.to_string(), "not an error".to_owned());
stmt.reset()?; // SQLITE_OMIT_AUTORESET = false
stmt.execute([]).unwrap_err(); stmt.execute([]).unwrap_err();
Ok(()) Ok(())
} }

View File

@@ -1,14 +1,16 @@
//! Tracing and profiling functions. Error and warning log. //! Tracing and profiling functions. Error and warning log.
use std::borrow::Cow;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::mem; use std::mem;
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_uint, c_void};
use std::panic::catch_unwind; use std::panic::catch_unwind;
use std::ptr; use std::ptr;
use std::time::Duration; use std::time::Duration;
use super::ffi; use super::ffi;
use crate::Connection; use crate::{Connection, DatabaseName, StatementStatus};
/// Set up the process-wide SQLite error logging callback. /// Set up the process-wide SQLite error logging callback.
/// ///
@@ -27,10 +29,9 @@ use crate::Connection;
#[cfg(not(feature = "loadable_extension"))] #[cfg(not(feature = "loadable_extension"))]
pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> crate::Result<()> { pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> crate::Result<()> {
extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) { extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) {
let c_slice = unsafe { CStr::from_ptr(msg).to_bytes() }; let s = unsafe { CStr::from_ptr(msg).to_string_lossy() };
let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) }; let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };
let s = String::from_utf8_lossy(c_slice);
drop(catch_unwind(|| callback(err, &s))); drop(catch_unwind(|| callback(err, &s)));
} }
@@ -62,6 +63,84 @@ pub fn log(err_code: c_int, msg: &str) {
} }
} }
bitflags::bitflags! {
/// Trace event codes
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
#[repr(C)]
pub struct TraceEventCodes: ::std::os::raw::c_uint {
/// when a prepared statement first begins running and possibly at other times during the execution
/// of the prepared statement, such as at the start of each trigger subprogram
const SQLITE_TRACE_STMT = ffi::SQLITE_TRACE_STMT;
/// when the statement finishes
const SQLITE_TRACE_PROFILE = ffi::SQLITE_TRACE_PROFILE;
/// whenever a prepared statement generates a single row of result
const SQLITE_TRACE_ROW = ffi::SQLITE_TRACE_ROW;
/// when a database connection closes
const SQLITE_TRACE_CLOSE = ffi::SQLITE_TRACE_CLOSE;
}
}
/// Trace event
#[non_exhaustive]
pub enum TraceEvent<'s> {
/// when a prepared statement first begins running and possibly at other times during the execution
/// of the prepared statement, such as at the start of each trigger subprogram
Stmt(StmtRef<'s>, &'s str),
/// when the statement finishes
Profile(StmtRef<'s>, Duration),
/// whenever a prepared statement generates a single row of result
Row(StmtRef<'s>),
/// when a database connection closes
Close(ConnRef<'s>),
}
/// Statement reference
pub struct StmtRef<'s> {
ptr: *mut ffi::sqlite3_stmt,
phantom: PhantomData<&'s ()>,
}
impl StmtRef<'_> {
fn new(ptr: *mut ffi::sqlite3_stmt) -> Self {
StmtRef {
ptr,
phantom: PhantomData,
}
}
/// SQL text
pub fn sql(&self) -> Cow<'_, str> {
unsafe { CStr::from_ptr(ffi::sqlite3_sql(self.ptr)).to_string_lossy() }
}
/// Expanded SQL text
pub fn expanded_sql(&self) -> Option<String> {
unsafe {
crate::raw_statement::expanded_sql(self.ptr).map(|s| s.to_string_lossy().to_string())
}
}
/// Get the value for one of the status counters for this statement.
pub fn get_status(&self, status: StatementStatus) -> i32 {
unsafe { crate::raw_statement::stmt_status(self.ptr, status, false) }
}
}
/// Connection reference
pub struct ConnRef<'s> {
ptr: *mut ffi::sqlite3,
phantom: PhantomData<&'s ()>,
}
impl ConnRef<'_> {
/// Test for auto-commit mode.
pub fn is_autocommit(&self) -> bool {
unsafe { crate::inner_connection::get_autocommit(self.ptr) }
}
/// the path to the database file, if one exists and is known.
pub fn db_filename(&self) -> Option<&str> {
unsafe { crate::inner_connection::db_filename(self.ptr, DatabaseName::Main) }
}
}
impl Connection { impl Connection {
/// Register or clear a callback function that can be /// Register or clear a callback function that can be
/// used for tracing the execution of SQL statements. /// used for tracing the execution of SQL statements.
@@ -69,11 +148,11 @@ impl Connection {
/// Prepared statement placeholders are replaced/logged with their assigned /// Prepared statement placeholders are replaced/logged with their assigned
/// values. There can only be a single tracer defined for each database /// values. There can only be a single tracer defined for each database
/// connection. Setting a new tracer clears the old one. /// connection. Setting a new tracer clears the old one.
#[deprecated(since = "0.33.0", note = "use trace_v2 instead")]
pub fn trace(&mut self, trace_fn: Option<fn(&str)>) { pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) { unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) {
let trace_fn: fn(&str) = mem::transmute(p_arg); let trace_fn: fn(&str) = mem::transmute(p_arg);
let c_slice = CStr::from_ptr(z_sql).to_bytes(); let s = CStr::from_ptr(z_sql).to_string_lossy();
let s = String::from_utf8_lossy(c_slice);
drop(catch_unwind(|| trace_fn(&s))); drop(catch_unwind(|| trace_fn(&s)));
} }
@@ -93,6 +172,7 @@ impl Connection {
/// ///
/// There can only be a single profiler defined for each database /// There can only be a single profiler defined for each database
/// connection. Setting a new profiler clears the old one. /// connection. Setting a new profiler clears the old one.
#[deprecated(since = "0.33.0", note = "use trace_v2 instead")]
pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) { pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
unsafe extern "C" fn profile_callback( unsafe extern "C" fn profile_callback(
p_arg: *mut c_void, p_arg: *mut c_void,
@@ -100,14 +180,9 @@ impl Connection {
nanoseconds: u64, nanoseconds: u64,
) { ) {
let profile_fn: fn(&str, Duration) = mem::transmute(p_arg); let profile_fn: fn(&str, Duration) = mem::transmute(p_arg);
let c_slice = CStr::from_ptr(z_sql).to_bytes(); let s = CStr::from_ptr(z_sql).to_string_lossy();
let s = String::from_utf8_lossy(c_slice);
const NANOS_PER_SEC: u64 = 1_000_000_000;
let duration = Duration::new( let duration = Duration::from_nanos(nanoseconds);
nanoseconds / NANOS_PER_SEC,
(nanoseconds % NANOS_PER_SEC) as u32,
);
drop(catch_unwind(|| profile_fn(&s, duration))); drop(catch_unwind(|| profile_fn(&s, duration)));
} }
@@ -120,22 +195,68 @@ impl Connection {
}; };
} }
// TODO sqlite3_trace_v2 (https://sqlite.org/c3ref/trace_v2.html) // 3.14.0, #977 /// Register or clear a trace callback function
pub fn trace_v2(&self, mask: TraceEventCodes, trace_fn: Option<fn(TraceEvent<'_>)>) {
unsafe extern "C" fn trace_callback(
evt: c_uint,
ctx: *mut c_void,
p: *mut c_void,
x: *mut c_void,
) -> c_int {
let trace_fn: fn(TraceEvent<'_>) = mem::transmute(ctx);
drop(catch_unwind(|| match evt {
ffi::SQLITE_TRACE_STMT => {
let str = CStr::from_ptr(x as *const c_char).to_string_lossy();
trace_fn(TraceEvent::Stmt(
StmtRef::new(p as *mut ffi::sqlite3_stmt),
&str,
))
}
ffi::SQLITE_TRACE_PROFILE => {
let ns = *(x as *const i64);
trace_fn(TraceEvent::Profile(
StmtRef::new(p as *mut ffi::sqlite3_stmt),
Duration::from_nanos(u64::try_from(ns).unwrap_or_default()),
))
}
ffi::SQLITE_TRACE_ROW => {
trace_fn(TraceEvent::Row(StmtRef::new(p as *mut ffi::sqlite3_stmt)))
}
ffi::SQLITE_TRACE_CLOSE => trace_fn(TraceEvent::Close(ConnRef {
ptr: p as *mut ffi::sqlite3,
phantom: PhantomData,
})),
_ => {}
}));
// The integer return value from the callback is currently ignored, though this may change in future releases.
// Callback implementations should return zero to ensure future compatibility.
ffi::SQLITE_OK
}
let c = self.db.borrow_mut();
if let Some(f) = trace_fn {
unsafe {
ffi::sqlite3_trace_v2(c.db(), mask.bits(), Some(trace_callback), f as *mut c_void);
}
} else {
unsafe {
ffi::sqlite3_trace_v2(c.db(), 0, None, ptr::null_mut());
}
}
}
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use lazy_static::lazy_static; use std::sync::{LazyLock, Mutex};
use std::sync::Mutex;
use std::time::Duration; use std::time::Duration;
use crate::{Connection, Result}; use crate::{Connection, Result};
#[test] #[test]
#[allow(deprecated)]
fn test_trace() -> Result<()> { fn test_trace() -> Result<()> {
lazy_static! { static TRACED_STMTS: LazyLock<Mutex<Vec<String>>> =
static ref TRACED_STMTS: Mutex<Vec<String>> = Mutex::new(Vec::new()); LazyLock::new(|| Mutex::new(Vec::new()));
}
fn tracer(s: &str) { fn tracer(s: &str) {
let mut traced_stmts = TRACED_STMTS.lock().unwrap(); let mut traced_stmts = TRACED_STMTS.lock().unwrap();
traced_stmts.push(s.to_owned()); traced_stmts.push(s.to_owned());
@@ -161,10 +282,10 @@ mod test {
} }
#[test] #[test]
#[allow(deprecated)]
fn test_profile() -> Result<()> { fn test_profile() -> Result<()> {
lazy_static! { static PROFILED: LazyLock<Mutex<Vec<(String, Duration)>>> =
static ref PROFILED: Mutex<Vec<(String, Duration)>> = Mutex::new(Vec::new()); LazyLock::new(|| Mutex::new(Vec::new()));
}
fn profiler(s: &str, d: Duration) { fn profiler(s: &str, d: Duration) {
let mut profiled = PROFILED.lock().unwrap(); let mut profiled = PROFILED.lock().unwrap();
profiled.push((s.to_owned(), d)); profiled.push((s.to_owned(), d));
@@ -181,4 +302,39 @@ mod test {
assert_eq!(profiled[0].0, "PRAGMA application_id = 1"); assert_eq!(profiled[0].0, "PRAGMA application_id = 1");
Ok(()) Ok(())
} }
#[test]
pub fn trace_v2() -> Result<()> {
use super::{TraceEvent, TraceEventCodes};
use std::borrow::Borrow;
use std::cmp::Ordering;
let db = Connection::open_in_memory()?;
db.trace_v2(
TraceEventCodes::all(),
Some(|e| match e {
TraceEvent::Stmt(s, sql) => {
assert_eq!(s.sql(), sql);
}
TraceEvent::Profile(s, d) => {
assert_eq!(s.get_status(crate::StatementStatus::Sort), 0);
assert_eq!(d.cmp(&Duration::ZERO), Ordering::Greater)
}
TraceEvent::Row(s) => {
assert_eq!(s.expanded_sql().as_deref(), Some(s.sql().borrow()));
}
TraceEvent::Close(db) => {
assert!(db.is_autocommit());
assert!(db.db_filename().is_none());
}
}),
);
db.one_column::<u32>("PRAGMA user_version")?;
drop(db);
let db = Connection::open_in_memory()?;
db.trace_v2(TraceEventCodes::empty(), None);
Ok(())
}
} }

View File

@@ -100,7 +100,7 @@ impl Transaction<'_> {
/// transactions. /// transactions.
/// ///
/// Even though we don't mutate the connection, we take a `&mut Connection` /// Even though we don't mutate the connection, we take a `&mut Connection`
/// so as to prevent nested transactions on the same connection. For cases /// to prevent nested transactions on the same connection. For cases
/// where this is unacceptable, [`Transaction::new_unchecked`] is available. /// where this is unacceptable, [`Transaction::new_unchecked`] is available.
#[inline] #[inline]
pub fn new(conn: &mut Connection, behavior: TransactionBehavior) -> Result<Transaction<'_>> { pub fn new(conn: &mut Connection, behavior: TransactionBehavior) -> Result<Transaction<'_>> {
@@ -238,7 +238,7 @@ impl Deref for Transaction<'_> {
} }
} }
#[allow(unused_must_use)] #[expect(unused_must_use)]
impl Drop for Transaction<'_> { impl Drop for Transaction<'_> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
@@ -363,7 +363,7 @@ impl Deref for Savepoint<'_> {
} }
} }
#[allow(unused_must_use)] #[expect(unused_must_use)]
impl Drop for Savepoint<'_> { impl Drop for Savepoint<'_> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
@@ -377,11 +377,11 @@ impl Drop for Savepoint<'_> {
#[cfg(feature = "modern_sqlite")] // 3.37.0 #[cfg(feature = "modern_sqlite")] // 3.37.0
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
pub enum TransactionState { pub enum TransactionState {
/// Equivalent to SQLITE_TXN_NONE /// Equivalent to `SQLITE_TXN_NONE`
None, None,
/// Equivalent to SQLITE_TXN_READ /// Equivalent to `SQLITE_TXN_READ`
Read, Read,
/// Equivalent to SQLITE_TXN_WRITE /// Equivalent to `SQLITE_TXN_WRITE`
Write, Write,
} }
@@ -414,7 +414,7 @@ impl Connection {
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
#[inline] #[inline]
pub fn transaction(&mut self) -> Result<Transaction<'_>> { pub fn transaction(&mut self) -> Result<Transaction<'_>> {
Transaction::new(self, TransactionBehavior::Deferred) Transaction::new(self, self.transaction_behavior)
} }
/// Begin a new transaction with a specified behavior. /// Begin a new transaction with a specified behavior.
@@ -464,7 +464,7 @@ impl Connection {
/// Will return `Err` if the underlying SQLite call fails. The specific /// Will return `Err` if the underlying SQLite call fails. The specific
/// error returned if transactions are nested is currently unspecified. /// error returned if transactions are nested is currently unspecified.
pub fn unchecked_transaction(&self) -> Result<Transaction<'_>> { pub fn unchecked_transaction(&self) -> Result<Transaction<'_>> {
Transaction::new_unchecked(self, TransactionBehavior::Deferred) Transaction::new_unchecked(self, self.transaction_behavior)
} }
/// Begin a new savepoint with the default behavior (DEFERRED). /// Begin a new savepoint with the default behavior (DEFERRED).
@@ -518,6 +518,34 @@ impl Connection {
) -> Result<TransactionState> { ) -> Result<TransactionState> {
self.db.borrow().txn_state(db_name) self.db.borrow().txn_state(db_name)
} }
/// Set the default transaction behavior for the connection.
///
/// ## Note
///
/// This will only apply to transactions initiated by [`transaction`](Connection::transaction)
/// or [`unchecked_transaction`](Connection::unchecked_transaction).
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result, TransactionBehavior};
/// # fn do_queries_part_1(_conn: &Connection) -> Result<()> { Ok(()) }
/// # fn do_queries_part_2(_conn: &Connection) -> Result<()> { Ok(()) }
/// fn perform_queries(conn: &mut Connection) -> Result<()> {
/// conn.set_transaction_behavior(TransactionBehavior::Immediate);
///
/// let tx = conn.transaction()?;
///
/// do_queries_part_1(&tx)?; // tx causes rollback if this fails
/// do_queries_part_2(&tx)?; // tx causes rollback if this fails
///
/// tx.commit()
/// }
/// ```
pub fn set_transaction_behavior(&mut self, behavior: TransactionBehavior) {
self.transaction_behavior = behavior;
}
} }
#[cfg(test)] #[cfg(test)]
@@ -624,12 +652,12 @@ mod test {
let mut sp1 = tx.savepoint()?; let mut sp1 = tx.savepoint()?;
sp1.execute_batch("INSERT INTO foo VALUES(2)")?; sp1.execute_batch("INSERT INTO foo VALUES(2)")?;
assert_current_sum(3, &sp1)?; assert_current_sum(3, &sp1)?;
// will rollback sp1 // will roll back sp1
{ {
let mut sp2 = sp1.savepoint()?; let mut sp2 = sp1.savepoint()?;
sp2.execute_batch("INSERT INTO foo VALUES(4)")?; sp2.execute_batch("INSERT INTO foo VALUES(4)")?;
assert_current_sum(7, &sp2)?; assert_current_sum(7, &sp2)?;
// will rollback sp2 // will roll back sp2
{ {
let sp3 = sp2.savepoint()?; let sp3 = sp2.savepoint()?;
sp3.execute_batch("INSERT INTO foo VALUES(8)")?; sp3.execute_batch("INSERT INTO foo VALUES(8)")?;
@@ -775,4 +803,27 @@ mod test {
db.execute_batch("ROLLBACK")?; db.execute_batch("ROLLBACK")?;
Ok(()) Ok(())
} }
#[test]
#[cfg(feature = "modern_sqlite")]
fn auto_commit() -> Result<()> {
use super::TransactionState;
let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE t(i UNIQUE);")?;
assert!(db.is_autocommit());
let mut stmt = db.prepare("SELECT name FROM sqlite_master")?;
assert_eq!(TransactionState::None, db.transaction_state(None)?);
{
let mut rows = stmt.query([])?;
assert!(rows.next()?.is_some()); // start reading
assert_eq!(TransactionState::Read, db.transaction_state(None)?);
db.execute("INSERT INTO t VALUES (1)", [])?; // auto-commit
assert_eq!(TransactionState::Read, db.transaction_state(None)?);
assert!(rows.next()?.is_some()); // still reading
assert_eq!(TransactionState::Read, db.transaction_state(None)?);
assert!(rows.next()?.is_none()); // end
assert_eq!(TransactionState::None, db.transaction_state(None)?);
}
Ok(())
}
} }

View File

@@ -20,7 +20,7 @@ impl FromSql for NaiveDate {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value value
.as_str() .as_str()
.and_then(|s| match NaiveDate::parse_from_str(s, "%F") { .and_then(|s| match Self::parse_from_str(s, "%F") {
Ok(dt) => Ok(dt), Ok(dt) => Ok(dt),
Err(err) => Err(FromSqlError::Other(Box::new(err))), Err(err) => Err(FromSqlError::Other(Box::new(err))),
}) })
@@ -45,7 +45,7 @@ impl FromSql for NaiveTime {
8 => "%T", 8 => "%T",
_ => "%T%.f", _ => "%T%.f",
}; };
match NaiveTime::parse_from_str(s, fmt) { match Self::parse_from_str(s, fmt) {
Ok(dt) => Ok(dt), Ok(dt) => Ok(dt),
Err(err) => Err(FromSqlError::Other(Box::new(err))), Err(err) => Err(FromSqlError::Other(Box::new(err))),
} }
@@ -75,7 +75,7 @@ impl FromSql for NaiveDateTime {
"%F %T%.f" "%F %T%.f"
}; };
match NaiveDateTime::parse_from_str(s, fmt) { match Self::parse_from_str(s, fmt) {
Ok(dt) => Ok(dt), Ok(dt) => Ok(dt),
Err(err) => Err(FromSqlError::Other(Box::new(err))), Err(err) => Err(FromSqlError::Other(Box::new(err))),
} }
@@ -238,7 +238,7 @@ mod test {
assert_eq!(utc, v2); assert_eq!(utc, v2);
let v3: DateTime<Utc> = db.one_column("SELECT '2016-02-23 23:56:04'")?; let v3: DateTime<Utc> = db.one_column("SELECT '2016-02-23 23:56:04'")?;
assert_eq!(utc - Duration::milliseconds(789), v3); assert_eq!(utc - Duration::try_milliseconds(789).unwrap(), v3);
let v4: DateTime<Utc> = db.one_column("SELECT '2016-02-23 23:56:04.789+00:00'")?; let v4: DateTime<Utc> = db.one_column("SELECT '2016-02-23 23:56:04.789+00:00'")?;
assert_eq!(utc, v4); assert_eq!(utc, v4);
@@ -285,13 +285,13 @@ mod test {
fn test_sqlite_functions() -> Result<()> { fn test_sqlite_functions() -> Result<()> {
let db = checked_memory_handle()?; let db = checked_memory_handle()?;
let result: Result<NaiveTime> = db.one_column("SELECT CURRENT_TIME"); let result: Result<NaiveTime> = db.one_column("SELECT CURRENT_TIME");
result.unwrap(); result?;
let result: Result<NaiveDate> = db.one_column("SELECT CURRENT_DATE"); let result: Result<NaiveDate> = db.one_column("SELECT CURRENT_DATE");
result.unwrap(); result?;
let result: Result<NaiveDateTime> = db.one_column("SELECT CURRENT_TIMESTAMP"); let result: Result<NaiveDateTime> = db.one_column("SELECT CURRENT_TIMESTAMP");
result.unwrap(); result?;
let result: Result<DateTime<Utc>> = db.one_column("SELECT CURRENT_TIMESTAMP"); let result: Result<DateTime<Utc>> = db.one_column("SELECT CURRENT_TIMESTAMP");
result.unwrap(); result?;
Ok(()) Ok(())
} }
@@ -299,7 +299,7 @@ mod test {
fn test_naive_date_time_param() -> Result<()> { fn test_naive_date_time_param() -> Result<()> {
let db = checked_memory_handle()?; let db = checked_memory_handle()?;
let result: Result<bool> = db.query_row("SELECT 1 WHERE ?1 BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [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(); result?;
Ok(()) Ok(())
} }
@@ -307,7 +307,7 @@ mod test {
fn test_date_time_param() -> Result<()> { fn test_date_time_param() -> Result<()> {
let db = checked_memory_handle()?; let db = checked_memory_handle()?;
let result: Result<bool> = db.query_row("SELECT 1 WHERE ?1 BETWEEN datetime('now', '-1 minute') AND datetime('now', '+1 minute')", [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(); result?;
Ok(()) Ok(())
} }

View File

@@ -1,5 +1,5 @@
use super::{Value, ValueRef}; use super::{Value, ValueRef};
use std::convert::TryInto; use std::borrow::Cow;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
@@ -29,16 +29,16 @@ pub enum FromSqlError {
} }
impl PartialEq for FromSqlError { impl PartialEq for FromSqlError {
fn eq(&self, other: &FromSqlError) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(FromSqlError::InvalidType, FromSqlError::InvalidType) => true, (Self::InvalidType, Self::InvalidType) => true,
(FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2, (Self::OutOfRange(n1), Self::OutOfRange(n2)) => n1 == n2,
( (
FromSqlError::InvalidBlobSize { Self::InvalidBlobSize {
expected_size: es1, expected_size: es1,
blob_size: bs1, blob_size: bs1,
}, },
FromSqlError::InvalidBlobSize { Self::InvalidBlobSize {
expected_size: es2, expected_size: es2,
blob_size: bs2, blob_size: bs2,
}, },
@@ -51,9 +51,9 @@ impl PartialEq for FromSqlError {
impl fmt::Display for FromSqlError { impl fmt::Display for FromSqlError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {
FromSqlError::InvalidType => write!(f, "Invalid type"), Self::InvalidType => write!(f, "Invalid type"),
FromSqlError::OutOfRange(i) => write!(f, "Value {i} out of range"), Self::OutOfRange(i) => write!(f, "Value {i} out of range"),
FromSqlError::InvalidBlobSize { Self::InvalidBlobSize {
expected_size, expected_size,
blob_size, blob_size,
} => { } => {
@@ -62,14 +62,14 @@ impl fmt::Display for FromSqlError {
"Cannot read {expected_size} byte value out of {blob_size} byte blob" "Cannot read {expected_size} byte value out of {blob_size} byte blob"
) )
} }
FromSqlError::Other(ref err) => err.fmt(f), Self::Other(ref err) => err.fmt(f),
} }
} }
} }
impl Error for FromSqlError { impl Error for FromSqlError {
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
if let FromSqlError::Other(ref err) = self { if let Self::Other(ref err) = self {
Some(&**err) Some(&**err)
} else { } else {
None None
@@ -145,8 +145,8 @@ impl FromSql for f32 {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value { match value {
ValueRef::Integer(i) => Ok(i as f32), ValueRef::Integer(i) => Ok(i as Self),
ValueRef::Real(f) => Ok(f as f32), ValueRef::Real(f) => Ok(f as Self),
_ => Err(FromSqlError::InvalidType), _ => Err(FromSqlError::InvalidType),
} }
} }
@@ -156,7 +156,7 @@ impl FromSql for f64 {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value { match value {
ValueRef::Integer(i) => Ok(i as f64), ValueRef::Integer(i) => Ok(i as Self),
ValueRef::Real(f) => Ok(f), ValueRef::Real(f) => Ok(f),
_ => Err(FromSqlError::InvalidType), _ => Err(FromSqlError::InvalidType),
} }
@@ -205,6 +205,27 @@ impl FromSql for Vec<u8> {
} }
} }
impl FromSql for Box<[u8]> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_blob().map(Box::<[u8]>::from)
}
}
impl FromSql for std::rc::Rc<[u8]> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_blob().map(std::rc::Rc::<[u8]>::from)
}
}
impl FromSql for std::sync::Arc<[u8]> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_blob().map(std::sync::Arc::<[u8]>::from)
}
}
impl<const N: usize> FromSql for [u8; N] { impl<const N: usize> FromSql for [u8; N] {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
@@ -222,7 +243,7 @@ impl FromSql for i128 {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let bytes = <[u8; 16]>::column_result(value)?; let bytes = <[u8; 16]>::column_result(value)?;
Ok(i128::from_be_bytes(bytes) ^ (1_i128 << 127)) Ok(Self::from_be_bytes(bytes) ^ (1_i128 << 127))
} }
} }
@@ -232,7 +253,7 @@ impl FromSql for uuid::Uuid {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let bytes = <[u8; 16]>::column_result(value)?; let bytes = <[u8; 16]>::column_result(value)?;
Ok(uuid::Uuid::from_u128(u128::from_be_bytes(bytes))) Ok(Self::from_u128(u128::from_be_bytes(bytes)))
} }
} }
@@ -246,6 +267,17 @@ impl<T: FromSql> FromSql for Option<T> {
} }
} }
impl<T: ?Sized> FromSql for Cow<'_, T>
where
T: ToOwned,
T::Owned: FromSql,
{
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
<T::Owned>::column_result(value).map(Cow::Owned)
}
}
impl FromSql for Value { impl FromSql for Value {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
@@ -257,6 +289,9 @@ impl FromSql for Value {
mod test { mod test {
use super::FromSql; use super::FromSql;
use crate::{Connection, Error, Result}; use crate::{Connection, Error, Result};
use std::borrow::Cow;
use std::rc::Rc;
use std::sync::Arc;
#[test] #[test]
fn test_integral_ranges() -> Result<()> { fn test_integral_ranges() -> Result<()> {
@@ -363,4 +398,62 @@ mod test {
Ok(()) Ok(())
} }
#[test]
fn test_cow() -> Result<()> {
let db = Connection::open_in_memory()?;
assert_eq!(
db.query_row("SELECT 'this is a string'", [], |r| r
.get::<_, Cow<'_, str>>(0)),
Ok(Cow::Borrowed("this is a string")),
);
assert_eq!(
db.query_row("SELECT x'09ab20fdee87'", [], |r| r
.get::<_, Cow<'_, [u8]>>(0)),
Ok(Cow::Owned(vec![0x09, 0xab, 0x20, 0xfd, 0xee, 0x87])),
);
assert_eq!(
db.query_row("SELECT 24.5", [], |r| r.get::<_, Cow<'_, f32>>(0),),
Ok(Cow::Borrowed(&24.5)),
);
Ok(())
}
#[test]
fn test_heap_slice() -> Result<()> {
let db = Connection::open_in_memory()?;
assert_eq!(
db.query_row("SELECT 'Some string slice!'", [], |r| r
.get::<_, Rc<str>>(0)),
Ok(Rc::from("Some string slice!")),
);
assert_eq!(
db.query_row("SELECT x'012366779988fedc'", [], |r| r
.get::<_, Rc<[u8]>>(0)),
Ok(Rc::from(b"\x01\x23\x66\x77\x99\x88\xfe\xdc".as_slice())),
);
assert_eq!(
db.query_row(
"SELECT x'6120737472696e672043414e206265206120626c6f62'",
[],
|r| r.get::<_, Box<[u8]>>(0)
),
Ok(b"a string CAN be a blob".to_vec().into_boxed_slice()),
);
assert_eq!(
db.query_row("SELECT 'This is inside an Arc.'", [], |r| r
.get::<_, Arc<str>>(0)),
Ok(Arc::from("This is inside an Arc.")),
);
assert_eq!(
db.query_row("SELECT x'afd374'", [], |r| r.get::<_, Arc<[u8]>>(0),),
Ok(Arc::from(b"\xaf\xd3\x74".as_slice())),
);
Ok(())
}
} }

View File

@@ -0,0 +1,137 @@
//! Convert some `jiff` types.
use jiff::civil::{Date, DateTime, Time};
use std::str::FromStr;
use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
use crate::Result;
/// Gregorian calendar date => "YYYY-MM-DD"
impl ToSql for Date {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let s = self.to_string();
Ok(ToSqlOutput::from(s))
}
}
/// "YYYY-MM-DD" => Gregorian calendar date.
impl FromSql for Date {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| match Self::from_str(s) {
Ok(d) => Ok(d),
Err(err) => Err(FromSqlError::Other(Box::new(err))),
})
}
}
/// time => "HH:MM:SS.SSS"
impl ToSql for Time {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let date_str = self.to_string();
Ok(ToSqlOutput::from(date_str))
}
}
/// "HH:MM:SS.SSS" => time.
impl FromSql for Time {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| match Self::from_str(s) {
Ok(t) => Ok(t),
Err(err) => Err(FromSqlError::Other(Box::new(err))),
})
}
}
/// Gregorian datetime => "YYYY-MM-DDTHH:MM:SS.SSS"
impl ToSql for DateTime {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let s = self.to_string();
Ok(ToSqlOutput::from(s))
}
}
/// "YYYY-MM-DDTHH:MM:SS.SSS" => Gregorian datetime.
impl FromSql for DateTime {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| match Self::from_str(s) {
Ok(dt) => Ok(dt),
Err(err) => Err(FromSqlError::Other(Box::new(err))),
})
}
}
#[cfg(test)]
mod test {
use crate::{Connection, Result};
use jiff::civil::{Date, DateTime, Time};
fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (t TEXT, b BLOB)")?;
Ok(db)
}
#[test]
fn test_date() -> Result<()> {
let db = checked_memory_handle()?;
let date = Date::constant(2016, 2, 23);
db.execute("INSERT INTO foo (t) VALUES (?1)", [date])?;
let s: String = db.one_column("SELECT t FROM foo")?;
assert_eq!("2016-02-23", s);
let t: Date = db.one_column("SELECT t FROM foo")?;
assert_eq!(date, t);
db.execute("UPDATE foo set b = date(t)", [])?;
let t: Date = db.one_column("SELECT b FROM foo")?;
assert_eq!(date, t);
let r: Result<Date> = db.one_column("SELECT '2023-02-29'");
assert!(r.is_err());
Ok(())
}
#[test]
fn test_time() -> Result<()> {
let db = checked_memory_handle()?;
let time = Time::constant(23, 56, 4, 0);
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);
let v: Time = db.one_column("SELECT t FROM foo")?;
assert_eq!(time, v);
db.execute("UPDATE foo set b = time(t)", [])?;
let v: Time = db.one_column("SELECT b FROM foo")?;
assert_eq!(time, v);
let r: Result<Time> = db.one_column("SELECT '25:22:45'");
assert!(r.is_err());
Ok(())
}
#[test]
fn test_date_time() -> Result<()> {
let db = checked_memory_handle()?;
let dt = DateTime::constant(2016, 2, 23, 23, 56, 4, 0);
db.execute("INSERT INTO foo (t) VALUES (?1)", [dt])?;
let s: String = db.one_column("SELECT t FROM foo")?;
assert_eq!("2016-02-23T23:56:04", s);
let v: DateTime = db.one_column("SELECT t FROM foo")?;
assert_eq!(dt, v);
db.execute("UPDATE foo set b = datetime(t)", [])?;
let v: DateTime = db.one_column("SELECT b FROM foo")?;
assert_eq!(dt, v);
let r: Result<DateTime> = db.one_column("SELECT '2023-02-29T00:00:00'");
assert!(r.is_err());
Ok(())
}
}

View File

@@ -81,6 +81,9 @@ use std::fmt;
#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))] #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
mod chrono; mod chrono;
mod from_sql; mod from_sql;
#[cfg(feature = "jiff")]
#[cfg_attr(docsrs, doc(cfg(feature = "jiff")))]
mod jiff;
#[cfg(feature = "serde_json")] #[cfg(feature = "serde_json")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))] #[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))]
mod serde_json; mod serde_json;
@@ -128,11 +131,11 @@ pub enum Type {
impl fmt::Display for Type { impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {
Type::Null => f.pad("Null"), Self::Null => f.pad("Null"),
Type::Integer => f.pad("Integer"), Self::Integer => f.pad("Integer"),
Type::Real => f.pad("Real"), Self::Real => f.pad("Real"),
Type::Text => f.pad("Text"), Self::Text => f.pad("Text"),
Type::Blob => f.pad("Blob"), Self::Blob => f.pad("Blob"),
} }
} }
} }
@@ -239,7 +242,7 @@ mod test {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)] #[expect(clippy::cognitive_complexity)]
fn test_mismatched_types() -> Result<()> { fn test_mismatched_types() -> Result<()> {
fn is_invalid_column_type(err: Error) -> bool { fn is_invalid_column_type(err: Error) -> bool {
matches!(err, Error::InvalidColumnType(..)) matches!(err, Error::InvalidColumnType(..))
@@ -385,9 +388,8 @@ mod test {
} }
#[test] #[test]
#[expect(clippy::float_cmp)]
fn test_numeric_conversions() -> Result<()> { fn test_numeric_conversions() -> Result<()> {
#![allow(clippy::float_cmp)]
// Test what happens when we store an f32 and retrieve an i32 etc. // Test what happens when we store an f32 and retrieve an i32 etc.
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (x)")?; db.execute_batch("CREATE TABLE foo (x)")?;

View File

@@ -18,9 +18,9 @@ impl ToSql for Value {
#[inline] #[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> { fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
match self { match self {
Value::Null => Ok(ToSqlOutput::Borrowed(ValueRef::Null)), Self::Null => Ok(ToSqlOutput::Borrowed(ValueRef::Null)),
Value::Number(n) if n.is_i64() => Ok(ToSqlOutput::from(n.as_i64().unwrap())), Self::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())), Self::Number(n) if n.is_f64() => Ok(ToSqlOutput::from(n.as_f64().unwrap())),
_ => serde_json::to_string(self) _ => serde_json::to_string(self)
.map(ToSqlOutput::from) .map(ToSqlOutput::from)
.map_err(|err| Error::ToSqlConversionFailure(err.into())), .map_err(|err| Error::ToSqlConversionFailure(err.into())),
@@ -47,14 +47,14 @@ impl FromSql for Value {
match value { match value {
ValueRef::Text(s) => serde_json::from_slice(s), // KO for b"text" ValueRef::Text(s) => serde_json::from_slice(s), // KO for b"text"
ValueRef::Blob(b) => serde_json::from_slice(b), ValueRef::Blob(b) => serde_json::from_slice(b),
ValueRef::Integer(i) => Ok(Value::Number(Number::from(i))), ValueRef::Integer(i) => Ok(Self::Number(Number::from(i))),
ValueRef::Real(f) => { ValueRef::Real(f) => {
match Number::from_f64(f) { match Number::from_f64(f) {
Some(n) => Ok(Value::Number(n)), Some(n) => Ok(Self::Number(n)),
_ => return Err(FromSqlError::InvalidType), // FIXME _ => return Err(FromSqlError::InvalidType), // FIXME
} }
} }
ValueRef::Null => Ok(Value::Null), ValueRef::Null => Ok(Self::Null),
} }
.map_err(|err| FromSqlError::Other(Box::new(err))) .map_err(|err| FromSqlError::Other(Box::new(err)))
} }

View File

@@ -1,12 +1,13 @@
//! Convert formats 1-10 in [Time Values](https://sqlite.org/lang_datefunc.html#time_values) to time types. //! Convert formats 1-10 in [Time Values](https://sqlite.org/lang_datefunc.html#time_values) to time types.
//! [`ToSql`] and [`FromSql`] implementation for [`time::OffsetDateTime`]. //! [`ToSql`] and [`FromSql`] implementation for [`OffsetDateTime`].
//! [`ToSql`] and [`FromSql`] implementation for [`time::PrimitiveDateTime`]. //! [`ToSql`] and [`FromSql`] implementation for [`PrimitiveDateTime`].
//! [`ToSql`] and [`FromSql`] implementation for [`time::Date`]. //! [`ToSql`] and [`FromSql`] implementation for [`Date`].
//! [`ToSql`] and [`FromSql`] implementation for [`time::Time`]. //! [`ToSql`] and [`FromSql`] implementation for [`Time`].
//! Time Strings in: //! Time Strings in:
//! - Format 2: "YYYY-MM-DD HH:MM" //! - Format 2: "YYYY-MM-DD HH:MM"
//! - Format 5: "YYYY-MM-DDTHH:MM" //! - Format 5: "YYYY-MM-DDTHH:MM"
//! - Format 8: "HH:MM" //! - Format 8: "HH:MM"
//!
//! without an explicit second value will assume 0 seconds. //! without an explicit second value will assume 0 seconds.
//! Time String that contain an optional timezone without an explicit date are unsupported. //! Time String that contain an optional timezone without an explicit date are unsupported.
//! All other assumptions described in [Time Values](https://sqlite.org/lang_datefunc.html#time_values) section are unsupported. //! All other assumptions described in [Time Values](https://sqlite.org/lang_datefunc.html#time_values) section are unsupported.
@@ -50,7 +51,7 @@ const LEGACY_DATE_TIME_FORMAT: &[FormatItem<'_>] = format_description!(
"[year]-[month]-[day] [hour]:[minute]:[second]:[subsecond] [offset_hour sign:mandatory]:[offset_minute]" "[year]-[month]-[day] [hour]:[minute]:[second]:[subsecond] [offset_hour sign:mandatory]:[offset_minute]"
); );
/// OffsetDatetime => RFC3339 format ("YYYY-MM-DD HH:MM:SS.SSS[+-]HH:MM") /// `OffsetDatetime` => RFC3339 format ("YYYY-MM-DD HH:MM:SS.SSS[+-]HH:MM")
impl ToSql for OffsetDateTime { impl ToSql for OffsetDateTime {
#[inline] #[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> { fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
@@ -68,12 +69,12 @@ impl FromSql for OffsetDateTime {
value.as_str().and_then(|s| { value.as_str().and_then(|s| {
if let Some(b' ') = s.as_bytes().get(23) { if let Some(b' ') = s.as_bytes().get(23) {
// legacy // legacy
return OffsetDateTime::parse(s, &LEGACY_DATE_TIME_FORMAT) return Self::parse(s, &LEGACY_DATE_TIME_FORMAT)
.map_err(|err| FromSqlError::Other(Box::new(err))); .map_err(|err| FromSqlError::Other(Box::new(err)));
} }
if s[8..].contains('+') || s[8..].contains('-') { if s[8..].contains('+') || s[8..].contains('-') {
// Formats 2-7 with timezone // Formats 2-7 with timezone
return OffsetDateTime::parse(s, &OFFSET_DATE_TIME_FORMAT) return Self::parse(s, &OFFSET_DATE_TIME_FORMAT)
.map_err(|err| FromSqlError::Other(Box::new(err))); .map_err(|err| FromSqlError::Other(Box::new(err)));
} }
// Formats 2-7 without timezone // Formats 2-7 without timezone
@@ -100,7 +101,7 @@ impl FromSql for Date {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| { value.as_str().and_then(|s| {
Date::parse(s, &DATE_FORMAT).map_err(|err| FromSqlError::Other(err.into())) Self::parse(s, &DATE_FORMAT).map_err(|err| FromSqlError::Other(err.into()))
}) })
} }
} }
@@ -121,7 +122,7 @@ impl FromSql for Time {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| { value.as_str().and_then(|s| {
Time::parse(s, &TIME_FORMAT).map_err(|err| FromSqlError::Other(err.into())) Self::parse(s, &TIME_FORMAT).map_err(|err| FromSqlError::Other(err.into()))
}) })
} }
} }
@@ -148,7 +149,7 @@ impl FromSql for PrimitiveDateTime {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().and_then(|s| { value.as_str().and_then(|s| {
PrimitiveDateTime::parse(s, &PRIMITIVE_DATE_TIME_FORMAT) Self::parse(s, &PRIMITIVE_DATE_TIME_FORMAT)
.map_err(|err| FromSqlError::Other(err.into())) .map_err(|err| FromSqlError::Other(err.into()))
}) })
} }
@@ -361,12 +362,10 @@ mod test {
#[test] #[test]
fn test_sqlite_functions() -> Result<()> { fn test_sqlite_functions() -> Result<()> {
let db = checked_memory_handle()?; let db = checked_memory_handle()?;
db.one_column::<Time>("SELECT CURRENT_TIME").unwrap(); db.one_column::<Time>("SELECT CURRENT_TIME")?;
db.one_column::<Date>("SELECT CURRENT_DATE").unwrap(); db.one_column::<Date>("SELECT CURRENT_DATE")?;
db.one_column::<PrimitiveDateTime>("SELECT CURRENT_TIMESTAMP") db.one_column::<PrimitiveDateTime>("SELECT CURRENT_TIMESTAMP")?;
.unwrap(); db.one_column::<OffsetDateTime>("SELECT CURRENT_TIMESTAMP")?;
db.one_column::<OffsetDateTime>("SELECT CURRENT_TIMESTAMP")
.unwrap();
Ok(()) Ok(())
} }
@@ -379,7 +378,7 @@ mod test {
[now], [now],
|r| r.get(0), |r| r.get(0),
); );
result.unwrap(); result?;
Ok(()) Ok(())
} }
@@ -392,7 +391,7 @@ mod test {
[now], [now],
|r| r.get(0), |r| r.get(0),
); );
result.unwrap(); result?;
Ok(()) Ok(())
} }
@@ -408,7 +407,7 @@ mod test {
[now], [now],
|r| r.get(0), |r| r.get(0),
); );
result.unwrap(); result?;
Ok(()) Ok(())
} }
@@ -420,7 +419,7 @@ mod test {
[OffsetDateTime::now_utc()], [OffsetDateTime::now_utc()],
|r| r.get(0), |r| r.get(0),
); );
result.unwrap(); result?;
Ok(()) Ok(())
} }
} }

View File

@@ -3,7 +3,6 @@ use super::{Null, Value, ValueRef};
use crate::vtab::array::Array; use crate::vtab::array::Array;
use crate::{Error, Result}; use crate::{Error, Result};
use std::borrow::Cow; use std::borrow::Cow;
use std::convert::TryFrom;
/// `ToSqlOutput` represents the possible output types for implementers of the /// `ToSqlOutput` represents the possible output types for implementers of the
/// [`ToSql`] trait. /// [`ToSql`] trait.
@@ -311,10 +310,24 @@ impl<T: ToSql> ToSql for Option<T> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::ToSql; use super::{ToSql, ToSqlOutput};
use crate::{types::Value, types::ValueRef, Result};
fn is_to_sql<T: ToSql>() {} fn is_to_sql<T: ToSql>() {}
#[test]
fn to_sql() -> Result<()> {
assert_eq!(
ToSqlOutput::Borrowed(ValueRef::Null).to_sql()?,
ToSqlOutput::Borrowed(ValueRef::Null)
);
assert_eq!(
ToSqlOutput::Owned(Value::Null).to_sql()?,
ToSqlOutput::Borrowed(ValueRef::Null)
);
Ok(())
}
#[test] #[test]
fn test_integral_types() { fn test_integral_types() {
is_to_sql::<i8>(); is_to_sql::<i8>();
@@ -432,7 +445,7 @@ mod test {
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[test] #[test]
fn test_i128() -> crate::Result<()> { fn test_i128() -> Result<()> {
use crate::Connection; use crate::Connection;
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (i128 BLOB, desc TEXT)")?; db.execute_batch("CREATE TABLE foo (i128 BLOB, desc TEXT)")?;
@@ -471,7 +484,7 @@ mod test {
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[test] #[test]
fn test_non_zero_i128() -> crate::Result<()> { fn test_non_zero_i128() -> Result<()> {
use std::num::NonZeroI128; use std::num::NonZeroI128;
macro_rules! nz { macro_rules! nz {
($x:expr) => { ($x:expr) => {
@@ -519,7 +532,7 @@ mod test {
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[test] #[test]
fn test_uuid() -> crate::Result<()> { fn test_uuid() -> Result<()> {
use crate::{params, Connection}; use crate::{params, Connection};
use uuid::Uuid; use uuid::Uuid;

View File

@@ -1,4 +1,4 @@
//! [`ToSql`] and [`FromSql`] implementation for [`url::Url`]. //! [`ToSql`] and [`FromSql`] implementation for [`Url`].
use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
use crate::Result; use crate::Result;
use url::Url; use url::Url;
@@ -18,7 +18,7 @@ impl FromSql for Url {
match value { match value {
ValueRef::Text(s) => { ValueRef::Text(s) => {
let s = std::str::from_utf8(s).map_err(|e| FromSqlError::Other(Box::new(e)))?; let s = std::str::from_utf8(s).map_err(|e| FromSqlError::Other(Box::new(e)))?;
Url::parse(s).map_err(|e| FromSqlError::Other(Box::new(e))) Self::parse(s).map_err(|e| FromSqlError::Other(Box::new(e)))
} }
_ => Err(FromSqlError::InvalidType), _ => Err(FromSqlError::InvalidType),
} }

View File

@@ -21,22 +21,22 @@ pub enum Value {
impl From<Null> for Value { impl From<Null> for Value {
#[inline] #[inline]
fn from(_: Null) -> Value { fn from(_: Null) -> Self {
Value::Null Self::Null
} }
} }
impl From<bool> for Value { impl From<bool> for Value {
#[inline] #[inline]
fn from(i: bool) -> Value { fn from(i: bool) -> Self {
Value::Integer(i as i64) Self::Integer(i as i64)
} }
} }
impl From<isize> for Value { impl From<isize> for Value {
#[inline] #[inline]
fn from(i: isize) -> Value { fn from(i: isize) -> Self {
Value::Integer(i as i64) Self::Integer(i as i64)
} }
} }
@@ -44,10 +44,10 @@ impl From<isize> for Value {
#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))] #[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
impl From<i128> for Value { impl From<i128> for Value {
#[inline] #[inline]
fn from(i: i128) -> Value { fn from(i: i128) -> Self {
// We store these biased (e.g. with the most significant bit flipped) // We store these biased (e.g. with the most significant bit flipped)
// so that comparisons with negative numbers work properly. // so that comparisons with negative numbers work properly.
Value::Blob(i128::to_be_bytes(i ^ (1_i128 << 127)).to_vec()) Self::Blob(i128::to_be_bytes(i ^ (1_i128 << 127)).to_vec())
} }
} }
@@ -55,8 +55,8 @@ impl From<i128> for Value {
#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))] #[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
impl From<uuid::Uuid> for Value { impl From<uuid::Uuid> for Value {
#[inline] #[inline]
fn from(id: uuid::Uuid) -> Value { fn from(id: uuid::Uuid) -> Self {
Value::Blob(id.as_bytes().to_vec()) Self::Blob(id.as_bytes().to_vec())
} }
} }
@@ -80,48 +80,48 @@ from_i64!(u32);
impl From<i64> for Value { impl From<i64> for Value {
#[inline] #[inline]
fn from(i: i64) -> Value { fn from(i: i64) -> Self {
Value::Integer(i) Self::Integer(i)
} }
} }
impl From<f32> for Value { impl From<f32> for Value {
#[inline] #[inline]
fn from(f: f32) -> Value { fn from(f: f32) -> Self {
Value::Real(f.into()) Self::Real(f.into())
} }
} }
impl From<f64> for Value { impl From<f64> for Value {
#[inline] #[inline]
fn from(f: f64) -> Value { fn from(f: f64) -> Self {
Value::Real(f) Self::Real(f)
} }
} }
impl From<String> for Value { impl From<String> for Value {
#[inline] #[inline]
fn from(s: String) -> Value { fn from(s: String) -> Self {
Value::Text(s) Self::Text(s)
} }
} }
impl From<Vec<u8>> for Value { impl From<Vec<u8>> for Value {
#[inline] #[inline]
fn from(v: Vec<u8>) -> Value { fn from(v: Vec<u8>) -> Self {
Value::Blob(v) Self::Blob(v)
} }
} }
impl<T> From<Option<T>> for Value impl<T> From<Option<T>> for Value
where where
T: Into<Value>, T: Into<Self>,
{ {
#[inline] #[inline]
fn from(v: Option<T>) -> Value { fn from(v: Option<T>) -> Self {
match v { match v {
Some(x) => x.into(), Some(x) => x.into(),
None => Value::Null, None => Self::Null,
} }
} }
} }
@@ -132,11 +132,33 @@ impl Value {
#[must_use] #[must_use]
pub fn data_type(&self) -> Type { pub fn data_type(&self) -> Type {
match *self { match *self {
Value::Null => Type::Null, Self::Null => Type::Null,
Value::Integer(_) => Type::Integer, Self::Integer(_) => Type::Integer,
Value::Real(_) => Type::Real, Self::Real(_) => Type::Real,
Value::Text(_) => Type::Text, Self::Text(_) => Type::Text,
Value::Blob(_) => Type::Blob, Self::Blob(_) => Type::Blob,
} }
} }
} }
#[cfg(test)]
mod test {
use super::Value;
use crate::types::Type;
#[test]
fn from() {
assert_eq!(Value::from(2f32), Value::Real(2f64));
assert_eq!(Value::from(3.), Value::Real(3.));
assert_eq!(Value::from(vec![0u8]), Value::Blob(vec![0u8]));
}
#[test]
fn data_type() {
assert_eq!(Value::Null.data_type(), Type::Null);
assert_eq!(Value::Integer(0).data_type(), Type::Integer);
assert_eq!(Value::Real(0.).data_type(), Type::Real);
assert_eq!(Value::Text(String::new()).data_type(), Type::Text);
assert_eq!(Value::Blob(vec![]).data_type(), Type::Blob);
}
}

View File

@@ -1,7 +1,7 @@
use super::{Type, Value}; use super::{Type, Value};
use crate::types::{FromSqlError, FromSqlResult}; use crate::types::{FromSqlError, FromSqlResult};
/// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically the /// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically, the
/// memory backing this value is owned by SQLite. /// memory backing this value is owned by SQLite.
/// ///
/// See [`Value`](Value) for an owning dynamic type value. /// See [`Value`](Value) for an owning dynamic type value.
@@ -47,7 +47,7 @@ impl<'a> ValueRef<'a> {
/// If `self` is case `Null` returns None. /// If `self` is case `Null` returns None.
/// If `self` is case `Integer`, returns the integral value. /// If `self` is case `Integer`, returns the integral value.
/// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
#[inline] #[inline]
pub fn as_i64_or_null(&self) -> FromSqlResult<Option<i64>> { pub fn as_i64_or_null(&self) -> FromSqlResult<Option<i64>> {
match *self { match *self {
@@ -69,7 +69,7 @@ impl<'a> ValueRef<'a> {
/// If `self` is case `Null` returns None. /// If `self` is case `Null` returns None.
/// If `self` is case `Real`, returns the floating point value. /// If `self` is case `Real`, returns the floating point value.
/// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
#[inline] #[inline]
pub fn as_f64_or_null(&self) -> FromSqlResult<Option<f64>> { pub fn as_f64_or_null(&self) -> FromSqlResult<Option<f64>> {
match *self { match *self {
@@ -93,7 +93,7 @@ impl<'a> ValueRef<'a> {
/// If `self` is case `Null` returns None. /// If `self` is case `Null` returns None.
/// If `self` is case `Text`, returns the string value. /// If `self` is case `Text`, returns the string value.
/// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
#[inline] #[inline]
pub fn as_str_or_null(&self) -> FromSqlResult<Option<&'a str>> { pub fn as_str_or_null(&self) -> FromSqlResult<Option<&'a str>> {
match *self { match *self {
@@ -117,7 +117,7 @@ impl<'a> ValueRef<'a> {
/// If `self` is case `Null` returns None. /// If `self` is case `Null` returns None.
/// If `self` is case `Blob`, returns the byte slice. /// If `self` is case `Blob`, returns the byte slice.
/// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
#[inline] #[inline]
pub fn as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> { pub fn as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
match *self { match *self {
@@ -153,16 +153,16 @@ impl<'a> ValueRef<'a> {
impl From<ValueRef<'_>> for Value { impl From<ValueRef<'_>> for Value {
#[inline] #[inline]
#[track_caller] #[track_caller]
fn from(borrowed: ValueRef<'_>) -> Value { fn from(borrowed: ValueRef<'_>) -> Self {
match borrowed { match borrowed {
ValueRef::Null => Value::Null, ValueRef::Null => Self::Null,
ValueRef::Integer(i) => Value::Integer(i), ValueRef::Integer(i) => Self::Integer(i),
ValueRef::Real(r) => Value::Real(r), ValueRef::Real(r) => Self::Real(r),
ValueRef::Text(s) => { ValueRef::Text(s) => {
let s = std::str::from_utf8(s).expect("invalid UTF-8"); let s = std::str::from_utf8(s).expect("invalid UTF-8");
Value::Text(s.to_string()) Self::Text(s.to_string())
} }
ValueRef::Blob(b) => Value::Blob(b.to_vec()), ValueRef::Blob(b) => Self::Blob(b.to_vec()),
} }
} }
} }
@@ -183,7 +183,7 @@ impl<'a> From<&'a [u8]> for ValueRef<'a> {
impl<'a> From<&'a Value> for ValueRef<'a> { impl<'a> From<&'a Value> for ValueRef<'a> {
#[inline] #[inline]
fn from(value: &'a Value) -> ValueRef<'a> { fn from(value: &'a Value) -> Self {
match *value { match *value {
Value::Null => ValueRef::Null, Value::Null => ValueRef::Null,
Value::Integer(i) => ValueRef::Integer(i), Value::Integer(i) => ValueRef::Integer(i),
@@ -194,12 +194,12 @@ impl<'a> From<&'a Value> for ValueRef<'a> {
} }
} }
impl<'a, T> From<Option<T>> for ValueRef<'a> impl<T> From<Option<T>> for ValueRef<'_>
where where
T: Into<ValueRef<'a>>, T: Into<Self>,
{ {
#[inline] #[inline]
fn from(s: Option<T>) -> ValueRef<'a> { fn from(s: Option<T>) -> Self {
match s { match s {
Some(x) => x.into(), Some(x) => x.into(),
None => ValueRef::Null, None => ValueRef::Null,
@@ -207,9 +207,14 @@ where
} }
} }
#[cfg(any(feature = "functions", feature = "session", feature = "vtab"))] #[cfg(any(
impl<'a> ValueRef<'a> { feature = "functions",
pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> { feature = "session",
feature = "vtab",
feature = "preupdate_hook"
))]
impl ValueRef<'_> {
pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> Self {
use crate::ffi; use crate::ffi;
use std::slice::from_raw_parts; use std::slice::from_raw_parts;
@@ -256,3 +261,75 @@ impl<'a> ValueRef<'a> {
// TODO sqlite3_value_nochange // 3.22.0 & VTab xUpdate // TODO sqlite3_value_nochange // 3.22.0 & VTab xUpdate
// TODO sqlite3_value_frombind // 3.28.0 // TODO sqlite3_value_frombind // 3.28.0
} }
#[cfg(test)]
mod test {
use super::ValueRef;
use crate::types::FromSqlResult;
#[test]
fn as_i64() -> FromSqlResult<()> {
assert!(ValueRef::Real(1.0).as_i64().is_err());
assert_eq!(ValueRef::Integer(1).as_i64(), Ok(1));
Ok(())
}
#[test]
fn as_i64_or_null() -> FromSqlResult<()> {
assert_eq!(ValueRef::Null.as_i64_or_null(), Ok(None));
assert!(ValueRef::Real(1.0).as_i64_or_null().is_err());
assert_eq!(ValueRef::Integer(1).as_i64_or_null(), Ok(Some(1)));
Ok(())
}
#[test]
fn as_f64() -> FromSqlResult<()> {
assert!(ValueRef::Integer(1).as_f64().is_err());
assert_eq!(ValueRef::Real(1.0).as_f64(), Ok(1.0));
Ok(())
}
#[test]
fn as_f64_or_null() -> FromSqlResult<()> {
assert_eq!(ValueRef::Null.as_f64_or_null(), Ok(None));
assert!(ValueRef::Integer(1).as_f64_or_null().is_err());
assert_eq!(ValueRef::Real(1.0).as_f64_or_null(), Ok(Some(1.0)));
Ok(())
}
#[test]
fn as_str() -> FromSqlResult<()> {
assert!(ValueRef::Null.as_str().is_err());
assert_eq!(ValueRef::Text(b"").as_str(), Ok(""));
Ok(())
}
#[test]
fn as_str_or_null() -> FromSqlResult<()> {
assert_eq!(ValueRef::Null.as_str_or_null(), Ok(None));
assert!(ValueRef::Integer(1).as_str_or_null().is_err());
assert_eq!(ValueRef::Text(b"").as_str_or_null(), Ok(Some("")));
Ok(())
}
#[test]
fn as_blob() -> FromSqlResult<()> {
assert!(ValueRef::Null.as_blob().is_err());
assert_eq!(ValueRef::Blob(b"").as_blob(), Ok(&b""[..]));
Ok(())
}
#[test]
fn as_blob_or_null() -> FromSqlResult<()> {
assert_eq!(ValueRef::Null.as_blob_or_null(), Ok(None));
assert!(ValueRef::Integer(1).as_blob_or_null().is_err());
assert_eq!(ValueRef::Blob(b"").as_blob_or_null(), Ok(Some(&b""[..])));
Ok(())
}
#[test]
fn as_bytes() -> FromSqlResult<()> {
assert!(ValueRef::Null.as_bytes().is_err());
assert_eq!(ValueRef::Blob(b"").as_bytes(), Ok(&b""[..]));
Ok(())
}
#[test]
fn as_bytes_or_null() -> FromSqlResult<()> {
assert_eq!(ValueRef::Null.as_bytes_or_null(), Ok(None));
assert!(ValueRef::Integer(1).as_bytes_or_null().is_err());
assert_eq!(ValueRef::Blob(b"").as_bytes_or_null(), Ok(Some(&b""[..])));
Ok(())
}
}

View File

@@ -12,10 +12,10 @@ struct UnlockNotification {
mutex: Mutex<bool>, // Mutex to protect structure mutex: Mutex<bool>, // Mutex to protect structure
} }
#[allow(clippy::mutex_atomic)] #[expect(clippy::mutex_atomic)]
impl UnlockNotification { impl UnlockNotification {
fn new() -> UnlockNotification { fn new() -> Self {
UnlockNotification { Self {
cond: Condvar::new(), cond: Condvar::new(),
mutex: Mutex::new(false), mutex: Mutex::new(false),
} }

View File

@@ -103,7 +103,7 @@ impl SqliteMallocString {
/// fails, we call `handle_alloc_error` which aborts the program after /// fails, we call `handle_alloc_error` which aborts the program after
/// calling a global hook. /// calling a global hook.
/// ///
/// This means it's safe to use in extern "C" functions even outside of /// This means it's safe to use in extern "C" functions even outside
/// `catch_unwind`. /// `catch_unwind`.
pub(crate) fn from_str(s: &str) -> Self { pub(crate) fn from_str(s: &str) -> Self {
let s = if s.as_bytes().contains(&0) { let s = if s.as_bytes().contains(&0) {

View File

@@ -26,7 +26,6 @@
//! } //! }
//! ``` //! ```
use std::default::Default;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::rc::Rc; use std::rc::Rc;
@@ -41,7 +40,7 @@ use crate::{Connection, Result};
// http://sqlite.org/bindptr.html // http://sqlite.org/bindptr.html
pub(crate) const ARRAY_TYPE: *const c_char = (b"rarray\0" as *const u8).cast::<c_char>(); pub(crate) const ARRAY_TYPE: *const c_char = c"rarray".as_ptr();
pub(crate) unsafe extern "C" fn free_array(p: *mut c_void) { pub(crate) unsafe extern "C" fn free_array(p: *mut c_void) {
drop(Rc::from_raw(p as *const Vec<Value>)); drop(Rc::from_raw(p as *const Vec<Value>));
@@ -82,8 +81,8 @@ unsafe impl<'vtab> VTab<'vtab> for ArrayTab {
_: &mut VTabConnection, _: &mut VTabConnection,
_aux: Option<&()>, _aux: Option<&()>,
_args: &[&[u8]], _args: &[&[u8]],
) -> Result<(String, ArrayTab)> { ) -> Result<(String, Self)> {
let vtab = ArrayTab { let vtab = Self {
base: ffi::sqlite3_vtab::default(), base: ffi::sqlite3_vtab::default(),
}; };
Ok(("CREATE TABLE x(value,pointer hidden)".to_owned(), vtab)) Ok(("CREATE TABLE x(value,pointer hidden)".to_owned(), vtab))

View File

@@ -91,14 +91,14 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
db: &mut VTabConnection, db: &mut VTabConnection,
_aux: Option<&()>, _aux: Option<&()>,
args: &[&[u8]], args: &[&[u8]],
) -> Result<(String, CsvTab)> { ) -> Result<(String, Self)> {
if args.len() < 4 { if args.len() < 4 {
return Err(Error::ModuleError("no CSV file specified".to_owned())); return Err(Error::ModuleError("no CSV file specified".to_owned()));
} }
let mut vtab = CsvTab { let mut vtab = Self {
base: ffi::sqlite3_vtab::default(), base: ffi::sqlite3_vtab::default(),
filename: "".to_owned(), filename: String::new(),
has_headers: false, has_headers: false,
delimiter: b',', delimiter: b',',
quote: b'"', quote: b'"',
@@ -115,7 +115,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
if !Path::new(value).exists() { if !Path::new(value).exists() {
return Err(Error::ModuleError(format!("file '{value}' does not exist"))); return Err(Error::ModuleError(format!("file '{value}' does not exist")));
} }
vtab.filename = value.to_owned(); value.clone_into(&mut vtab.filename);
} }
"schema" => { "schema" => {
schema = Some(value.to_owned()); schema = Some(value.to_owned());
@@ -148,7 +148,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
} }
} }
"delimiter" => { "delimiter" => {
if let Some(b) = CsvTab::parse_byte(value) { if let Some(b) = Self::parse_byte(value) {
vtab.delimiter = b; vtab.delimiter = b;
} else { } else {
return Err(Error::ModuleError(format!( return Err(Error::ModuleError(format!(
@@ -157,7 +157,7 @@ unsafe impl<'vtab> VTab<'vtab> for CsvTab {
} }
} }
"quote" => { "quote" => {
if let Some(b) = CsvTab::parse_byte(value) { if let Some(b) = Self::parse_byte(value) {
if b == b'0' { if b == b'0' {
vtab.quote = 0; vtab.quote = 0;
} else { } else {
@@ -335,8 +335,8 @@ unsafe impl VTabCursor for CsvTabCursor<'_> {
impl From<csv::Error> for Error { impl From<csv::Error> for Error {
#[cold] #[cold]
fn from(err: csv::Error) -> Error { fn from(err: csv::Error) -> Self {
Error::ModuleError(err.to_string()) Self::ModuleError(err.to_string())
} }
} }
@@ -350,7 +350,9 @@ mod test {
fn test_csv_module() -> Result<()> { fn test_csv_module() -> Result<()> {
let db = Connection::open_in_memory()?; let db = Connection::open_in_memory()?;
csvtab::load_module(&db)?; csvtab::load_module(&db)?;
db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)")?; db.execute_batch(
"CREATE VIRTUAL TABLE vtab USING csv(filename = 'test.csv', header = yes)",
)?;
{ {
let mut s = db.prepare("SELECT rowid, * FROM vtab")?; let mut s = db.prepare("SELECT rowid, * FROM vtab")?;

View File

@@ -3,15 +3,14 @@
//! Follow these steps to create your own virtual table: //! Follow these steps to create your own virtual table:
//! 1. Write implementation of [`VTab`] and [`VTabCursor`] traits. //! 1. Write implementation of [`VTab`] and [`VTabCursor`] traits.
//! 2. Create an instance of the [`Module`] structure specialized for [`VTab`] //! 2. Create an instance of the [`Module`] structure specialized for [`VTab`]
//! impl. from step 1. //! impl. from step 1.
//! 3. Register your [`Module`] structure using [`Connection::create_module`]. //! 3. Register your [`Module`] structure using [`Connection::create_module`].
//! 4. Run a `CREATE VIRTUAL TABLE` command that specifies the new module in the //! 4. Run a `CREATE VIRTUAL TABLE` command that specifies the new module in the
//! `USING` clause. //! `USING` clause.
//! //!
//! (See [SQLite doc](http://sqlite.org/vtab.html)) //! (See [SQLite doc](http://sqlite.org/vtab.html))
use std::borrow::Cow::{self, Borrowed, Owned}; use std::borrow::Cow::{self, Borrowed, Owned};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::marker::Sync;
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::ptr; use std::ptr;
use std::slice; use std::slice;
@@ -88,7 +87,7 @@ unsafe impl<'vtab, T: VTab<'vtab>> Send for Module<'vtab, T> {}
unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {} unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {}
union ModuleZeroHack { union ModuleZeroHack {
bytes: [u8; std::mem::size_of::<ffi::sqlite3_module>()], bytes: [u8; size_of::<ffi::sqlite3_module>()],
module: ffi::sqlite3_module, module: ffi::sqlite3_module,
} }
@@ -97,14 +96,13 @@ union ModuleZeroHack {
// structs are allowed to be zeroed. // structs are allowed to be zeroed.
const ZERO_MODULE: ffi::sqlite3_module = unsafe { const ZERO_MODULE: ffi::sqlite3_module = unsafe {
ModuleZeroHack { ModuleZeroHack {
bytes: [0_u8; std::mem::size_of::<ffi::sqlite3_module>()], bytes: [0_u8; size_of::<ffi::sqlite3_module>()],
} }
.module .module
}; };
macro_rules! module { macro_rules! module {
($lt:lifetime, $vt:ty, $ct:ty, $xc:expr, $xd:expr, $xu:expr) => { ($lt:lifetime, $vt:ty, $ct:ty, $xc:expr, $xd:expr, $xu:expr) => {
#[allow(clippy::needless_update)]
&Module { &Module {
base: ffi::sqlite3_module { base: ffi::sqlite3_module {
// We don't use V3 // We don't use V3
@@ -138,7 +136,7 @@ macro_rules! module {
}; };
} }
/// Create an modifiable virtual table implementation. /// Create a modifiable virtual table implementation.
/// ///
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
#[must_use] #[must_use]
@@ -190,13 +188,13 @@ pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab,
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum VTabConfig { pub enum VTabConfig {
/// Equivalent to SQLITE_VTAB_CONSTRAINT_SUPPORT /// Equivalent to `SQLITE_VTAB_CONSTRAINT_SUPPORT`
ConstraintSupport = 1, ConstraintSupport = 1,
/// Equivalent to SQLITE_VTAB_INNOCUOUS /// Equivalent to `SQLITE_VTAB_INNOCUOUS`
Innocuous = 2, Innocuous = 2,
/// Equivalent to SQLITE_VTAB_DIRECTONLY /// Equivalent to `SQLITE_VTAB_DIRECTONLY`
DirectOnly = 3, DirectOnly = 3,
/// Equivalent to SQLITE_VTAB_USES_ALL_SCHEMAS /// Equivalent to `SQLITE_VTAB_USES_ALL_SCHEMAS`
UsesAllSchemas = 4, UsesAllSchemas = 4,
} }
@@ -323,8 +321,8 @@ pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
/// Index constraint operator. /// Index constraint operator.
/// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details. /// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
#[allow(non_snake_case, non_camel_case_types, missing_docs)] #[allow(missing_docs)]
#[allow(clippy::upper_case_acronyms)] #[expect(non_camel_case_types)]
pub enum IndexConstraintOp { pub enum IndexConstraintOp {
SQLITE_INDEX_CONSTRAINT_EQ, SQLITE_INDEX_CONSTRAINT_EQ,
SQLITE_INDEX_CONSTRAINT_GT, SQLITE_INDEX_CONSTRAINT_GT,
@@ -346,25 +344,25 @@ pub enum IndexConstraintOp {
} }
impl From<u8> for IndexConstraintOp { impl From<u8> for IndexConstraintOp {
fn from(code: u8) -> IndexConstraintOp { fn from(code: u8) -> Self {
match code { match code {
2 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ, 2 => Self::SQLITE_INDEX_CONSTRAINT_EQ,
4 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GT, 4 => Self::SQLITE_INDEX_CONSTRAINT_GT,
8 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LE, 8 => Self::SQLITE_INDEX_CONSTRAINT_LE,
16 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LT, 16 => Self::SQLITE_INDEX_CONSTRAINT_LT,
32 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GE, 32 => Self::SQLITE_INDEX_CONSTRAINT_GE,
64 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_MATCH, 64 => Self::SQLITE_INDEX_CONSTRAINT_MATCH,
65 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIKE, 65 => Self::SQLITE_INDEX_CONSTRAINT_LIKE,
66 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GLOB, 66 => Self::SQLITE_INDEX_CONSTRAINT_GLOB,
67 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_REGEXP, 67 => Self::SQLITE_INDEX_CONSTRAINT_REGEXP,
68 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_NE, 68 => Self::SQLITE_INDEX_CONSTRAINT_NE,
69 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOT, 69 => Self::SQLITE_INDEX_CONSTRAINT_ISNOT,
70 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOTNULL, 70 => Self::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
71 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNULL, 71 => Self::SQLITE_INDEX_CONSTRAINT_ISNULL,
72 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_IS, 72 => Self::SQLITE_INDEX_CONSTRAINT_IS,
73 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIMIT, 73 => Self::SQLITE_INDEX_CONSTRAINT_LIMIT,
74 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_OFFSET, 74 => Self::SQLITE_INDEX_CONSTRAINT_OFFSET,
v => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_FUNCTION(v), v => Self::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
} }
} }
} }
@@ -374,11 +372,13 @@ bitflags::bitflags! {
/// See [Function Flags](https://sqlite.org/c3ref/c_index_scan_unique.html) for details. /// See [Function Flags](https://sqlite.org/c3ref/c_index_scan_unique.html) for details.
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct IndexFlags: ::std::os::raw::c_int { pub struct IndexFlags: c_int {
/// Default /// Default
const NONE = 0; const NONE = 0;
/// Scan visits at most 1 row. /// Scan visits at most 1 row.
const SQLITE_INDEX_SCAN_UNIQUE = ffi::SQLITE_INDEX_SCAN_UNIQUE; const SQLITE_INDEX_SCAN_UNIQUE = ffi::SQLITE_INDEX_SCAN_UNIQUE;
/// Display idxNum as hex in EXPLAIN QUERY PLAN
const SQLITE_INDEX_SCAN_HEX = 0x0000_0002; // 3.47.0
} }
} }
@@ -481,7 +481,7 @@ impl IndexInfo {
} }
} }
/// Mask of SQLITE_INDEX_SCAN_* flags. /// Mask of `SQLITE_INDEX_SCAN_*` flags.
#[inline] #[inline]
pub fn set_idx_flags(&mut self, flags: IndexFlags) { pub fn set_idx_flags(&mut self, flags: IndexFlags) {
unsafe { (*self.0).idxFlags = flags.bits() }; unsafe { (*self.0).idxFlags = flags.bits() };
@@ -501,10 +501,7 @@ impl IndexInfo {
let idx = constraint_idx as c_int; let idx = constraint_idx as c_int;
let collation = unsafe { ffi::sqlite3_vtab_collation(self.0, idx) }; let collation = unsafe { ffi::sqlite3_vtab_collation(self.0, idx) };
if collation.is_null() { if collation.is_null() {
return Err(Error::SqliteFailure( return Err(err!(ffi::SQLITE_MISUSE, "{constraint_idx} is out of range"));
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("{constraint_idx} is out of range")),
));
} }
Ok(unsafe { CStr::from_ptr(collation) }.to_str()?) Ok(unsafe { CStr::from_ptr(collation) }.to_str()?)
} }
@@ -760,10 +757,9 @@ impl Values<'_> {
None None
} else { } else {
Some(unsafe { Some(unsafe {
let rc = array::Array::from_raw(ptr as *const Vec<Value>); let ptr = ptr as *const Vec<Value>;
let array = rc.clone(); array::Array::increment_strong_count(ptr); // don't consume it
array::Array::into_raw(rc); // don't consume it array::Array::from_raw(ptr)
array
}) })
} }
} }
@@ -924,7 +920,7 @@ pub fn parameter(c_slice: &[u8]) -> Result<(&str, &str)> {
if let Some(key) = split.next() { if let Some(key) = split.next() {
if let Some(value) = split.next() { if let Some(value) = split.next() {
let param = key.trim(); let param = key.trim();
let value = dequote(value); let value = dequote(value.trim());
return Ok((param, value)); return Ok((param, value));
} }
} }
@@ -941,7 +937,7 @@ unsafe extern "C" fn rust_create<'vtab, T>(
aux: *mut c_void, aux: *mut c_void,
argc: c_int, argc: c_int,
argv: *const *const c_char, argv: *const *const c_char,
pp_vtab: *mut *mut ffi::sqlite3_vtab, pp_vtab: *mut *mut sqlite3_vtab,
err_msg: *mut *mut c_char, err_msg: *mut *mut c_char,
) -> c_int ) -> c_int
where where
@@ -962,7 +958,7 @@ where
let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr()); let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
if rc == ffi::SQLITE_OK { if rc == ffi::SQLITE_OK {
let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab)); let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
*pp_vtab = boxed_vtab.cast::<ffi::sqlite3_vtab>(); *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
ffi::SQLITE_OK ffi::SQLITE_OK
} else { } else {
let err = error_from_sqlite_code(rc, None); let err = error_from_sqlite_code(rc, None);
@@ -983,7 +979,7 @@ unsafe extern "C" fn rust_connect<'vtab, T>(
aux: *mut c_void, aux: *mut c_void,
argc: c_int, argc: c_int,
argv: *const *const c_char, argv: *const *const c_char,
pp_vtab: *mut *mut ffi::sqlite3_vtab, pp_vtab: *mut *mut sqlite3_vtab,
err_msg: *mut *mut c_char, err_msg: *mut *mut c_char,
) -> c_int ) -> c_int
where where
@@ -1004,7 +1000,7 @@ where
let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr()); let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
if rc == ffi::SQLITE_OK { if rc == ffi::SQLITE_OK {
let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab)); let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
*pp_vtab = boxed_vtab.cast::<ffi::sqlite3_vtab>(); *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
ffi::SQLITE_OK ffi::SQLITE_OK
} else { } else {
let err = error_from_sqlite_code(rc, None); let err = error_from_sqlite_code(rc, None);
@@ -1021,7 +1017,7 @@ where
} }
unsafe extern "C" fn rust_best_index<'vtab, T>( unsafe extern "C" fn rust_best_index<'vtab, T>(
vtab: *mut ffi::sqlite3_vtab, vtab: *mut sqlite3_vtab,
info: *mut ffi::sqlite3_index_info, info: *mut ffi::sqlite3_index_info,
) -> c_int ) -> c_int
where where
@@ -1044,7 +1040,7 @@ where
} }
} }
unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
where where
T: VTab<'vtab>, T: VTab<'vtab>,
{ {
@@ -1056,7 +1052,7 @@ where
ffi::SQLITE_OK ffi::SQLITE_OK
} }
unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
where where
T: CreateVTab<'vtab>, T: CreateVTab<'vtab>,
{ {
@@ -1082,18 +1078,18 @@ where
} }
} }
unsafe extern "C" fn rust_open<'vtab, T: 'vtab>( unsafe extern "C" fn rust_open<'vtab, T>(
vtab: *mut ffi::sqlite3_vtab, vtab: *mut sqlite3_vtab,
pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor, pp_cursor: *mut *mut sqlite3_vtab_cursor,
) -> c_int ) -> c_int
where where
T: VTab<'vtab>, T: VTab<'vtab> + 'vtab,
{ {
let vt = vtab.cast::<T>(); let vt = vtab.cast::<T>();
match (*vt).open() { match (*vt).open() {
Ok(cursor) => { Ok(cursor) => {
let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor)); let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
*pp_cursor = boxed_cursor.cast::<ffi::sqlite3_vtab_cursor>(); *pp_cursor = boxed_cursor.cast::<sqlite3_vtab_cursor>();
ffi::SQLITE_OK ffi::SQLITE_OK
} }
Err(Error::SqliteFailure(err, s)) => { Err(Error::SqliteFailure(err, s)) => {
@@ -1109,7 +1105,7 @@ where
} }
} }
unsafe extern "C" fn rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int unsafe extern "C" fn rust_close<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
where where
C: VTabCursor, C: VTabCursor,
{ {
@@ -1119,7 +1115,7 @@ where
} }
unsafe extern "C" fn rust_filter<C>( unsafe extern "C" fn rust_filter<C>(
cursor: *mut ffi::sqlite3_vtab_cursor, cursor: *mut sqlite3_vtab_cursor,
idx_num: c_int, idx_num: c_int,
idx_str: *const c_char, idx_str: *const c_char,
argc: c_int, argc: c_int,
@@ -1142,7 +1138,7 @@ where
cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values)) cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values))
} }
unsafe extern "C" fn rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int unsafe extern "C" fn rust_next<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
where where
C: VTabCursor, C: VTabCursor,
{ {
@@ -1150,7 +1146,7 @@ where
cursor_error(cursor, (*cr).next()) cursor_error(cursor, (*cr).next())
} }
unsafe extern "C" fn rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int unsafe extern "C" fn rust_eof<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
where where
C: VTabCursor, C: VTabCursor,
{ {
@@ -1159,7 +1155,7 @@ where
} }
unsafe extern "C" fn rust_column<C>( unsafe extern "C" fn rust_column<C>(
cursor: *mut ffi::sqlite3_vtab_cursor, cursor: *mut sqlite3_vtab_cursor,
ctx: *mut ffi::sqlite3_context, ctx: *mut ffi::sqlite3_context,
i: c_int, i: c_int,
) -> c_int ) -> c_int
@@ -1172,7 +1168,7 @@ where
} }
unsafe extern "C" fn rust_rowid<C>( unsafe extern "C" fn rust_rowid<C>(
cursor: *mut ffi::sqlite3_vtab_cursor, cursor: *mut sqlite3_vtab_cursor,
p_rowid: *mut ffi::sqlite3_int64, p_rowid: *mut ffi::sqlite3_int64,
) -> c_int ) -> c_int
where where
@@ -1188,14 +1184,14 @@ where
} }
} }
unsafe extern "C" fn rust_update<'vtab, T: 'vtab>( unsafe extern "C" fn rust_update<'vtab, T>(
vtab: *mut ffi::sqlite3_vtab, vtab: *mut sqlite3_vtab,
argc: c_int, argc: c_int,
argv: *mut *mut ffi::sqlite3_value, argv: *mut *mut ffi::sqlite3_value,
p_rowid: *mut ffi::sqlite3_int64, p_rowid: *mut ffi::sqlite3_int64,
) -> c_int ) -> c_int
where where
T: UpdateVTab<'vtab>, T: UpdateVTab<'vtab> + 'vtab,
{ {
assert!(argc >= 1); assert!(argc >= 1);
let args = slice::from_raw_parts_mut(argv, argc as usize); let args = slice::from_raw_parts_mut(argv, argc as usize);
@@ -1234,7 +1230,7 @@ where
/// Virtual table cursors can set an error message by assigning a string to /// Virtual table cursors can set an error message by assigning a string to
/// `zErrMsg`. /// `zErrMsg`.
#[cold] #[cold]
unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int { unsafe fn cursor_error<T>(cursor: *mut sqlite3_vtab_cursor, result: Result<T>) -> c_int {
match result { match result {
Ok(_) => ffi::SQLITE_OK, Ok(_) => ffi::SQLITE_OK,
Err(Error::SqliteFailure(err, s)) => { Err(Error::SqliteFailure(err, s)) => {
@@ -1253,7 +1249,7 @@ unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<
/// Virtual tables methods can set an error message by assigning a string to /// Virtual tables methods can set an error message by assigning a string to
/// `zErrMsg`. /// `zErrMsg`.
#[cold] #[cold]
unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) { unsafe fn set_err_msg(vtab: *mut sqlite3_vtab, err_msg: &str) {
if !(*vtab).zErrMsg.is_null() { if !(*vtab).zErrMsg.is_null() {
ffi::sqlite3_free((*vtab).zErrMsg.cast::<c_void>()); ffi::sqlite3_free((*vtab).zErrMsg.cast::<c_void>());
} }

View File

@@ -3,7 +3,6 @@
//! Port of C [generate series //! Port of C [generate series
//! "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c): //! "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c):
//! `https://www.sqlite.org/series.html` //! `https://www.sqlite.org/series.html`
use std::default::Default;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::raw::c_int; use std::os::raw::c_int;
@@ -13,9 +12,9 @@ use crate::vtab::{
eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConfig, VTabConnection, eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConfig, VTabConnection,
VTabCursor, Values, VTabCursor, Values,
}; };
use crate::{Connection, Error, Result}; use crate::{error::error_from_sqlite_code, Connection, Result};
/// Register the "generate_series" module. /// Register the `generate_series` module.
pub fn load_module(conn: &Connection) -> Result<()> { pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None; let aux: Option<()> = None;
conn.create_module("generate_series", eponymous_only_module::<SeriesTab>(), aux) conn.create_module("generate_series", eponymous_only_module::<SeriesTab>(), aux)
@@ -30,7 +29,7 @@ const SERIES_COLUMN_STEP: c_int = 3;
bitflags::bitflags! { bitflags::bitflags! {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(C)] #[repr(C)]
struct QueryPlanFlags: ::std::os::raw::c_int { struct QueryPlanFlags: c_int {
// start = $value -- constraint exists // start = $value -- constraint exists
const START = 1; const START = 1;
// stop = $value -- constraint exists // stop = $value -- constraint exists
@@ -61,8 +60,8 @@ unsafe impl<'vtab> VTab<'vtab> for SeriesTab {
db: &mut VTabConnection, db: &mut VTabConnection,
_aux: Option<&()>, _aux: Option<&()>,
_args: &[&[u8]], _args: &[&[u8]],
) -> Result<(String, SeriesTab)> { ) -> Result<(String, Self)> {
let vtab = SeriesTab { let vtab = Self {
base: ffi::sqlite3_vtab::default(), base: ffi::sqlite3_vtab::default(),
}; };
db.config(VTabConfig::Innocuous)?; db.config(VTabConfig::Innocuous)?;
@@ -109,14 +108,11 @@ unsafe impl<'vtab> VTab<'vtab> for SeriesTab {
debug_assert_eq!(Ok("BINARY"), info.collation(*j)); debug_assert_eq!(Ok("BINARY"), info.collation(*j));
} }
if !(unusable_mask & !idx_num).is_empty() { if !(unusable_mask & !idx_num).is_empty() {
return Err(Error::SqliteFailure( return Err(error_from_sqlite_code(ffi::SQLITE_CONSTRAINT, None));
ffi::Error::new(ffi::SQLITE_CONSTRAINT),
None,
));
} }
if idx_num.contains(QueryPlanFlags::BOTH) { if idx_num.contains(QueryPlanFlags::BOTH) {
// Both start= and stop= boundaries are available. // Both start= and stop= boundaries are available.
#[allow(clippy::bool_to_int_with_if)] #[expect(clippy::bool_to_int_with_if)]
info.set_estimated_cost(f64::from( info.set_estimated_cost(f64::from(
2 - if idx_num.contains(QueryPlanFlags::STEP) { 2 - if idx_num.contains(QueryPlanFlags::STEP) {
1 1
@@ -194,7 +190,7 @@ impl SeriesTabCursor<'_> {
} }
} }
} }
#[allow(clippy::comparison_chain)] #[expect(clippy::comparison_chain)]
unsafe impl VTabCursor for SeriesTabCursor<'_> { unsafe impl VTabCursor for SeriesTabCursor<'_> {
fn filter(&mut self, idx_num: c_int, _idx_str: Option<&str>, args: &Values<'_>) -> Result<()> { fn filter(&mut self, idx_num: c_int, _idx_str: Option<&str>, args: &Values<'_>) -> Result<()> {
let mut idx_num = QueryPlanFlags::from_bits_truncate(idx_num); let mut idx_num = QueryPlanFlags::from_bits_truncate(idx_num);

View File

@@ -1,5 +1,4 @@
//! Port of C [vtablog](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/vtablog.c) //! Port of C [vtablog](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/vtablog.c)
use std::default::Default;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::raw::c_int; use std::os::raw::c_int;
use std::str::FromStr; use std::str::FromStr;
@@ -37,7 +36,7 @@ impl VTabLog {
_: Option<&()>, _: Option<&()>,
args: &[&[u8]], args: &[&[u8]],
is_create: bool, is_create: bool,
) -> Result<(String, VTabLog)> { ) -> Result<(String, Self)> {
static N_INST: AtomicUsize = AtomicUsize::new(1); static N_INST: AtomicUsize = AtomicUsize::new(1);
let i_inst = N_INST.fetch_add(1, Ordering::SeqCst); let i_inst = N_INST.fetch_add(1, Ordering::SeqCst);
println!( println!(
@@ -81,7 +80,7 @@ impl VTabLog {
if schema.is_none() { if schema.is_none() {
return Err(Error::ModuleError("no schema defined".to_owned())); return Err(Error::ModuleError("no schema defined".to_owned()));
} }
let vtab = VTabLog { let vtab = Self {
base: ffi::sqlite3_vtab::default(), base: ffi::sqlite3_vtab::default(),
n_row: n_row.unwrap_or(10), n_row: n_row.unwrap_or(10),
i_inst, i_inst,
@@ -106,7 +105,7 @@ unsafe impl<'vtab> VTab<'vtab> for VTabLog {
aux: Option<&Self::Aux>, aux: Option<&Self::Aux>,
args: &[&[u8]], args: &[&[u8]],
) -> Result<(String, Self)> { ) -> Result<(String, Self)> {
VTabLog::connect_create(db, aux, args, false) Self::connect_create(db, aux, args, false)
} }
fn best_index(&self, info: &mut IndexInfo) -> Result<()> { fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
@@ -131,7 +130,7 @@ unsafe impl<'vtab> VTab<'vtab> for VTabLog {
} }
} }
impl<'vtab> CreateVTab<'vtab> for VTabLog { impl CreateVTab<'_> for VTabLog {
const KIND: VTabKind = VTabKind::Default; const KIND: VTabKind = VTabKind::Default;
fn create( fn create(
@@ -139,7 +138,7 @@ impl<'vtab> CreateVTab<'vtab> for VTabLog {
aux: Option<&Self::Aux>, aux: Option<&Self::Aux>,
args: &[&[u8]], args: &[&[u8]],
) -> Result<(String, Self)> { ) -> Result<(String, Self)> {
VTabLog::connect_create(db, aux, args, true) Self::connect_create(db, aux, args, true)
} }
fn destroy(&self) -> Result<()> { fn destroy(&self) -> Result<()> {
@@ -148,7 +147,7 @@ impl<'vtab> CreateVTab<'vtab> for VTabLog {
} }
} }
impl<'vtab> UpdateVTab<'vtab> for VTabLog { impl UpdateVTab<'_> for VTabLog {
fn delete(&mut self, arg: ValueRef<'_>) -> Result<()> { fn delete(&mut self, arg: ValueRef<'_>) -> Result<()> {
println!("VTabLog::delete({}, {arg:?})", self.i_inst); println!("VTabLog::delete({}, {arg:?})", self.i_inst);
Ok(()) Ok(())

View File

@@ -0,0 +1,41 @@
#[cfg(all(feature = "bundled", not(feature = "loadable_extension")))]
#[test]
fn auto_ext() -> rusqlite::Result<()> {
use rusqlite::auto_extension::*;
use rusqlite::{ffi, Connection, Error, Result};
use std::os::raw::{c_char, c_int};
fn test_ok(_: Connection) -> Result<()> {
Ok(())
}
unsafe extern "C" fn sqlite_test_ok(
db: *mut ffi::sqlite3,
pz_err_msg: *mut *mut c_char,
_: *const ffi::sqlite3_api_routines,
) -> c_int {
init_auto_extension(db, pz_err_msg, test_ok)
}
fn test_err(_: Connection) -> Result<()> {
Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_CORRUPT),
Some("AutoExtErr".to_owned()),
))
}
unsafe extern "C" fn sqlite_test_err(
db: *mut ffi::sqlite3,
pz_err_msg: *mut *mut c_char,
_: *const ffi::sqlite3_api_routines,
) -> c_int {
init_auto_extension(db, pz_err_msg, test_err)
}
//assert!(!cancel_auto_extension(sqlite_test_ok));
unsafe { register_auto_extension(sqlite_test_ok)? };
Connection::open_in_memory()?;
assert!(cancel_auto_extension(sqlite_test_ok));
assert!(!cancel_auto_extension(sqlite_test_ok));
unsafe { register_auto_extension(sqlite_test_err)? };
Connection::open_in_memory().unwrap_err();
reset_auto_extension();
Ok(())
}

View File

@@ -4,13 +4,11 @@
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
fn main() { fn main() {
use lazy_static::lazy_static;
use std::os::raw::c_int; use std::os::raw::c_int;
use std::sync::Mutex; use std::sync::{LazyLock, Mutex};
lazy_static! { static LOGS_RECEIVED: LazyLock<Mutex<Vec<(c_int, String)>>> =
static ref LOGS_RECEIVED: Mutex<Vec<(c_int, String)>> = Mutex::new(Vec::new()); LazyLock::new(|| Mutex::new(Vec::new()));
}
fn log_handler(err: c_int, message: &str) { fn log_handler(err: c_int, message: &str) {
let mut logs_received = LOGS_RECEIVED.lock().unwrap(); let mut logs_received = LOGS_RECEIVED.lock().unwrap();

View File

@@ -27,8 +27,8 @@ fn test_dummy_module() -> rusqlite::Result<()> {
_: &mut VTabConnection, _: &mut VTabConnection,
_aux: Option<&()>, _aux: Option<&()>,
_args: &[&[u8]], _args: &[&[u8]],
) -> Result<(String, DummyTab)> { ) -> Result<(String, Self)> {
let vtab = DummyTab { let vtab = Self {
base: sqlite3_vtab::default(), base: sqlite3_vtab::default(),
}; };
Ok(("CREATE TABLE x(value)".to_owned(), vtab)) Ok(("CREATE TABLE x(value)".to_owned(), vtab))

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"22a76fdf06c848eeb950bb8ddb0cb4ec918adbeef3eae2bb7006a6ecf76f5dfa","src/conn_ext.rs":"1280fb1f06b74ed312e73f34c4fd86f538411c4b3d4eeccb631c80d02e295645","src/debug_tools.rs":"bece2bc3d35379b81ea2f942a0a3e909e0ab0553656505904745548eacaf402a","src/each_chunk.rs":"e900a4ebadad31b0a87cb8d7c3ed5aeb7325d4d380ae1d9174eff62c78facdcc","src/lazy.rs":"a96b4f4ec572538b49cdfa8fee981dcf5143a5f51163fb8a573d3ac128df70f9","src/lib.rs":"cb501b3b0482d549cbe6f0350d7321ed315269ccd75215af2582aae340fe354b","src/maybe_cached.rs":"0b18425595055883a98807fbd62ff27a79c18af34e7cb3439f8c3438463ef2dd","src/open_database.rs":"0e50c02b3a052c6b3cdc742409d46fb40a5939080c1f7ec1684241dc2b02f269","src/repeat.rs":"3dad3cbc6f47fc7598fc7b0fbf79b9c915322396d1f64d3d09651d100d428351"},"package":null} {"files":{"Cargo.toml":"00ffcb582afeb58d8249fc5fa2c453dab9ce3e305cb49410e21ca9a8561ce16e","src/conn_ext.rs":"1280fb1f06b74ed312e73f34c4fd86f538411c4b3d4eeccb631c80d02e295645","src/debug_tools.rs":"bece2bc3d35379b81ea2f942a0a3e909e0ab0553656505904745548eacaf402a","src/each_chunk.rs":"0b4de829ccaf06b743d0ee5bce766399d841e12592cd00d22605b75a5ae6dbd0","src/lazy.rs":"a96b4f4ec572538b49cdfa8fee981dcf5143a5f51163fb8a573d3ac128df70f9","src/lib.rs":"cb501b3b0482d549cbe6f0350d7321ed315269ccd75215af2582aae340fe354b","src/maybe_cached.rs":"0b18425595055883a98807fbd62ff27a79c18af34e7cb3439f8c3438463ef2dd","src/open_database.rs":"0e50c02b3a052c6b3cdc742409d46fb40a5939080c1f7ec1684241dc2b02f269","src/repeat.rs":"3dad3cbc6f47fc7598fc7b0fbf79b9c915322396d1f64d3d09651d100d428351"},"package":null}

View File

@@ -42,7 +42,7 @@ thiserror = "1.0"
path = "../interrupt" path = "../interrupt"
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = [ features = [
"functions", "functions",
"limits", "limits",

View File

@@ -21,7 +21,7 @@ pub fn default_max_variable_number() -> usize {
let conn = rusqlite::Connection::open_in_memory() let conn = rusqlite::Connection::open_in_memory()
.expect("Failed to initialize in-memory connection (out of memory?)"); .expect("Failed to initialize in-memory connection (out of memory?)");
let limit = conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER); let limit = conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER).unwrap();
assert!( assert!(
limit > 0, limit > 0,
"Illegal value for SQLITE_LIMIT_VARIABLE_NUMBER (must be > 0) {}", "Illegal value for SQLITE_LIMIT_VARIABLE_NUMBER (must be > 0) {}",

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"014932716cf1518dfe78c34d2c6ea4c30b23f5f5911c6ad2995de8cc72042bef","README.md":"5e28baf874b643d756228bdab345e287bf107d3182dfe6a18aafadcc4b9a3fc9","benches/benchmark_all.rs":"5909dfb1e62793afb1f2bc15b75914527a4d14fce6796307c04a309e45c0598c","metrics.yaml":"0540ab2271aeab7f07335c7ceec12acde942995f9dcb3c29070489aa61899d56","src/benchmarks/README.md":"ccee8dbddba8762d0453fa855bd6984137b224b8c019f3dd8e86a3c303f51d71","src/benchmarks/client.rs":"e5897d4e2eda06809fa6dc6db4e780b9ef266f613fb113aa6613b83f7005dd0b","src/benchmarks/geoname.rs":"00fab05cf9465cf8e22e143cde75a81885411001b240af00efda4071975d0563","src/benchmarks/ingest.rs":"1f3b5eca704c51bc8f972e7a3492a518516461e5834f97a5f7d1855a048ab16b","src/benchmarks/mod.rs":"ac8965ca749f2932dc90299b159026c73416afadde1f2e71a2613d7d58d6ac3d","src/benchmarks/query.rs":"d54946063e72cf98e7f46d94665c17c66af637774c2bb50cd5798dbe63d74f3c","src/bin/debug_ingestion_sizes.rs":"ce6e810be7b3fc19e826d75b622b82cfab5a1a99397a6d0833c2c4eebff2d364","src/config.rs":"0ca876e845841bb6429862c0904c82265003f53b55aea053fac60aed278586a7","src/db.rs":"e41cbfb922d3c4123ee014f3bcd17c2819aead424c68b51256377a0c8740ef4c","src/error.rs":"e2ef3ec0e0b2b8ecbb8f2f1717d4cb753af06913b8395d086b7643098ad100a7","src/fakespot.rs":"f501c9fe5296e7c130a9fcb532b861465717652cb5ef688230bc7a3b94df91b1","src/geoname.rs":"77376dbc7d06532a7797a93b863f150317df7f31d9200d375c8ea489ac8bee6f","src/lib.rs":"67d77bf55498ce57c9e607d34e2bc5820403dda1207e85bf1f1c79d235d862f7","src/metrics.rs":"871f0d834efbbc9e26d61f66fa31f0021dcf41444746cd7c082f93ba9628e399","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"eaf893b55473d0f6ce7fbc45a70e5d994b054c1d369453eeb12c3d3cf0c1dc31","src/query.rs":"3556e2c76e3fa20f93fa78173162c79bf11fefba930deaa762fa7c5d85cd6f41","src/rs.rs":"c41facd0bd1706065f29267cbf230cb8baae4b34aae85f487b90fd7620bdc0d2","src/schema.rs":"4e7fc587a58cbf008211629f86292fb6ee9220e827b00aa6865dceaabeb9e581","src/store.rs":"200620f428a70e0fa6ae505be07870335843fe5381f26cd1244cdf9817b17b32","src/suggestion.rs":"7e295a534d6914e6c70cc14e0bc7df953b1b266232c812175c82e1a58d0305f9","src/testing/client.rs":"47a32fd84c733001f11e8bfff94dc8c060b6b0780346dca5ddc7a5f5489c1d85","src/testing/data.rs":"2a25c4ba7997f0bd5d1815666dff31b8db845f6f22f3635e878921695a4e783c","src/testing/mod.rs":"dce5a18cc2e6b951304e613055dd8e6b0d89c90934eee55e424ecfdf92f745a5","src/util.rs":"52c6ec405637afa2d1a89f29fbbb7dcc341546b6deb97d326c4490bbf8713cb0","src/weather.rs":"7cc9167dcdfca49d6ad91eba6fba4d5fd49f45052f25a7fe3ad6749d3e6783fb","src/yelp.rs":"0b9dfa698d9c3162d47c0103d1799838d444345f9d7f943eedc6bcc98fd8b57d","uniffi.toml":"8205e4679ac26d53e70af0f85c013fd27cda1119f4322aebf5f2b9403d45a611"},"package":null} {"files":{"Cargo.toml":"922b2e4d85f325dbef99d5e439558a75dbfda82e1d263c2dd3bfadac9879df18","README.md":"5e28baf874b643d756228bdab345e287bf107d3182dfe6a18aafadcc4b9a3fc9","benches/benchmark_all.rs":"5909dfb1e62793afb1f2bc15b75914527a4d14fce6796307c04a309e45c0598c","metrics.yaml":"0540ab2271aeab7f07335c7ceec12acde942995f9dcb3c29070489aa61899d56","src/benchmarks/README.md":"ccee8dbddba8762d0453fa855bd6984137b224b8c019f3dd8e86a3c303f51d71","src/benchmarks/client.rs":"e5897d4e2eda06809fa6dc6db4e780b9ef266f613fb113aa6613b83f7005dd0b","src/benchmarks/geoname.rs":"00fab05cf9465cf8e22e143cde75a81885411001b240af00efda4071975d0563","src/benchmarks/ingest.rs":"1f3b5eca704c51bc8f972e7a3492a518516461e5834f97a5f7d1855a048ab16b","src/benchmarks/mod.rs":"ac8965ca749f2932dc90299b159026c73416afadde1f2e71a2613d7d58d6ac3d","src/benchmarks/query.rs":"d54946063e72cf98e7f46d94665c17c66af637774c2bb50cd5798dbe63d74f3c","src/bin/debug_ingestion_sizes.rs":"ce6e810be7b3fc19e826d75b622b82cfab5a1a99397a6d0833c2c4eebff2d364","src/config.rs":"0ca876e845841bb6429862c0904c82265003f53b55aea053fac60aed278586a7","src/db.rs":"e41cbfb922d3c4123ee014f3bcd17c2819aead424c68b51256377a0c8740ef4c","src/error.rs":"e2ef3ec0e0b2b8ecbb8f2f1717d4cb753af06913b8395d086b7643098ad100a7","src/fakespot.rs":"f501c9fe5296e7c130a9fcb532b861465717652cb5ef688230bc7a3b94df91b1","src/geoname.rs":"77376dbc7d06532a7797a93b863f150317df7f31d9200d375c8ea489ac8bee6f","src/lib.rs":"67d77bf55498ce57c9e607d34e2bc5820403dda1207e85bf1f1c79d235d862f7","src/metrics.rs":"871f0d834efbbc9e26d61f66fa31f0021dcf41444746cd7c082f93ba9628e399","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"eaf893b55473d0f6ce7fbc45a70e5d994b054c1d369453eeb12c3d3cf0c1dc31","src/query.rs":"3556e2c76e3fa20f93fa78173162c79bf11fefba930deaa762fa7c5d85cd6f41","src/rs.rs":"c41facd0bd1706065f29267cbf230cb8baae4b34aae85f487b90fd7620bdc0d2","src/schema.rs":"4e7fc587a58cbf008211629f86292fb6ee9220e827b00aa6865dceaabeb9e581","src/store.rs":"200620f428a70e0fa6ae505be07870335843fe5381f26cd1244cdf9817b17b32","src/suggestion.rs":"7e295a534d6914e6c70cc14e0bc7df953b1b266232c812175c82e1a58d0305f9","src/testing/client.rs":"47a32fd84c733001f11e8bfff94dc8c060b6b0780346dca5ddc7a5f5489c1d85","src/testing/data.rs":"2a25c4ba7997f0bd5d1815666dff31b8db845f6f22f3635e878921695a4e783c","src/testing/mod.rs":"dce5a18cc2e6b951304e613055dd8e6b0d89c90934eee55e424ecfdf92f745a5","src/util.rs":"52c6ec405637afa2d1a89f29fbbb7dcc341546b6deb97d326c4490bbf8713cb0","src/weather.rs":"7cc9167dcdfca49d6ad91eba6fba4d5fd49f45052f25a7fe3ad6749d3e6783fb","src/yelp.rs":"0b9dfa698d9c3162d47c0103d1799838d444345f9d7f943eedc6bcc98fd8b57d","uniffi.toml":"8205e4679ac26d53e70af0f85c013fd27cda1119f4322aebf5f2b9403d45a611"},"package":null}

View File

@@ -71,7 +71,7 @@ path = "../support/interrupt"
path = "../remote_settings" path = "../remote_settings"
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = [ features = [
"functions", "functions",
"bundled", "bundled",

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"bcc4f6c5b402910927c448ad1d91069b0c2b529abaf3541d3aee3ab245364543","src/lib.rs":"a112b66270feba587d0b09e64b4197af01f981675a23f76649a7d948f85c2bd9","src/rusqlite_support.rs":"c6791f103c286858a1a6e2c7e106b177ed8d9196b73ed100a8bb0aec1b1f957f","src/serde_support.rs":"0aade33dae88373d250ad921295d8dfe344e655f7c6240e3491d11ffc774443f"},"package":null} {"files":{"Cargo.toml":"31126d01938cc9989323c25f96617d2fe5e3f5749c385e730497c277ed3fb144","src/lib.rs":"a112b66270feba587d0b09e64b4197af01f981675a23f76649a7d948f85c2bd9","src/rusqlite_support.rs":"c6791f103c286858a1a6e2c7e106b177ed8d9196b73ed100a8bb0aec1b1f957f","src/serde_support.rs":"0aade33dae88373d250ad921295d8dfe344e655f7c6240e3491d11ffc774443f"},"package":null}

View File

@@ -45,7 +45,7 @@ version = "0.8"
optional = true optional = true
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = ["bundled"] features = ["bundled"]
optional = true optional = true

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"aa26c17e79d8e66293d8d198d1d00e0928c7a418c24663b53878a8ed7596f2ad","README.md":"c48b8f391ef822c4f3971b5f453a1e7b43bea232752d520460d2f04803aead1a","build.rs":"33e61b811b19ed2b58e319cc65d5988bed258d2c4fea2d706301184c59847a0f","src/error.rs":"6e5fd48a3f228d37977881a3657f8635b1b37e3b16d91ac2d8476174172a2a74","src/lib.rs":"2e2a7173ec3bf46065a60c34fbdf91254ff720d9d15955cb87b9019dafca7690","src/schema.rs":"510218d465c7d26d6b9f342cc33c14ab83044a67561ef924c33dadb060761972","src/storage.rs":"e3ee12bbaecb754eced07b2f4bcd034b84161c5dcd6dc5cbe62ebc47a92f44d2","src/store.rs":"30d854aa7ad1ee3a3cac683a1ae0b9fb3833c8d90537beafcd3e4b24f6e7c6e8","src/sync/bridge.rs":"18d3a7913a030b598d4b6cbd5b7e2ab4cef4cc7ea964f5bc84d7fb2f28787529","src/sync/engine.rs":"73007423f2a22314a034ac660aa65bd9c50e8aa850c445a66604486280067843","src/sync/mod.rs":"09ba3c87f1174a243bf5aaa481effd18929d54359ceb9b23ccb2c32ee3482f34","src/sync/record.rs":"eef6751c209d039958afbe245ddb006cfdf6b8b6b47f925f69c552b832b87922","src/tabs.udl":"abb9f81705ee7ac277a1696b224404388a793301f973718322e9aa07538f1bc4","uniffi.toml":"70a41bac1bbbde7a571f1b023f22636337ca3bffd6891dd67596fe13ab98b2f6"},"package":null} {"files":{"Cargo.toml":"ffc7a4b8f8d8df651cdf9de08c1da761554c5bd615c215ba6ebbdd8920b6b04c","README.md":"c48b8f391ef822c4f3971b5f453a1e7b43bea232752d520460d2f04803aead1a","build.rs":"33e61b811b19ed2b58e319cc65d5988bed258d2c4fea2d706301184c59847a0f","src/error.rs":"6e5fd48a3f228d37977881a3657f8635b1b37e3b16d91ac2d8476174172a2a74","src/lib.rs":"2e2a7173ec3bf46065a60c34fbdf91254ff720d9d15955cb87b9019dafca7690","src/schema.rs":"510218d465c7d26d6b9f342cc33c14ab83044a67561ef924c33dadb060761972","src/storage.rs":"e3ee12bbaecb754eced07b2f4bcd034b84161c5dcd6dc5cbe62ebc47a92f44d2","src/store.rs":"30d854aa7ad1ee3a3cac683a1ae0b9fb3833c8d90537beafcd3e4b24f6e7c6e8","src/sync/bridge.rs":"18d3a7913a030b598d4b6cbd5b7e2ab4cef4cc7ea964f5bc84d7fb2f28787529","src/sync/engine.rs":"73007423f2a22314a034ac660aa65bd9c50e8aa850c445a66604486280067843","src/sync/mod.rs":"09ba3c87f1174a243bf5aaa481effd18929d54359ceb9b23ccb2c32ee3482f34","src/sync/record.rs":"eef6751c209d039958afbe245ddb006cfdf6b8b6b47f925f69c552b832b87922","src/tabs.udl":"abb9f81705ee7ac277a1696b224404388a793301f973718322e9aa07538f1bc4","uniffi.toml":"70a41bac1bbbde7a571f1b023f22636337ca3bffd6891dd67596fe13ab98b2f6"},"package":null}

View File

@@ -51,7 +51,7 @@ path = "../support/interrupt"
path = "../support/payload" path = "../support/payload"
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = [ features = [
"bundled", "bundled",
"unlock_notify", "unlock_notify",

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"975c09d26dbae7df6821539bec208a14954a4268a3c4b1e7ed31b78073628de5","src/lib.rs":"0ce1fe3683f2285fea2d67975e53d121b69c23bf901a5b1d428919e5ce67a7ba"},"package":null} {"files":{"Cargo.toml":"4959f4736aa0763fccbebd9c10bccd333044f26ca277958ecec96abe61cf4eff","src/lib.rs":"0ce1fe3683f2285fea2d67975e53d121b69c23bf901a5b1d428919e5ce67a7ba"},"package":null}

View File

@@ -33,7 +33,7 @@ serde_derive = "1"
serde_json = "1" serde_json = "1"
[dependencies.rusqlite] [dependencies.rusqlite]
version = "0.31.0" version = "0.33.0"
features = [ features = [
"functions", "functions",
"bundled", "bundled",

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"e086db21f065690c0cd49a3c4a8766bcc005fa7f13d8dd229a9af18d9d3fac94","README.md":"821cac7eb5b963fc3f3fe21dd890427ab2bbf335cb25cbae89b713b3350687c5","build.rs":"f4ff15cd54890d3e3636e77a0458ba9a8882f271ccb0056a0bbae1975cdd75d5","sql/create_schema.sql":"a17311a407ec10e033886b7125da4c8b84bc6d761f6b28edc9594de430e1d964","sql/create_sync_temp_tables.sql":"860ede362c94feb47d85522553fa2852f9bdb9f9b025d6438dd5dee3d4acd527","sql/tests/create_schema_v1.sql":"77cf0c90eaac3e1aea626537147e1b8ec349b68d6076c92fa7ae402aac613050","src/api.rs":"6a3c3e09797df06165091a3d66e3830febb63bd901250f89f7d6886ba0f408cd","src/db.rs":"9676325b259faadecfc28180d43f8b0a640a1204c2783fc626137eee62a9089b","src/error.rs":"10d99e3dc6a38951456c0fac7e46fb4f441e976b47fdddea257badbc66b8702d","src/ffi.rs":"f66a81393bebe7a4b7e7960cb426df106ff1f02bfebcaa6e335b4b8b56c5c936","src/lib.rs":"e00636eb57498ab015387b08ffe64618dca31e95977e60be624aa259d7dfe4b5","src/migration.rs":"a87a9628f31a4b5a1d1610f80fb37ddb8f94c28a9455980bd5153198d1d7aa2a","src/schema.rs":"d90556dcfa5784a2d3e9432968b6eed60630e3bff5978d73abd8da2b4c71ea63","src/store.rs":"a898492e4a53472414e114ad275bf6a750313a228e589814d73c803f6ce59288","src/sync/bridge.rs":"14d095bc67e511297b833e279912f61dd67993a877be941cc058afe9017cb058","src/sync/incoming.rs":"5899c880810968e1e99f4b2de5ea1eb9d0886643eea85c851571e4ac6f2eca08","src/sync/mod.rs":"75091c8f3138fa5585352b5ea7e5967088e76b1857d24cc02d3e142c0ee9e89d","src/sync/outgoing.rs":"e1577ceef9d1d87c0a0985cad16bc13938dc2144dd0befeb7aca2c97375e7ee7","src/sync/sync_tests.rs":"f999b9acfb95604e4b3b981a29527a490b64e39026ea9d9668418912cda54536","src/webext-storage.udl":"a37a5c796bcdc71b61dbb189a8801bbff9e67bf81aebb489db0e7fcafc58521d","uniffi.toml":"beeec89c2f877eb89be0090dc304dbc7c74e787385e7459bad78c6165bb66791"},"package":null} {"files":{"Cargo.toml":"593176ab8f1999a5d71dedac7a50e7b0b66815807f630a50ace84948bd1c6838","README.md":"821cac7eb5b963fc3f3fe21dd890427ab2bbf335cb25cbae89b713b3350687c5","build.rs":"f4ff15cd54890d3e3636e77a0458ba9a8882f271ccb0056a0bbae1975cdd75d5","sql/create_schema.sql":"a17311a407ec10e033886b7125da4c8b84bc6d761f6b28edc9594de430e1d964","sql/create_sync_temp_tables.sql":"860ede362c94feb47d85522553fa2852f9bdb9f9b025d6438dd5dee3d4acd527","sql/tests/create_schema_v1.sql":"77cf0c90eaac3e1aea626537147e1b8ec349b68d6076c92fa7ae402aac613050","src/api.rs":"6a3c3e09797df06165091a3d66e3830febb63bd901250f89f7d6886ba0f408cd","src/db.rs":"9676325b259faadecfc28180d43f8b0a640a1204c2783fc626137eee62a9089b","src/error.rs":"10d99e3dc6a38951456c0fac7e46fb4f441e976b47fdddea257badbc66b8702d","src/ffi.rs":"f66a81393bebe7a4b7e7960cb426df106ff1f02bfebcaa6e335b4b8b56c5c936","src/lib.rs":"e00636eb57498ab015387b08ffe64618dca31e95977e60be624aa259d7dfe4b5","src/migration.rs":"a87a9628f31a4b5a1d1610f80fb37ddb8f94c28a9455980bd5153198d1d7aa2a","src/schema.rs":"d90556dcfa5784a2d3e9432968b6eed60630e3bff5978d73abd8da2b4c71ea63","src/store.rs":"a898492e4a53472414e114ad275bf6a750313a228e589814d73c803f6ce59288","src/sync/bridge.rs":"14d095bc67e511297b833e279912f61dd67993a877be941cc058afe9017cb058","src/sync/incoming.rs":"5899c880810968e1e99f4b2de5ea1eb9d0886643eea85c851571e4ac6f2eca08","src/sync/mod.rs":"75091c8f3138fa5585352b5ea7e5967088e76b1857d24cc02d3e142c0ee9e89d","src/sync/outgoing.rs":"e1577ceef9d1d87c0a0985cad16bc13938dc2144dd0befeb7aca2c97375e7ee7","src/sync/sync_tests.rs":"f999b9acfb95604e4b3b981a29527a490b64e39026ea9d9668418912cda54536","src/webext-storage.udl":"a37a5c796bcdc71b61dbb189a8801bbff9e67bf81aebb489db0e7fcafc58521d","uniffi.toml":"beeec89c2f877eb89be0090dc304dbc7c74e787385e7459bad78c6165bb66791"},"package":null}

Some files were not shown because too many files have changed in this diff Show More