//! 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 {
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)
}