diff --git a/libsqlite3-sys/build.rs b/libsqlite3-sys/build.rs index 87998ef..e91f8c6 100644 --- a/libsqlite3-sys/build.rs +++ b/libsqlite3-sys/build.rs @@ -134,8 +134,14 @@ mod build { } // Allow users to specify where to find SQLite. if let Ok(dir) = env::var(format!("{}_LIB_DIR", env_prefix())) { - println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib); - println!("cargo:rustc-link-search={}", dir); + // Try to use pkg-config to determine link commands + let pkgconfig_path = Path::new(&dir).join("pkgconfig"); + env::set_var("PKG_CONFIG_PATH", pkgconfig_path); + if let Err(_) = pkg_config::Config::new().probe(link_lib) { + // Otherwise just emit the bare minimum link commands. + println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib); + println!("cargo:rustc-link-search={}", dir); + } return HeaderLocation::FromEnvironment; } diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..36337f0 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,88 @@ +//! Configure database connections + +use std::os::raw::c_int; + +use crate::ffi; +use crate::{Connection, Result}; + +/// Database Connection Configuration Options +#[repr(i32)] +#[allow(non_snake_case, non_camel_case_types)] +pub enum DbConfig { + //SQLITE_DBCONFIG_MAINDBNAME = 1000, /* const char* */ + //SQLITE_DBCONFIG_LOOKASIDE = 1001, /* void* int int */ + SQLITE_DBCONFIG_ENABLE_FKEY = 1002, + SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003, + SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004, // 3.12.0 + //SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005, + SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1006, + SQLITE_DBCONFIG_ENABLE_QPSG = 1007, // 3.20.0 + SQLITE_DBCONFIG_TRIGGER_EQP = 1008, + //SQLITE_DBCONFIG_RESET_DATABASE = 1009, + SQLITE_DBCONFIG_DEFENSIVE = 1010, +} + +impl Connection { + /// Returns the current value of a `config`. + /// + /// - SQLITE_DBCONFIG_ENABLE_FKEY: return `false` or `true` to indicate whether FK enforcement is off or on + /// - SQLITE_DBCONFIG_ENABLE_TRIGGER: return `false` or `true` to indicate whether triggers are disabled or enabled + /// - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: return `false` or `true` to indicate whether fts3_tokenizer are disabled or enabled + /// - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: return `false` to indicate checkpoints-on-close are not disabled or `true` if they are + /// - SQLITE_DBCONFIG_ENABLE_QPSG: return `false` or `true` to indicate whether the QPSG is disabled or enabled + /// - SQLITE_DBCONFIG_TRIGGER_EQP: return `false` to indicate output-for-trigger are not disabled or `true` if it is + pub fn db_config(&self, config: DbConfig) -> Result { + let c = self.db.borrow(); + unsafe { + let mut val = 0; + check!(ffi::sqlite3_db_config( + c.db(), + config as c_int, + -1, + &mut val + )); + Ok(val != 0) + } + } + + /// Make configuration changes to a database connection + /// + /// - SQLITE_DBCONFIG_ENABLE_FKEY: `false` to disable FK enforcement, `true` to enable FK enforcement + /// - SQLITE_DBCONFIG_ENABLE_TRIGGER: `false` to disable triggers, `true` to enable triggers + /// - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: `false` to disable fts3_tokenizer(), `true` to enable fts3_tokenizer() + /// - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: `false` (the default) to enable checkpoints-on-close, `true` to disable them + /// - SQLITE_DBCONFIG_ENABLE_QPSG: `false` to disable the QPSG, `true` to enable QPSG + /// - SQLITE_DBCONFIG_TRIGGER_EQP: `false` to disable output for trigger programs, `true` to enable it + pub fn set_db_config(&self, config: DbConfig, new_val: bool) -> Result { + let c = self.db.borrow_mut(); + unsafe { + let mut val = 0; + check!(ffi::sqlite3_db_config( + c.db(), + config as c_int, + if new_val { 1 } else { 0 }, + &mut val + )); + Ok(val != 0) + } + } +} + +#[cfg(test)] +mod test { + use super::DbConfig; + use crate::Connection; + + #[test] + fn test_db_config() { + let db = Connection::open_in_memory().unwrap(); + + let opposite = !db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY).unwrap(); + assert_eq!(db.set_db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY, opposite), Ok(opposite)); + assert_eq!(db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY), Ok(opposite)); + + let opposite = !db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER).unwrap(); + assert_eq!(db.set_db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER, opposite), Ok(opposite)); + assert_eq!(db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER), Ok(opposite)); + } +} diff --git a/src/lib.rs b/src/lib.rs index 6a72e12..f1e7764 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,16 +100,18 @@ pub use crate::transaction::{DropBehavior, Savepoint, Transaction, TransactionBe pub use crate::types::ToSql; pub use crate::version::*; +#[macro_use] +mod error; + #[cfg(feature = "backup")] pub mod backup; #[cfg(feature = "blob")] pub mod blob; mod busy; mod cache; +pub mod config; #[cfg(any(feature = "functions", feature = "vtab"))] mod context; -#[macro_use] -mod error; #[cfg(feature = "functions")] pub mod functions; #[cfg(feature = "hooks")] diff --git a/src/row.rs b/src/row.rs index 0ae8f3d..180e37d 100644 --- a/src/row.rs +++ b/src/row.rs @@ -148,11 +148,11 @@ impl<'stmt> Row<'stmt> { /// Panics if calling `row.get_checked(idx)` would return an error, /// including: /// - /// * If the underlying SQLite column type is not a valid type as a - /// source for `T` - /// * If the underlying SQLite integral value is outside the range - /// representable by `T` - /// * If `idx` is outside the range of columns in the returned query + /// * If the underlying SQLite column type is not a valid type as a + /// source for `T` + /// * If the underlying SQLite integral value is outside the range + /// representable by `T` + /// * If `idx` is outside the range of columns in the returned query pub fn get(&self, idx: I) -> T { self.get_checked(idx).unwrap() } @@ -224,8 +224,8 @@ impl<'stmt> Row<'stmt> { /// Panics if calling `row.get_raw_checked(idx)` would return an error, /// including: /// - /// * If `idx` is outside the range of columns in the returned query. - /// * If `idx` is not a valid column name for this row. + /// * If `idx` is outside the range of columns in the returned query. + /// * If `idx` is not a valid column name for this row. pub fn get_raw(&self, idx: I) -> ValueRef<'_> { self.get_raw_checked(idx).unwrap() }