Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
92fa703
add support for sqlite loadable extensions
jrandall Jun 15, 2019
5c97c48
install rustfmt in travis ci
jrandall Jun 15, 2019
4caff14
add rustfmt to appveyor install
jrandall Jun 15, 2019
b21aed2
fix reference to link_lib in vcpkg build
jrandall Jun 16, 2019
0bf1e74
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Feb 9, 2020
955521f
Remove old bindgens
gwenn Feb 9, 2020
26c9193
Remove some more old bindgens
gwenn Feb 11, 2020
e1fffce
Remove unused `api_routines_stub` feature
gwenn Feb 11, 2020
d4b710a
Remove unused `vtab_v3` feature
gwenn Feb 11, 2020
2b3fd57
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Feb 11, 2020
168821a
Revert changes on old bindgens
gwenn Feb 11, 2020
2c6b6ac
Ignore PATH change on Windows
gwenn Feb 11, 2020
68bea40
Remove copyright header from build script
gwenn Feb 15, 2020
325bfb6
Generate all three bindgen files
gwenn Feb 15, 2020
2b170f0
Generate new bindgen files for bundled version
gwenn Feb 15, 2020
3494e67
Remove generate-bindgen-bindings script
gwenn Feb 15, 2020
7dd7204
Upgrade syn / quote
gwenn Feb 15, 2020
1e19268
Fix warning after wrong merge
gwenn Feb 15, 2020
0b042d0
Run rustfmt manually only while regenerating bindgen files
gwenn Feb 15, 2020
9be9358
Fix warnings in build script
gwenn Feb 15, 2020
5e20e5d
Remove code specific to SQLITE_DETERMINISTIC
gwenn Feb 15, 2020
e4b669c
Fix build_loadable_extension conditional compilation
gwenn Feb 15, 2020
df9a1b1
Remove non_threadsafe feature
gwenn Feb 15, 2020
14ef2d1
Make loadable_extension compatible with bundled* features
gwenn Feb 16, 2020
347c9ff
Fix clippy warnings
gwenn Feb 16, 2020
112b061
Fix compilation error with loadable_extension feature
gwenn Feb 16, 2020
5181cca
Revert output mutability
gwenn Feb 16, 2020
ffbf6b5
Fix warnings
gwenn Feb 16, 2020
0f6ad74
Check loadable_extension build
gwenn Feb 16, 2020
1e211b3
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Feb 22, 2020
39ac443
eliminate -ext-embed versions of bindgen-bindings
jrandall Feb 22, 2020
be120ef
Merge pull request #2 from Genomicsplc/pr/loadable-extensions
gwenn Feb 28, 2020
121fdba
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Mar 1, 2020
d52a920
Fix bindgen_bundled_version-ext.rs
gwenn Mar 8, 2020
db04c93
Add comments
gwenn Mar 8, 2020
f3b58e1
`config_log` cannot be used with `loadable_extension`
gwenn Mar 8, 2020
643c0f6
Introduce `to_sqlite_error`
gwenn Mar 8, 2020
a252561
Add `dummy-extension` module
gwenn Mar 8, 2020
bceef65
Fix dummy-extension module
gwenn Mar 15, 2020
03cb901
Document and export check macro
gwenn Mar 15, 2020
84bae86
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Mar 15, 2020
ad842a3
Try to fix CI build
gwenn Mar 15, 2020
f1ae27c
Fix dummy-extension
gwenn Mar 15, 2020
66de561
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Apr 1, 2020
cf658af
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Apr 5, 2020
cb9e702
Merge remote-tracking branch 'upstream/master' into pr/loadable-exten…
gwenn Jun 13, 2020
bbbc76a
Fix build error
gwenn Jun 13, 2020
61ee112
Fix bindgen ext files.
gwenn Jun 13, 2020
a20039b
Export check macro
gwenn Jun 13, 2020
9b93d38
Fix to_sqlite_error doc
gwenn Jun 13, 2020
3770778
Fix dummy extension
gwenn Jun 13, 2020
944ad5e
Fix sqlite3_api_routines size
gwenn Jun 13, 2020
5fb3f42
Merge remote-tracking branch 'upstream/master' into gwenntest
phiresky Dec 16, 2020
c409018
fix build for loadable_extension
phiresky Dec 16, 2020
44cf295
update bundled bindgen for loadable_extension
phiresky Dec 16, 2020
98bb78f
add test function to dummy module as well
phiresky Dec 16, 2020
763364f
format
phiresky Dec 18, 2020
efd88cb
Merge remote-tracking branch 'upstream/master' into loadable-extensions
phiresky Dec 23, 2020
28f7c42
Fix up loadable extensions work
jrandall Mar 7, 2021
63c66ed
Merge branch 'master' into loadable-extensions
jrandall Mar 7, 2021
e63b17f
improve loadable_extension integration test and add loadable_extensio…
jrandall Mar 7, 2021
4f68759
Merge tag 'v0.25.0' into loadable-extensions
jrandall Apr 4, 2021
6980767
Merge tag 'v0.26.2' into loadable-extensions
jrandall Dec 8, 2021
568dfea
rename dummy-extension and dummy-embedded-extension to example-extens…
jrandall Dec 8, 2021
462ff15
fix issues resulting from merge conflict resolution in libsqlite3-sys…
jrandall Dec 8, 2021
f87a94c
fix issue with header_path in libsqlite3-sys/build.rs
jrandall Dec 8, 2021
a2ac5f2
don't specify version in example-*/Cargo.toml so that they can be bui…
jrandall Dec 8, 2021
0c50fd3
cargo fmt
jrandall Dec 8, 2021
2472ec9
remove extraneous cmoment line in libsqlite3-sys/build.rs
jrandall Dec 8, 2021
5069474
add runtime version checks to loadable extension wrappers, improve sa…
jrandall Dec 8, 2021
b252f5e
cargo fmt
jrandall Dec 9, 2021
55c0c3c
add safety docs to unsafe functions in example-extension and example-…
jrandall Dec 9, 2021
069fc87
cargo fmt
jrandall Dec 9, 2021
b4ae3e0
fix doctests in src/loadable_extension.rs
jrandall Dec 10, 2021
3819e07
access sqlite3_api_routines fields in generated wrapper functions usi…
jrandall Dec 10, 2021
a8e7665
Merge branch 'loadable-extensions' of github.com:Genomicsplc/rusqlite…
polyrand May 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,22 @@ jobs:
- run: cargo build --features sqlcipher --workspace --all-targets --verbose
- run: cargo test --features sqlcipher --workspace --all-targets --verbose

example-extension:
name: Test loadable_extension with example-extension
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: hecrj/setup-rust-action@v1
- run: ./example-extension/integration-test.sh

example-embedded-extension:
name: Test loadable_extension_embedded with example-embedded-extension
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: hecrj/setup-rust-action@v1
- run: ./example-embedded-extension/integration-test.sh

sanitizer:
name: Address Sanitizer
runs-on: ubuntu-latest
Expand Down Expand Up @@ -170,6 +186,7 @@ jobs:
- run: cargo clippy --all-targets --workspace --features bundled -- -D warnings
# Clippy with all non-conflicting features
- run: cargo clippy --all-targets --workspace --features 'bundled-full session buildtime_bindgen' -- -D warnings
- run: (cd example-extension && cargo clippy --all-targets -- -D warnings)

# Ensure patch is formatted.
fmt:
Expand Down
10 changes: 10 additions & 0 deletions CONTRIBUTORS.md
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
11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ backup = ["libsqlite3-sys/min_sqlite_version_3_6_23"]
blob = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
collation = []
# sqlite3_create_function_v2: 3.7.3 (2010-10-08)
functions = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
# functions requires ffi::SQLITE_DETERMINISTIC: 3.8.3 (2014-02-03)
functions = ["modern_sqlite"]
# sqlite3_log: 3.6.23 (2010-03-09)
trace = ["libsqlite3-sys/min_sqlite_version_3_6_23"]
# sqlite3_db_release_memory: 3.7.10 (2012-01-16)
Expand All @@ -49,6 +50,8 @@ bundled = ["libsqlite3-sys/bundled", "modern_sqlite"]
bundled-sqlcipher = ["libsqlite3-sys/bundled-sqlcipher", "bundled"]
bundled-sqlcipher-vendored-openssl = ["libsqlite3-sys/bundled-sqlcipher-vendored-openssl", "bundled-sqlcipher"]
buildtime_bindgen = ["libsqlite3-sys/buildtime_bindgen"]
loadable_extension = ["libsqlite3-sys/loadable_extension"]
loadable_extension_embedded = ["loadable_extension", "libsqlite3-sys/loadable_extension_embedded"]
limits = []
hooks = []
i128_blob = []
Expand All @@ -58,11 +61,11 @@ unlock_notify = ["libsqlite3-sys/unlock_notify"]
vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
csvtab = ["csv", "vtab"]
# pointer passing interfaces: 3.20.0
array = ["vtab"]
array = ["modern_sqlite", "vtab"]
# session extension: 3.13.0
session = ["libsqlite3-sys/session", "hooks"]
session = ["modern_sqlite", "libsqlite3-sys/session", "hooks"]
# window functions: 3.25.0
window = ["functions"]
window = ["modern_sqlite", "functions"]
# 3.9.0
series = ["vtab"]
# check for invalid query.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ pregenerated bindings are chosen:
* `min_sqlite_version_3_6_8` - SQLite 3.6.8 bindings (this is the default)
* `min_sqlite_version_3_6_23` - SQLite 3.6.23 bindings
* `min_sqlite_version_3_7_7` - SQLite 3.7.7 bindings
* `min_sqlite_version_3_7_16` - SQLite 3.7.16 bindings

If you use any of the `bundled` features, you will get pregenerated bindings for the
bundled version of SQLite/SQLCipher. If you need other specific pregenerated binding
Expand Down
3 changes: 3 additions & 0 deletions example-embedded-extension/.gitignore
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/
25 changes: 25 additions & 0 deletions example-embedded-extension/Cargo.toml
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 = []
15 changes: 15 additions & 0 deletions example-embedded-extension/build.rs
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");
}
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;
}
50 changes: 50 additions & 0 deletions example-embedded-extension/integration-test.sh
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
135 changes: 135 additions & 0 deletions example-embedded-extension/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
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.
///
/// # Safety
///
/// The C host extension must pass a pointer to a valid `sqlite3` struct in
/// `db`` and either null or a pointer to a char* in `pz_err_msg`.
#[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)
}
3 changes: 3 additions & 0 deletions example-extension/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target/
/doc/
Cargo.lock
22 changes: 22 additions & 0 deletions example-extension/Cargo.toml
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 = []
Loading