| //! Adaptation of https://sqlite.org/loadext.html#programming_loadable_extensions |
| use std::os::raw::{c_char, c_int}; |
| |
| use rusqlite::ffi; |
| use rusqlite::functions::FunctionFlags; |
| use rusqlite::types::{ToSqlOutput, Value}; |
| use rusqlite::{Connection, Result}; |
| |
| /// # 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! |
| /// ``` |
| #[allow(clippy::not_unsafe_ptr_arg_deref)] |
| #[no_mangle] |
| 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 { |
| Connection::extension_init2(db, pz_err_msg, p_api, extension_init) |
| } |
| |
| fn extension_init(db: Connection) -> Result<bool> { |
| db.create_scalar_function( |
| "rusqlite_test_function", |
| 0, |
| FunctionFlags::SQLITE_DETERMINISTIC, |
| |_ctx| { |
| Ok(ToSqlOutput::Owned(Value::Text( |
| "Rusqlite extension loaded correctly!".to_string(), |
| ))) |
| }, |
| )?; |
| rusqlite::trace::log(ffi::SQLITE_WARNING, "Rusqlite extension initialized"); |
| Ok(false) |
| } |