Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "sqlsrv" -version = "0.1.0" +version = "0.1.1" edition = "2021" license = "0BSD" categories = [ "database" ] keywords = [ "sqlite", "server" ] repository = "https://repos.qrnch.tech/pub/sqlsrv" Index: src/lib.rs ================================================================== --- src/lib.rs +++ src/lib.rs @@ -25,11 +25,12 @@ mod err; mod rawhook; mod wrconn; use std::{ - mem::ManuallyDrop, num::NonZeroUsize, path::Path, str::FromStr, sync::Arc + fmt, mem::ManuallyDrop, num::NonZeroUsize, path::Path, str::FromStr, + sync::Arc }; use parking_lot::{Condvar, Mutex}; use r2d2::{CustomizeConnection, PooledConnection}; @@ -103,20 +104,36 @@ /// /// If this is `None` then all pages will be processed. npages: Option } +type RoRegCb = dyn Fn(&Connection) + Send + Sync; +type RwRegCb = dyn Fn(&Connection); + /// Read-only connection. -#[derive(Debug)] -struct RoConn {} +struct RoConn { + regfuncs: Option> +} + +impl fmt::Debug for RoConn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RoConn {{}}") + } +} + impl CustomizeConnection for RoConn { fn on_acquire( &self, conn: &mut rusqlite::Connection ) -> Result<(), rusqlite::Error> { conn.pragma_update(None, "foreign_keys", "ON")?; + + if let Some(ref regfuncs) = self.regfuncs { + regfuncs(conn); + } + Ok(()) } fn on_release(&self, _conn: rusqlite::Connection) {} } @@ -138,11 +155,13 @@ full_vacuum: bool, max_readers: usize, #[cfg(feature = "tpool")] thrdpool: ThrdPool, autoclean: Option, - hook: Option> + hook: Option>, + rofuncs: Option>, + rwfuncs: Option> } /// Internal methods. impl Builder { /// Open the writer connection. @@ -166,16 +185,18 @@ Ok(()) } fn create_ro_pool( &self, - fname: &Path + fname: &Path, + regfuncs: Option> ) -> Result, r2d2::Error> { let fl = OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_NO_MUTEX; let manager = SqliteConnectionManager::file(fname).with_flags(fl); - let roconn_initterm = RoConn {}; + let regfuncs = regfuncs.map(Arc::from); + let roconn_initterm = RoConn { regfuncs }; let max_readers = u32::try_from(self.max_readers).unwrap(); r2d2::Pool::builder() .max_size(max_readers) .connection_customizer(Box::new(roconn_initterm)) .build(manager) @@ -211,11 +232,13 @@ full_vacuum: false, max_readers: 2, #[cfg(feature = "tpool")] thrdpool: ThrdPool::default(), autoclean: None, - hook: None + hook: None, + rofuncs: None, + rwfuncs: None } } /// Trigger a full vacuum when initializing the connection pool. /// @@ -310,13 +333,29 @@ dirt_threshold: dirt_watermark, npages }); self } + + pub fn register_ro_functions(mut self, f: F) -> Self + where + F: Fn(&Connection) + Send + Sync + 'static + { + self.rofuncs = Some(Box::new(f)); + self + } + + pub fn register_rw_functions(mut self, f: F) -> Self + where + F: Fn(&Connection) + 'static + { + self.rwfuncs = Some(Box::new(f)); + self + } /// Construct a connection pool. - pub fn build

(self, fname: P) -> Result + pub fn build

(mut self, fname: P) -> Result where P: AsRef { // ToDo: Use std::path::absolute() once stabilized let fname = fname.as_ref(); @@ -327,10 +366,15 @@ // // This must be done before creating the read-only connection pool, because // at that point the database file must already exist. // let mut conn = self.open_writer(fname)?; + + // Register read/write connection functions + if let Some(ref regfn) = self.rwfuncs { + regfn(&conn); + } // // Perform schema initialization. // // This must be done after auto_vacuum is set, because auto_vacuum requires @@ -363,11 +407,12 @@ let tpool = self.init_tpool(); // // Set up connection pool for read-only connections. // - let rpool = self.create_ro_pool(fname)?; + let rofuncs = self.rofuncs.take(); + let rpool = self.create_ro_pool(fname, rofuncs)?; // // Prepare shared data // let iconn = InnerWrConn { conn, dirt: 0 }; @@ -396,11 +441,11 @@ /// a raw update hook. /// /// # Panic /// This method will panic if a hook has been added to the Builder. pub fn build_with_changelog_hook( - self, + mut self, fname: P, hook: Box + Send> ) -> Result where P: AsRef, @@ -422,10 +467,15 @@ // // This must be done before creating the read-only connection pool, because // at that point the database file must already exist. // let mut conn = self.open_writer(fname)?; + + // Register read/write connection functions + if let Some(ref regfn) = self.rwfuncs { + regfn(&conn); + } // // Perform schema initialization. // // This must be done after auto_vacuum is set, because auto_vacuum requires @@ -456,11 +506,12 @@ let tpool = self.init_tpool(); // // Set up connection pool for read-only connections. // - let rpool = self.create_ro_pool(fname)?; + let rofuncs = self.rofuncs.take(); + let rpool = self.create_ro_pool(fname, rofuncs)?; // // Prepare shared data // let iconn = InnerWrConn { conn, dirt: 0 }; Index: www/changelog.md ================================================================== --- www/changelog.md +++ www/changelog.md @@ -1,17 +1,28 @@ # Change Log ## [Unreleased] -[Details](/vdiff?from=sqlsrv-0.1.0&to=trunk) +[Details](/vdiff?from=sqlsrv-0.1.1&to=trunk) ### Added ### Changed ### Removed +--- + +## [0.1.1] - 2024-01-24 + +[Details](/vdiff?from=sqlsrv-0.1.0&to=sqlsrv-0.1.1) + +### Added + +- Add ability to register callback functions for registering SQL functions for + both read-only and read/write connections. + --- ## [0.1.0] - 2024-01-21 [Details](/vdiff?from=sqlsrv-0.0.4&to=sqlsrv-0.1.0)