forked from rusqlite/rusqlite
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
40 changed files
with
55,884 additions
and
5,264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Contributors | ||
============ | ||
|
||
"The rusqlite developers" referred to in the copyright notice in the LICENSE | ||
file is intended to include all individual developers who have contributed | ||
code to the rusqlite project. | ||
|
||
In addition, it includes the following organisations who retain copyright in | ||
portions of the code (this list is not intended to be comprehensive): | ||
- Genomics plc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
example-embedded-extension.h | ||
example-c-host-extension/libexample_c_host_extension.so | ||
target/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[package] | ||
name = "example-embedded-extension" | ||
version = "0.0.1" | ||
authors = ["The rusqlite developers"] | ||
edition = "2018" | ||
repository = "https://github.com/rusqlite/rusqlite" | ||
description = "Example embedded extension to demonstrate and test rusqlite feature loadable_extension_embedded" | ||
license = "MIT" | ||
keywords = ["sqlite", "extension"] | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
|
||
[dependencies.rusqlite] | ||
path = ".." | ||
default-features = false | ||
features = ["loadable_extension_embedded", "vtab", "functions", "bundled"] | ||
|
||
[build-dependencies] | ||
cbindgen = "0.18.0" | ||
|
||
[workspace] | ||
members = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
extern crate cbindgen; | ||
|
||
use std::env; | ||
|
||
fn main() { | ||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); | ||
|
||
// generate bindings to be included by the host extension that embeds us | ||
cbindgen::Builder::new() | ||
.with_language(cbindgen::Language::C) | ||
.with_crate(crate_dir) | ||
.generate() | ||
.expect("Unable to generate bindings") | ||
.write_to_file("example-embedded-extension.h"); | ||
} |
22 changes: 22 additions & 0 deletions
22
example-embedded-extension/example-c-host-extension/example_c_host_extension.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// include the sqlite3 extension header and call macros as documented in https://sqlite.org/loadext.html | ||
#include "sqlite3ext.h" | ||
SQLITE_EXTENSION_INIT1 | ||
|
||
// include the cbindgen-generated bindings for the embedded extension | ||
#include "example-embedded-extension.h" | ||
|
||
// the extension entry point | ||
int sqlite3_examplechostextension_init( | ||
sqlite3 *db, | ||
char **pzErrMsg, | ||
const sqlite3_api_routines *pApi | ||
) { | ||
int rc = SQLITE_OK; | ||
SQLITE_EXTENSION_INIT2(pApi); | ||
|
||
// for this example, we essentially just pass through to the embedded | ||
// extension and return the result. | ||
rc = example_embedded_extension_init(db, pzErrMsg); | ||
|
||
return rc; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#!/bin/bash | ||
|
||
set -euf -o pipefail | ||
|
||
# the crate dir is where this script is located | ||
crate_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
|
||
# location of the cdylib embedded library within the target dir to be embedded within the c host extension | ||
example_embedded_extension_lib_dir="${crate_dir}/target/debug" | ||
example_embedded_extension_lib="example_embedded_extension" | ||
|
||
# location of the c host extension to be loaded by sqlite | ||
example_c_host_extension_dir="${crate_dir}/example-c-host-extension" | ||
example_c_host_extension="${example_c_host_extension_dir}/libexample_c_host_extension" # sqlite will try adding .so, .dll, .dylib to this on its own | ||
|
||
# expected output from vtable query | ||
expected_vtable_output="example_embedded_test_value" | ||
|
||
# expected output from function query | ||
expected_function_output="Example embedded extension loaded correctly!" | ||
|
||
# sqlite3 include dir (location of sqlite3ext.h) - can be set by SQLITE3_INCLUDE_DIR env var or defaults to bundled version | ||
sqlite3_include_dir=${SQLITE3_INCLUDE_DIR:-${crate_dir}/../libsqlite3-sys/sqlite3} | ||
|
||
>&2 echo "checking for sqlite3 shell" | ||
sqlite3_cmd=$(which sqlite3) | ||
>&2 echo "sqlite3 found: ${sqlite3_cmd}" | ||
|
||
# build the example-embedded-extension crate | ||
>&2 echo "building the example-embedded-extension crate in ${crate_dir}" | ||
(cd "${crate_dir}" && cargo build --all-targets --verbose) | ||
>&2 echo "successfully built the example-embedded-extension crate" | ||
|
||
# build the C-based host extension | ||
>&2 echo "building the example-c-host-extension" | ||
clang -g -fPIC -O2 -shared -I${sqlite3_include_dir} -I${crate_dir} -L${example_embedded_extension_lib_dir} -Wl,-rpath,${example_embedded_extension_lib_dir} -l${example_embedded_extension_lib} ${example_c_host_extension_dir}/example_c_host_extension.c -o ${example_c_host_extension}.so | ||
>&2 echo "successfully built the example-c-host-extension" | ||
|
||
>&2 echo "running sqlite3 (${sqlite3_cmd}) to test loadable_extension_embedded ${example_c_host_extension} vtable (embedded within C-based extension)" | ||
actual_vtable_output=$(${sqlite3_cmd} -cmd ".load ${example_c_host_extension}" :memory: "SELECT value FROM example_embedded LIMIT 1;") | ||
>&2 echo "sqlite3 command returned successfully from vtable test, checking output is as expected" | ||
test "${actual_vtable_output}" = "${expected_vtable_output}" && echo "OK" || (echo "vtable output '${actual_vtable_output}' was not as expected '${expected_vtable_output}'"; echo "FAIL"; exit 1) | ||
|
||
>&2 echo "running sqlite3 (${sqlite3_cmd}) to test loadable_extension_embedded ${example_c_host_extension} function (embedded within C-based extension)" | ||
actual_function_output=$(${sqlite3_cmd} -cmd ".load ${example_c_host_extension}" :memory: "SELECT example_embedded_test_function();") | ||
>&2 echo "sqlite3 command returned successfully from function test, checking output is as expected" | ||
test "${actual_function_output}" = "${expected_function_output}" && echo "OK" || (echo "function output '${actual_function_output}' was not as expected '${expected_function_output}'"; echo "FAIL"; exit 1) | ||
|
||
>&2 echo "All tests passed." | ||
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
use crate::ffi::loadable_extension_embedded_init; // required feature `loadable_extension_embedded` | ||
use std::marker::PhantomData; | ||
use std::os::raw::{c_char, c_int}; | ||
|
||
use rusqlite::vtab::{ | ||
eponymous_only_module, sqlite3_vtab, sqlite3_vtab_cursor, Context, IndexInfo, VTab, | ||
VTabConnection, VTabCursor, Values, | ||
}; | ||
use rusqlite::{ | ||
ffi, | ||
functions::FunctionFlags, | ||
types::{ToSqlOutput, Value}, | ||
}; | ||
use rusqlite::{to_sqlite_error, Connection, Result}; | ||
|
||
/// example_embedded_extension_init is the entry point for this library. | ||
/// | ||
/// This crate produces a cdylib that is intended to be embedded within | ||
/// (i.e. linked into) another library that implements the sqlite loadable | ||
/// extension entrypoint. | ||
/// | ||
/// In the case of this example code, refer to the `example-c-host-extension` | ||
/// C code to find where this entry point is invoked. | ||
/// | ||
/// Note that this interface is private between the host extension and this | ||
/// library - it can have any signature as long as it passes the *sqlite3 db | ||
/// pointer so we can use it to initialize our rusqlite::Connection. | ||
/// | ||
/// It does *not* have to return sqlite status codes (such as SQLITE_OK), we | ||
/// just do that here to keep the C extension simple. | ||
#[no_mangle] | ||
pub unsafe extern "C" fn example_embedded_extension_init( | ||
db: *mut ffi::sqlite3, | ||
pz_err_msg: *mut *mut c_char, | ||
) -> c_int { | ||
loadable_extension_embedded_init(); | ||
|
||
let res = example_embedded_init(db); | ||
if let Err(err) = res { | ||
return to_sqlite_error(&err, pz_err_msg); | ||
} | ||
|
||
ffi::SQLITE_OK | ||
} | ||
|
||
#[repr(C)] | ||
struct ExampleEmbeddedTab { | ||
/// Base class. Must be first | ||
base: sqlite3_vtab, | ||
} | ||
|
||
unsafe impl<'vtab> VTab<'vtab> for ExampleEmbeddedTab { | ||
type Aux = (); | ||
type Cursor = ExampleEmbeddedTabCursor<'vtab>; | ||
|
||
fn connect( | ||
_: &mut VTabConnection, | ||
_aux: Option<&()>, | ||
_args: &[&[u8]], | ||
) -> Result<(String, ExampleEmbeddedTab)> { | ||
let vtab = ExampleEmbeddedTab { | ||
base: sqlite3_vtab::default(), | ||
}; | ||
Ok(("CREATE TABLE x(value TEXT)".to_owned(), vtab)) | ||
} | ||
|
||
fn best_index(&self, info: &mut IndexInfo) -> Result<()> { | ||
info.set_estimated_cost(1.); | ||
Ok(()) | ||
} | ||
|
||
fn open(&'vtab self) -> Result<ExampleEmbeddedTabCursor<'vtab>> { | ||
Ok(ExampleEmbeddedTabCursor::default()) | ||
} | ||
} | ||
|
||
#[derive(Default)] | ||
#[repr(C)] | ||
struct ExampleEmbeddedTabCursor<'vtab> { | ||
/// Base class. Must be first | ||
base: sqlite3_vtab_cursor, | ||
/// The rowid | ||
row_id: i64, | ||
phantom: PhantomData<&'vtab ExampleEmbeddedTab>, | ||
} | ||
|
||
unsafe impl VTabCursor for ExampleEmbeddedTabCursor<'_> { | ||
fn filter( | ||
&mut self, | ||
_idx_num: c_int, | ||
_idx_str: Option<&str>, | ||
_args: &Values<'_>, | ||
) -> Result<()> { | ||
self.row_id = 1; | ||
Ok(()) | ||
} | ||
|
||
fn next(&mut self) -> Result<()> { | ||
self.row_id += 1; | ||
Ok(()) | ||
} | ||
|
||
fn eof(&self) -> bool { | ||
self.row_id > 1 | ||
} | ||
|
||
fn column(&self, ctx: &mut Context, _: c_int) -> Result<()> { | ||
ctx.set_result(&"example_embedded_test_value".to_string()) | ||
} | ||
|
||
fn rowid(&self) -> Result<i64> { | ||
Ok(self.row_id) | ||
} | ||
} | ||
|
||
fn example_embedded_init(db: *mut ffi::sqlite3) -> Result<()> { | ||
let conn = unsafe { Connection::from_handle(db)? }; | ||
eprintln!("inited example embedded extension module {:?}", db); | ||
conn.create_scalar_function( | ||
"example_embedded_test_function", | ||
0, | ||
FunctionFlags::SQLITE_DETERMINISTIC, | ||
|_ctx| { | ||
Ok(ToSqlOutput::Owned(Value::Text( | ||
"Example embedded extension loaded correctly!".to_string(), | ||
))) | ||
}, | ||
)?; | ||
conn.create_module::<ExampleEmbeddedTab>("example_embedded", eponymous_only_module::<ExampleEmbeddedTab>(), None) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/target/ | ||
/doc/ | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[package] | ||
name = "example-extension" | ||
version = "0.0.1" | ||
authors = ["The rusqlite developers"] | ||
edition = "2018" | ||
repository = "https://github.com/rusqlite/rusqlite" | ||
description = "Example extension to demonstrate and test rusqlite feature loadable_extension" | ||
license = "MIT" | ||
keywords = ["sqlite", "extension"] | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
|
||
[dependencies.rusqlite] | ||
path = ".." | ||
default-features = false | ||
features = ["loadable_extension", "vtab", "functions", "bundled"] | ||
|
||
[workspace] | ||
members = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#!/bin/bash | ||
|
||
set -euf -o pipefail | ||
|
||
# the crate dir is where this script is located | ||
crate_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
|
||
# location of the cdylib extension within the target dir | ||
example_extension="${crate_dir}/target/debug/libexample_extension" # sqlite will try adding .so, .dll, .dylib to this on its own | ||
|
||
# expected output from vtable query | ||
expected_vtable_output="1" | ||
|
||
# expected output from function query | ||
expected_function_output="Example extension loaded correctly!" | ||
|
||
>&2 echo "checking for sqlite3 shell" | ||
sqlite3_cmd=$(which sqlite3) | ||
>&2 echo "sqlite3 found: ${sqlite3_cmd}" | ||
|
||
# build the example-extension crate | ||
>&2 echo "building the example-extension crate in ${crate_dir}" | ||
(cd "${crate_dir}" && cargo build --all-targets --verbose) | ||
>&2 echo "successfully built the example-extension crate" | ||
|
||
>&2 echo "running sqlite3 (${sqlite3_cmd}) to test loadable_extension ${example_extension} vtable" | ||
actual_vtable_output=$(${sqlite3_cmd} -cmd ".load ${example_extension}" :memory: "SELECT value FROM example LIMIT 1;") | ||
>&2 echo "sqlite3 command returned successfully from vtable test, checking output is as expected" | ||
test "${actual_vtable_output}" = "${expected_vtable_output}" && echo "OK" || (echo "vtable output '${actual_vtable_output}' was not as expected '${expected_vtable_output}'"; echo "FAIL"; exit 1) | ||
|
||
>&2 echo "running sqlite3 (${sqlite3_cmd}) to test loadable_extension ${example_extension} function" | ||
actual_function_output=$(${sqlite3_cmd} -cmd ".load ${example_extension}" :memory: "SELECT example_test_function();") | ||
>&2 echo "sqlite3 command returned successfully from function test, checking output is as expected" | ||
test "${actual_function_output}" = "${expected_function_output}" && echo "OK" || (echo "function output '${actual_function_output}' was not as expected '${expected_function_output}'"; echo "FAIL"; exit 1) | ||
|
||
>&2 echo "All tests passed." | ||
exit 0 |
Oops, something went wrong.