diff --git a/examples/loadable_extension.rs b/examples/loadable_extension.rs index 5a197d3..6d623b5 100644 --- a/examples/loadable_extension.rs +++ b/examples/loadable_extension.rs @@ -20,21 +20,15 @@ use rusqlite::{to_sqlite_error, Connection, Result}; /// ``` #[allow(clippy::not_unsafe_ptr_arg_deref)] #[no_mangle] -pub extern "C" fn sqlite3_extension_init( +pub unsafe extern "C" fn sqlite3_extension_init( db: *mut ffi::sqlite3, pz_err_msg: *mut *mut c_char, p_api: *mut ffi::sqlite3_api_routines, ) -> c_int { - if p_api.is_null() { - 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 + Connection::extension_init2(db, pz_err_msg, p_api, extension_init) } -fn extension_init(db: *mut ffi::sqlite3, p_api: *mut ffi::sqlite3_api_routines) -> Result<()> { - let db = unsafe { Connection::extension_init2(db, p_api)? }; +fn extension_init(db: Connection) -> Result { db.create_scalar_function( "rusqlite_test_function", 0, @@ -46,5 +40,5 @@ fn extension_init(db: *mut ffi::sqlite3, p_api: *mut ffi::sqlite3_api_routines) }, )?; rusqlite::trace::log(ffi::SQLITE_WARNING, "Rusqlite extension initialized"); - Ok(()) + Ok(false) } diff --git a/src/lib.rs b/src/lib.rs index 1df6e2b..d9c3ee6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -952,15 +952,31 @@ impl Connection { }) } - /// 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 returns `Ok(true)`. + /// # Safety + /// * Results are undefined if `init` does not just register features. #[cfg(feature = "loadable_extension")] #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))] pub unsafe fn extension_init2( db: *mut ffi::sqlite3, + pz_err_msg: *mut *mut c_char, p_api: *mut ffi::sqlite3_api_routines, - ) -> Result { - ffi::rusqlite_extension_init2(p_api)?; - Connection::from_handle(db) + init: fn(Connection) -> Result, + ) -> c_int { + if p_api.is_null() { + return ffi::SQLITE_ERROR; + } + match ffi::rusqlite_extension_init2(p_api) + .map_err(Error::from) + .and(Connection::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.