sqlite3_ext
Create SQLite loadable extensions in Rust. The design philosophy of the API is gradual enhancement: all use of SQLite features returns a Result, and an Err is returned when the host version of SQLite does not support the feature in question.
Early Version Warning
This crate is pre-1.0 and the API is allowed to change freely. In particular, if a safe API is found to be unsafe, it will be changed. Once the crate reaches version 1.0, the API will be subject to semantic versioning.
Being a pre-1.0, young crate, there may be bugs which have not yet been discovered. The crate comes with a modest test suite covering all of the features (over 100 tests currently).
Crate documentation is moderately covered, and there are example extensions in the repository that can serve as a guide. Also look at the integration test in the "test" folder at the root.
Multi-threading support is low-priority and untested. If your application-defined functions and virtual tables don't reference data outside of the database they are attached to, this will not cause issues because SQLite always does database operations in a single thread. However, the API needs to be evaluated through a multithreading lens to ensure that it is safe.
Features
- A querying interface similar to Rusqlite's.
- Application-defined scalar and aggregate functions, and collating sequences.
- A more comprehensive virtual table implementation than any other Rust crate currently published, supporting all SQLite virtual table methods.
- Rust support for the most modern features of SQLite, up to version 3.38.5.
Crate features
-
static
- The consumer of this crate is a statically linked run-time loadable extension. SQLite will be provided by the linker. To avoid link errors, sqlite3_ext disables all APIs that are added after 3.6.8. -
static_modern
- Same asstatic
, but sqlite3_ext does not disable any APIs. This will cause link errors if the linked version of SQLite is older than the version supported by sqlite3_ext. -
bundled
- Same asstatic_modern
, but also statically link a bundled version of SQLite from libsqlite3-sys. Please do not activate this feature from library crates, so that the consumer of your crate can decide for themselves to enable it. -
with_rusqlite
- Adds support for registering your statically linked extension to a Rusqlite Connection object.
How to use
- I want to create a loadable extension that can be used by any SQLite client, or from the sqlite3 shell.
- Your crate should be
crate-type = [ "cdylib" ]
. - Use
sqlite3_ext_main
to register your enhancements. - SQLite methods are provided by SQLite at run-time, and methods will return
Error::VersionNotSatisfied
if they are not available in the host SQLite.
- Your crate should be
- I want to create a Rust binary that uses features not supported by rusqlite.
- Your crate can be of any type. Enable the
with_rusqlite
andbundled
features of this crate. - Use
sqlite3_ext_init
to create an initialization function. Call the function with the rusqlite Connection, as shown here. - SQLite methods will always be available, since the SQLite version is controlled by Rust.
- Your crate can be of any type. Enable the
- I want to create a statically linked extension that can be used by a (potentially non-Rust) program.
- Your crate should be
crate-type = [ "staticlib" ]
. Enable thestatic
feature of this crate. Usesqlite3_ext_main
to register your enhancements. - Call
sqlite3_mycrate_init
directly (the method name is derived from the crate name) as documented here, or usesqlite3_auto_extension
. - The host system provides SQLite. SQLite methods not available in version 3.6.8 will always return
Error::VersionNotSatisfied
.
- Your crate should be
- I want to create a statically linked extension with modern SQLite features that can be used by a (potentially non-Rust) program.
- This is the same as above, but using the
static_modern
feature. - The version of SQLite being linked in must be the same or newer than the version supported by sqlite3_ext.
- This is the same as above, but using the
- I want to create a Rust program that does not use rusqlite.
- Your crate can be of any type. Enable the
with_rusqlite
andbundled
features of this crate. - Use
sqlite3_ext_init
to create an initialization function. UseDatabase
to open a connection to a database. Pass the Database to the init function. - SQLite methods will always be available, since the SQLite version is controlled by Rust.
-
Note: if you are publishing a library crate, use
static_modern
instead ofbundled
, to avoid corrupting the database of your library's consumer.
- Your crate can be of any type. Enable the
Test configurations
Tests run with modern SQLite:
- All tests from
Cargo.toml
with crate featurestatic
. - All tests from
Cargo.toml
with crate featurestatic_modern
.
Todo:
- Run tests against SQLite 3.6.8.
Interfaces supported
Here is a compatibility chart showing which parts of the SQLite API are currently covered by sqlite3_ext. Iconography:
-
✅ - This API is fully exposed via an API in sqlite3_ext -
❕ - This API is available via unsafe ffi, but there are no plans to make an API for it in sqlite3_ext.
Interface | Object | Status | Details |
---|---|---|---|
sqlite3_aggregate_context | sqlite3_context | Arbitrary structs supported | |
sqlite3_auto_extension | - | Extension::register_auto | |
sqlite3_autovacuum_pages | |||
sqlite3_backup_finish | |||
sqlite3_backup_init | |||
sqlite3_backup_pagecount | |||
sqlite3_backup_remaining | |||
sqlite3_backup_step | |||
sqlite3_bind_blob | sqlite3_stmt | ToParam | |
sqlite3_bind_blob64 | sqlite3_stmt | ToParam | |
sqlite3_bind_double | sqlite3_stmt | ToParam | |
sqlite3_bind_int | sqlite3_stmt | Unnecessary | |
sqlite3_bind_int64 | sqlite3_stmt | ToParam | |
sqlite3_bind_null | sqlite3_stmt | ToParam | |
sqlite3_bind_parameter_count | sqlite3_stmt | Statement::parameter_count | |
sqlite3_bind_parameter_index | sqlite3_stmt | Statement::parameter_position | |
sqlite3_bind_parameter_name | sqlite3_stmt | Statement::parameter_name | |
sqlite3_bind_pointer | sqlite3_stmt | ToParam | |
sqlite3_bind_text | sqlite3_stmt | ToParam | |
sqlite3_bind_text16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_bind_text64 | sqlite3_stmt | ToParam | |
sqlite3_bind_value | sqlite3_stmt | ToParam | |
sqlite3_bind_zeroblob | sqlite3_stmt | ||
sqlite3_bind_zeroblob64 | sqlite3_stmt | ||
sqlite3_blob_bytes | |||
sqlite3_blob_close | |||
sqlite3_blob_open | |||
sqlite3_blob_read | |||
sqlite3_blob_reopen | |||
sqlite3_blob_write | |||
sqlite3_busy_handler | |||
sqlite3_busy_timeout | |||
sqlite3_cancel_auto_extension | - | Extension::cancel_auto | |
sqlite3_changes | Statement::execute | ||
sqlite3_changes64 | Statement::execute | ||
sqlite3_clear_bindings | sqlite3_stmt | Unnecessary | |
sqlite3_close | Database::close | ||
sqlite3_close_v2 | Unnecessary | ||
sqlite3_collation_needed | sqlite3 | Connection::set_collation_needed_func | |
sqlite3_collation_needed16 | sqlite3 | Use UTF-8 equivalent | |
sqlite3_column_blob | sqlite3_stmt | Column::get_blob | |
sqlite3_column_bytes | sqlite3_stmt | Unnecessary | |
sqlite3_column_bytes16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_column_count | sqlite3_stmt | Statement::column_count | |
sqlite3_column_database_name | sqlite3_stmt | Column::database_name | |
sqlite3_column_database_name16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_column_decltype | sqlite3_stmt | Column::decltype | |
sqlite3_column_decltype16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_column_double | sqlite3_stmt | Column::get_f64 | |
sqlite3_column_int | sqlite3_stmt | Column::get_i32 | |
sqlite3_column_int64 | sqlite3_stmt | Column::get_i64 | |
sqlite3_column_name | sqlite3_stmt | Column::name | |
sqlite3_column_name16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_column_origin_name | sqlite3_stmt | Column::origin_name | |
sqlite3_column_origin_name16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_column_table_name | sqlite3_stmt | Column::table_name | |
sqlite3_column_table_name16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_column_text | sqlite3_stmt | Column::get_str | |
sqlite3_column_text16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_column_type | sqlite3_stmt | Column::value_type | |
sqlite3_column_value | sqlite3_stmt | Column::as_ref | |
sqlite3_commit_hook | sqlite3 | ||
sqlite3_compileoption_get | |||
sqlite3_compileoption_used | |||
sqlite3_complete | |||
sqlite3_complete16 | Use UTF-8 equivalent | ||
sqlite3_config | |||
sqlite3_context_db_handle | sqlite3_context | Context::db | |
sqlite3_create_collation | sqlite3 | Connection::create_collation | |
sqlite3_create_collation16 | sqlite3 | Use UTF-8 equivalent | |
sqlite3_create_collation_v2 | sqlite3 | Connection::create_collation | |
sqlite3_create_filename | |||
sqlite3_create_function | sqlite3 | Connection::create_scalar_function | |
sqlite3_create_function16 | sqlite3 | Use UTF-8 equivalent | |
sqlite3_create_function_v2 | sqlite3 | Connection::create_scalar_function | |
sqlite3_create_module | sqlite3 | Connection::create_module | |
sqlite3_create_module_v2 | sqlite3 | Connection::create_module | |
sqlite3_create_window_function | sqlite3 | Connection::create_aggregate_function | |
sqlite3_data_count | sqlite3_stmt | ||
sqlite3_database_file_object | |||
sqlite3_db_cacheflush | |||
sqlite3_db_config | |||
sqlite3_db_filename | |||
sqlite3_db_handle | sqlite3_stmt | Statement::db | |
sqlite3_db_mutex | sqlite3 | Connection::lock | |
sqlite3_db_readonly | |||
sqlite3_db_release_memory | |||
sqlite3_db_status | |||
sqlite3_declare_vtab | VTab::connect | ||
sqlite3_deserialize | |||
sqlite3_drop_modules | |||
sqlite3_enable_load_extension | sqlite3 | Available via ffi | |
sqlite3_enable_shared_cache | |||
sqlite3_errcode | sqlite3 | ||
sqlite3_errmsg | sqlite3 | ||
sqlite3_errmsg16 | sqlite3 | Use UTF-8 equivalent | |
sqlite3_error_offset | sqlite3 | ||
sqlite3_errstr | - | Error::fmt | |
sqlite3_exec | sqlite3 | Unnecessary | |
sqlite3_expanded_sql | sqlite3_stmt | ||
sqlite3_extended_errcode | sqlite3 | ||
sqlite3_extended_result_codes | sqlite3 | ||
sqlite3_file_control | |||
sqlite3_filename_database | |||
sqlite3_filename_journal | |||
sqlite3_filename_wal | |||
sqlite3_finalize | sqlite3_stmt | Unnecessary | |
sqlite3_free | Available via ffi | ||
sqlite3_free_filename | |||
sqlite3_free_table | Available via ffi | ||
sqlite3_get_autocommit | |||
sqlite3_get_auxdata | sqlite3_context | Context::aux_data | |
sqlite3_get_table | Available via ffi | ||
sqlite3_hard_heap_limit64 | |||
sqlite3_initialize | Available via ffi | ||
sqlite3_interrupt | |||
sqlite3_keyword_check | |||
sqlite3_keyword_count | |||
sqlite3_keyword_name | |||
sqlite3_last_insert_rowid | |||
sqlite3_libversion | SQLITE_VERSION.as_str | ||
sqlite3_libversion_number | SQLITE_VERSION.get | ||
sqlite3_limit | sqlite3 | ||
sqlite3_load_extension | sqlite3 | ||
sqlite3_log | |||
sqlite3_malloc | Available via ffi | ||
sqlite3_malloc64 | Available via ffi | ||
sqlite3_memory_highwater | |||
sqlite3_memory_used | |||
sqlite3_mprintf | char | Available via ffi | |
sqlite3_msize | Available via ffi | ||
sqlite3_mutex_alloc | Available via ffi | ||
sqlite3_mutex_enter | Available via ffi | ||
sqlite3_mutex_free | Available via ffi | ||
sqlite3_mutex_held | Available via ffi | ||
sqlite3_mutex_leave | Available via ffi | ||
sqlite3_mutex_notheld | Available via ffi | ||
sqlite3_mutex_try | Available via ffi | ||
sqlite3_next_stmt | |||
sqlite3_normalized_sql | sqlite3_stmt | ||
sqlite3_open | sqlite3 | ||
sqlite3_open16 | sqlite3 | Use UTF-8 equivalent | |
sqlite3_open_v2 | sqlite3 | ||
sqlite3_overload_function | sqlite3 | Connection::create_overloaded_function | |
sqlite3_prepare | sqlite3_stmt | Unnecessary | |
sqlite3_prepare16 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_prepare16_v2 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_prepare16_v3 | sqlite3_stmt | Use UTF-8 equivalent | |
sqlite3_prepare_v2 | sqlite3_stmt | Connection::prepare | |
sqlite3_prepare_v3 | sqlite3_stmt | Connection::prepare | |
sqlite3_preupdate_blobwrite | |||
sqlite3_preupdate_count | |||
sqlite3_preupdate_depth | |||
sqlite3_preupdate_hook | |||
sqlite3_preupdate_new | |||
sqlite3_preupdate_old | |||
sqlite3_profile | |||
sqlite3_progress_handler | |||
sqlite3_randomness | sqlite3_randomness | ||
sqlite3_realloc | Available via ffi | ||
sqlite3_realloc64 | Available via ffi | ||
sqlite3_release_memory | |||
sqlite3_reset | sqlite3_stmt | Statement::query | |
sqlite3_reset_auto_extension | Extension::reset_auto | ||
sqlite3_result_blob | sqlite3_context | ToContextResult | |
sqlite3_result_blob64 | sqlite3_context | ToContextResult | |
sqlite3_result_double | sqlite3_context | ToContextResult | |
sqlite3_result_error | sqlite3_context | ToContextResult | |
sqlite3_result_error16 | sqlite3_context | Use UTF-8 equivalent | |
sqlite3_result_error_code | sqlite3_context | ToContextResult | |
sqlite3_result_error_nomem | sqlite3_context | ||
sqlite3_result_error_toobig | sqlite3_context | ||
sqlite3_result_int | sqlite3_context | ToContextResult | |
sqlite3_result_int64 | sqlite3_context | ToContextResult | |
sqlite3_result_null | sqlite3_context | ToContextResult | |
sqlite3_result_pointer | sqlite3_context | PassedRef | |
sqlite3_result_subtype | sqlite3_context | UnsafePtr | |
sqlite3_result_text | sqlite3_context | ToContextResult | |
sqlite3_result_text16 | sqlite3_context | Use UTF-8 equivalent | |
sqlite3_result_text16be | sqlite3_context | Use UTF-8 equivalent | |
sqlite3_result_text16le | sqlite3_context | Use UTF-8 equivalent | |
sqlite3_result_text64 | sqlite3_context | ToContextResult | |
sqlite3_result_value | sqlite3_context | ToContextResult | |
sqlite3_result_zeroblob | sqlite3_context | ||
sqlite3_result_zeroblob64 | sqlite3_context | ||
sqlite3_rollback_hook | sqlite3 | ||
sqlite3_serialize | |||
sqlite3_set_authorizer | |||
sqlite3_set_auxdata | sqlite3_context | Context::set_aux_data | |
sqlite3_set_last_insert_rowid | sqlite3 | Available via ffi | |
sqlite3_shutdown | Available via ffi | ||
sqlite3_sleep | Available via ffi | ||
sqlite3_snapshot_cmp | |||
sqlite3_snapshot_free | |||
sqlite3_snapshot_get | |||
sqlite3_snapshot_open | |||
sqlite3_snapshot_recover | |||
sqlite3_snprintf | char | Available via ffi | |
sqlite3_soft_heap_limit64 | |||
sqlite3_sourceid | SQLITE_VERSION.sourceid | ||
sqlite3_sql | sqlite3_stmt | Statement::sql | |
sqlite3_status | |||
sqlite3_status64 | |||
sqlite3_step | sqlite3_stmt | ResultSet::next | |
sqlite3_stmt_busy | sqlite3_stmt | ||
sqlite3_stmt_isexplain | sqlite3_stmt | ||
sqlite3_stmt_readonly | sqlite3_stmt | ||
sqlite3_stmt_scanstatus | sqlite3_stmt | ||
sqlite3_stmt_scanstatus_reset | sqlite3_stmt | ||
sqlite3_stmt_status | sqlite3_stmt | ||
sqlite3_str_append | sqlite3_str | Available via ffi | |
sqlite3_str_appendall | sqlite3_str | Available via ffi | |
sqlite3_str_appendchar | sqlite3_str | Available via ffi | |
sqlite3_str_appendf | sqlite3_str | Available via ffi | |
sqlite3_str_errcode | sqlite3_str | Available via ffi | |
sqlite3_str_finish | sqlite3_str | Available via ffi | |
sqlite3_str_length | sqlite3_str | Available via ffi | |
sqlite3_str_new | sqlite3_str | Available via ffi | |
sqlite3_str_reset | sqlite3_str | Available via ffi | |
sqlite3_str_value | sqlite3_str | Available via ffi | |
sqlite3_str_vappendf | sqlite3_str | Available via ffi | |
sqlite3_strglob | char | sqlite3_strglob | |
sqlite3_stricmp | char | sqlite3_stricmp | |
sqlite3_strlike | char | sqlite3_strlike | |
sqlite3_strnicmp | char | Unnecessary | |
sqlite3_system_errno | sqlite3 | Available via ffi | |
sqlite3_table_column_metadata | |||
sqlite3_threadsafe | Available via ffi | ||
sqlite3_total_changes | sqlite3 | ||
sqlite3_total_changes64 | sqlite3 | ||
sqlite3_trace | |||
sqlite3_trace_v2 | |||
sqlite3_txn_state | |||
sqlite3_unlock_notify | |||
sqlite3_update_hook | |||
sqlite3_uri_boolean | Available via ffi | ||
sqlite3_uri_int64 | Available via ffi | ||
sqlite3_uri_key | Available via ffi | ||
sqlite3_uri_parameter | Available via ffi | ||
sqlite3_user_data | sqlite3_context | Use a closure for the function | |
sqlite3_value_blob | sqlite3_value | ValueRef::get_blob | |
sqlite3_value_bytes | sqlite3_value | Unnecessary | |
sqlite3_value_bytes16 | sqlite3_value | Use UTF-8 equivalent | |
sqlite3_value_double | sqlite3_value | ValueRef::get_f64 | |
sqlite3_value_dup | sqlite3_value | ||
sqlite3_value_free | sqlite3_value | Unnecesary | |
sqlite3_value_frombind | sqlite3_value | ValueRef::is_from_bind | |
sqlite3_value_int | sqlite3_value | ValueRef::get_i32 | |
sqlite3_value_int64 | sqlite3_value | ValueRef::get_i64 | |
sqlite3_value_nochange | sqlite3_value | ValueRef::nochange | |
sqlite3_value_numeric_type | sqlite3_value | ValueRef::numeric_type | |
sqlite3_value_pointer | sqlite3_value | ValueRef::get_ref | |
sqlite3_value_subtype | sqlite3_value | UnsafePtr | |
sqlite3_value_text | sqlite3_value | ValueRef::get_str | |
sqlite3_value_text16 | sqlite3_value | Use UTF-8 equivalent | |
sqlite3_value_text16be | sqlite3_value | Use UTF-8 equivalent | |
sqlite3_value_text16le | sqlite3_value | Use UTF-8 equivalent | |
sqlite3_value_type | sqlite3_value | ValueRef::value_type | |
sqlite3_vfs_find | |||
sqlite3_vfs_register | |||
sqlite3_vfs_unregister | |||
sqlite3_vmprintf | char | Unnecessary | |
sqlite3_vsnprintf | char | Unnecessary | |
sqlite3_vtab_collation | sqlite3_index_info | IndexInfoConstraint::collation | |
sqlite3_vtab_config | sqlite3 | VTabConnection | |
sqlite3_vtab_distinct | sqlite3_index_info | IndexInfo::distinct_mode | |
sqlite3_vtab_in | sqlite3_index_info | IndexInfoConstraint::set_value_list_wanted | |
sqlite3_vtab_in_first | sqlite3_value | ValueList | |
sqlite3_vtab_in_next | sqlite3_value | ValueList | |
sqlite3_vtab_nochange | sqlite3_context | ColumnContext::nochange | |
sqlite3_vtab_on_conflict | sqlite3 | ChangeInfo::conflict_mode | |
sqlite3_vtab_rhs_value | sqlite3_index_info | IndexInfoConstraint::rhs | |
sqlite3_wal_autocheckpoint | |||
sqlite3_wal_checkpoint | |||
sqlite3_wal_checkpoint_v2 | |||
sqlite3_wal_hook | |||
sqlite3_win32_set_directory | |||
sqlite3_win32_set_directory16 | Use UTF-8 equivalent | ||
sqlite3_win32_set_directory8 |