From c70d14854282ccddcf9c42d2078eebad54eb7c86 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 14 Jan 2020 08:11:36 -0800 Subject: [PATCH] Remove most of the code using `feature=bundled` as a version check --- Cargo.toml | 5 +++-- README.md | 6 ++++++ libsqlite3-sys/Cargo.toml | 7 +++++-- libsqlite3-sys/build.rs | 15 +++++++-------- src/functions.rs | 4 ++-- src/inner_connection.rs | 2 +- src/lib.rs | 14 +++++++------- src/pragma.rs | 4 ++-- src/raw_statement.rs | 4 ++-- src/statement.rs | 12 ++++++------ src/vtab/mod.rs | 18 ++++++++++++------ 11 files changed, 53 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d83372f..73cd294 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ collation = [] functions = ["libsqlite3-sys/min_sqlite_version_3_7_7"] # sqlite3_log: 3.6.23 (2010-03-09) trace = ["libsqlite3-sys/min_sqlite_version_3_6_23"] -bundled = ["libsqlite3-sys/bundled"] +bundled = ["libsqlite3-sys/bundled", "modern_sqlite"] buildtime_bindgen = ["libsqlite3-sys/buildtime_bindgen"] limits = [] hooks = [] @@ -55,6 +55,7 @@ window = ["functions"] series = ["vtab"] # check for invalid query. extra_check = [] +modern_sqlite = ["libsqlite3-sys/bundled_bindings"] [dependencies] time = "0.1.0" @@ -93,7 +94,7 @@ name = "deny_single_threaded_sqlite_config" name = "vtab" [package.metadata.docs.rs] -features = [ "backup", "blob", "chrono", "collation", "functions", "limits", "load_extension", "serde_json", "trace", "url", "vtab", "window" ] +features = [ "backup", "blob", "chrono", "collation", "functions", "limits", "load_extension", "serde_json", "trace", "url", "vtab", "window", "modern_sqlite" ] all-features = false no-default-features = true default-target = "x86_64-unknown-linux-gnu" diff --git a/README.md b/README.md index 6844d28..965a1d9 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,12 @@ bundled version of SQLite. If you need other specific pregenerated binding versions, please file an issue. If you want to run `bindgen` at buildtime to produce your own bindings, use the `buildtime_bindgen` Cargo feature. +If you enable the `modern_sqlite` feature, we'll use the bindings we would have +included with the bundled build. You generally should have `buildtime_bindgen` +enabled if you turn this on, as otherwise you'll need to keep the version of +SQLite you link with in sync with what rusqlite would have bundled, (usually the +most recent release of sqlite). Failing to do this will cause a runtime error. + ## Author John Gallagher, johnkgallagher@gmail.com diff --git a/libsqlite3-sys/Cargo.toml b/libsqlite3-sys/Cargo.toml index 452bb28..1c3eda1 100644 --- a/libsqlite3-sys/Cargo.toml +++ b/libsqlite3-sys/Cargo.toml @@ -13,14 +13,17 @@ categories = ["external-ffi-bindings"] [features] default = ["min_sqlite_version_3_6_8"] -bundled = ["cc"] -bundled-windows = ["cc"] +bundled = ["cc", "bundled_bindings"] +bundled-windows = ["cc", "bundled_bindings"] buildtime_bindgen = ["bindgen", "pkg-config", "vcpkg"] sqlcipher = [] min_sqlite_version_3_6_8 = ["pkg-config", "vcpkg"] min_sqlite_version_3_6_23 = ["pkg-config", "vcpkg"] min_sqlite_version_3_7_7 = ["pkg-config", "vcpkg"] min_sqlite_version_3_7_16 = ["pkg-config", "vcpkg"] +# Bundle only the bindings file. Note that this does nothing if +# `buildtime_bindgen` is enabled. +bundled_bindings = [] # sqlite3_unlock_notify >= 3.6.12 unlock_notify = [] # 3.13.0 diff --git a/libsqlite3-sys/build.rs b/libsqlite3-sys/build.rs index fcb27b8..bab6d1e 100644 --- a/libsqlite3-sys/build.rs +++ b/libsqlite3-sys/build.rs @@ -166,18 +166,17 @@ mod build_linked { pub fn main(_out_dir: &str, out_path: &Path) { let header = find_sqlite(); if cfg!(any( + feature = "bundled_bindings", feature = "bundled", all(windows, feature = "bundled-windows") )) && !cfg!(feature = "buildtime_bindgen") { - // We can only get here if `bundled` and `sqlcipher` were both - // specified (and `builtime_bindgen` was not). In order to keep - // `rusqlite` relatively clean we hide the fact that `bundled` can - // be ignored in some cases, and just use the bundled bindings, even - // though the library we found might not match their version. - // Ideally we'd perform a version check here, but doing so is rather - // tricky, since we might not have access to executables (and - // moreover, we might be cross compiling). + // Generally means the `bundled_bindings` feature is enabled + // (there's also an edge case where we get here involving + // sqlcipher). In either case most users are better off with turning + // on buildtime_bindgen instead, but this is still supported as we + // have runtime version checks and there are good reasons to not + // want to run bindgen. std::fs::copy("sqlite3/bindgen_bundled_version.rs", out_path) .expect("Could not copy bindings to output directory"); } else { diff --git a/src/functions.rs b/src/functions.rs index e8bd1a6..98056c1 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -81,11 +81,11 @@ unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) { // an explicit feature check for that, and this doesn't really warrant one. // We'll use the extended code if we're on the bundled version (since it's // at least 3.17.0) and the normal constraint error code if not. - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] fn constraint_error_code() -> i32 { ffi::SQLITE_CONSTRAINT_FUNCTION } - #[cfg(not(feature = "bundled"))] + #[cfg(not(feature = "modern_sqlite"))] fn constraint_error_code() -> i32 { ffi::SQLITE_CONSTRAINT } diff --git a/src/inner_connection.rs b/src/inner_connection.rs index d5d4e25..9e291c9 100644 --- a/src/inner_connection.rs +++ b/src/inner_connection.rs @@ -281,7 +281,7 @@ impl InnerConnection { unsafe { ffi::sqlite3_get_autocommit(self.db()) != 0 } } - #[cfg(feature = "bundled")] // 3.8.6 + #[cfg(feature = "modern_sqlite")] // 3.8.6 pub fn is_busy(&self) -> bool { let db = self.db(); unsafe { diff --git a/src/lib.rs b/src/lib.rs index 1c8f9bb..08378d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -295,7 +295,7 @@ pub enum DatabaseName<'a> { feature = "backup", feature = "blob", feature = "session", - feature = "bundled" + feature = "modern_sqlite" ))] impl DatabaseName<'_> { fn to_cstring(&self) -> Result { @@ -750,7 +750,7 @@ impl Connection { } /// Determine if all associated prepared statements have been reset. - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] // 3.8.6 pub fn is_busy(&self) -> bool { self.db.borrow().is_busy() } @@ -847,7 +847,7 @@ impl InterruptHandle { } } -#[cfg(feature = "bundled")] // 3.7.10 +#[cfg(feature = "modern_sqlite")] // 3.7.10 unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option { let db_name = DatabaseName::Main.to_cstring().unwrap(); let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr()); @@ -857,7 +857,7 @@ unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option { CStr::from_ptr(db_filename).to_str().ok().map(PathBuf::from) } } -#[cfg(not(feature = "bundled"))] +#[cfg(not(feature = "modern_sqlite"))] unsafe fn db_filename(_: *mut ffi::sqlite3) -> Option { None } @@ -1302,7 +1302,7 @@ mod test { } #[test] - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] fn test_is_busy() { let db = checked_memory_handle(); assert!(!db.is_busy()); @@ -1331,11 +1331,11 @@ mod test { fn test_notnull_constraint_error() { // extended error codes for constraints were added in SQLite 3.7.16; if we're // running on our bundled version, we know the extended error code exists. - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] fn check_extended_code(extended_code: c_int) { assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL); } - #[cfg(not(feature = "bundled"))] + #[cfg(not(feature = "modern_sqlite"))] fn check_extended_code(_extended_code: c_int) {} let db = checked_memory_handle(); diff --git a/src/pragma.rs b/src/pragma.rs index 52d334a..b115f8f 100644 --- a/src/pragma.rs +++ b/src/pragma.rs @@ -326,7 +326,7 @@ mod test { } #[test] - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] fn pragma_func_query_value() { use crate::NO_PARAMS; @@ -379,7 +379,7 @@ mod test { } #[test] - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] fn pragma_func() { let db = Connection::open_in_memory().unwrap(); let mut table_info = db.prepare("SELECT * FROM pragma_table_info(?)").unwrap(); diff --git a/src/raw_statement.rs b/src/raw_statement.rs index 67d2a67..8d943ba 100644 --- a/src/raw_statement.rs +++ b/src/raw_statement.rs @@ -117,13 +117,13 @@ impl RawStatement { r } - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] // 3.7.4 pub fn readonly(&self) -> bool { unsafe { ffi::sqlite3_stmt_readonly(self.0) != 0 } } /// `CStr` must be freed - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] // 3.14.0 pub unsafe fn expanded_sql(&self) -> Option<&CStr> { let ptr = ffi::sqlite3_expanded_sql(self.0); if ptr.is_null() { diff --git a/src/statement.rs b/src/statement.rs index 5533897..e421832 100644 --- a/src/statement.rs +++ b/src/statement.rs @@ -533,13 +533,13 @@ impl Statement<'_> { self.conn.decode_result(stmt.finalize()) } - #[cfg(not(feature = "bundled"))] + #[cfg(not(feature = "modern_sqlite"))] #[inline] fn check_readonly(&self) -> Result<()> { Ok(()) } - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] #[inline] fn check_readonly(&self) -> Result<()> { /*if !self.stmt.readonly() { does not work for PRAGMA @@ -548,7 +548,7 @@ impl Statement<'_> { Ok(()) } - #[cfg(all(feature = "bundled", feature = "extra_check"))] + #[cfg(all(feature = "modern_sqlite", feature = "extra_check"))] #[inline] fn check_update(&self) -> Result<()> { if self.column_count() > 0 || self.stmt.readonly() { @@ -557,7 +557,7 @@ impl Statement<'_> { Ok(()) } - #[cfg(all(not(feature = "bundled"), feature = "extra_check"))] + #[cfg(all(not(feature = "modern_sqlite"), feature = "extra_check"))] #[inline] fn check_update(&self) -> Result<()> { if self.column_count() > 0 { @@ -574,7 +574,7 @@ impl Statement<'_> { /// Returns a string containing the SQL text of prepared statement with /// bound parameters expanded. - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] pub fn expanded_sql(&self) -> Option { unsafe { match self.stmt.expanded_sql() { @@ -1019,7 +1019,7 @@ mod test { } #[test] - #[cfg(feature = "bundled")] + #[cfg(feature = "modern_sqlite")] fn test_expanded_sql() { let db = Connection::open_in_memory().unwrap(); let stmt = db.prepare("SELECT ?").unwrap(); diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index e5f7365..d3b58f8 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -70,6 +70,14 @@ pub struct Module { unsafe impl Send for Module {} unsafe impl Sync for Module {} +// Used as a trailing initializer for sqlite3_module -- this way we avoid having +// the build fail if buildtime_bindgen is on, our bindings have +// `sqlite3_module::xShadowName`, but vtab_v3 wasn't specified. +fn zeroed_module() -> ffi::sqlite3_module { + // This is safe, as bindgen-generated structs are allowed to be zeroed. + unsafe { std::mem::MaybeUninit::zeroed().assume_init() } +} + /// Create a read-only virtual table implementation. /// /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). @@ -100,8 +108,7 @@ pub fn read_only_module(version: c_int) -> Module { xSavepoint: None, xRelease: None, xRollbackTo: None, - #[cfg(any(feature = "bundled", feature = "vtab_v3"))] - xShadowName: None, + .. zeroed_module() }; Module { base: ffi_module, @@ -140,8 +147,7 @@ pub fn eponymous_only_module(version: c_int) -> Module { xSavepoint: None, xRelease: None, xRollbackTo: None, - #[cfg(any(feature = "bundled", feature = "vtab_v3"))] - xShadowName: None, + .. zeroed_module() }; Module { base: ffi_module, @@ -309,8 +315,8 @@ impl IndexInfo { } } - /// Estimated number of rows returned - #[cfg(feature = "bundled")] // SQLite >= 3.8.2 + /// Estimated number of rows returned. + #[cfg(feature = "modern_sqlite")] // SQLite >= 3.8.2 pub fn set_estimated_rows(&mut self, estimated_rows: i64) { unsafe { (*self.0).estimatedRows = estimated_rows;