diff --git a/src/vtab/array.rs b/src/vtab/array.rs index 38efe96..645ab60 100644 --- a/src/vtab/array.rs +++ b/src/vtab/array.rs @@ -33,8 +33,8 @@ use std::rc::Rc; use crate::ffi; use crate::types::{ToSql, ToSqlOutput, Value}; use crate::vtab::{ - eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection, - VTabCursor, Values, + eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConnection, VTabCursor, + Values, }; use crate::{Connection, Result}; @@ -57,11 +57,7 @@ impl ToSql for Array { /// `feature = "array"` Register the "rarray" module. pub fn load_module(conn: &Connection) -> Result<()> { let aux: Option<()> = None; - conn.create_module("rarray", &ARRAY_MODULE, aux) -} - -lazy_static::lazy_static! { - static ref ARRAY_MODULE: Module = eponymous_only_module::(1); + conn.create_module("rarray", eponymous_only_module::(), aux) } // Column numbers diff --git a/src/vtab/csvtab.rs b/src/vtab/csvtab.rs index 658dbf8..77570ae 100644 --- a/src/vtab/csvtab.rs +++ b/src/vtab/csvtab.rs @@ -30,7 +30,7 @@ use crate::ffi; use crate::types::Null; use crate::vtab::{ dequote, escape_double_quote, parse_boolean, read_only_module, Context, CreateVTab, IndexInfo, - Module, VTab, VTabConnection, VTabCursor, Values, + VTab, VTabConnection, VTabCursor, Values, }; use crate::{Connection, Error, Result}; @@ -47,11 +47,7 @@ use crate::{Connection, Error, Result}; /// ``` pub fn load_module(conn: &Connection) -> Result<()> { let aux: Option<()> = None; - conn.create_module("csv", &CSV_MODULE, aux) -} - -lazy_static::lazy_static! { - static ref CSV_MODULE: Module = read_only_module::(1); + conn.create_module("csv", read_only_module::(), aux) } /// An instance of the CSV virtual table diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index fdbede5..e9b2b10 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -60,7 +60,7 @@ use crate::{str_to_cstring, Connection, Error, InnerConnection, Result}; /// `feature = "vtab"` Virtual table module /// /// (See [SQLite doc](https://sqlite.org/c3ref/module.html)) -#[repr(C)] +#[repr(transparent)] pub struct Module { base: ffi::sqlite3_module, phantom: PhantomData, @@ -69,47 +69,55 @@ pub struct Module { unsafe impl Send for Module {} unsafe impl Sync for Module {} -// Used as a trailing initializer for sqlite3_module -- this way we avoid having -// the build fail if buildtime_bindgen is on -fn zeroed_module() -> ffi::sqlite3_module { - // This is safe, as bindgen-generated structs are allowed to be zeroed. - unsafe { std::mem::MaybeUninit::zeroed().assume_init() } +union ModuleZeroHack { + bytes: [u8; std::mem::size_of::()], + module: ffi::sqlite3_module, } +// Used as a trailing initializer for sqlite3_module -- this way we avoid having +// the build fail if buildtime_bindgen is on. This is safe, as bindgen-generated +// structs are allowed to be zeroed. +const ZERO_MODULE: ffi::sqlite3_module = unsafe { + ModuleZeroHack { + bytes: [0u8; std::mem::size_of::()], + } + .module +}; + /// `feature = "vtab"` Create a read-only virtual table implementation. /// /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). -pub fn read_only_module(version: c_int) -> Module { +pub fn read_only_module() -> &'static Module { // The xConnect and xCreate methods do the same thing, but they must be // different so that the virtual table is not an eponymous virtual table. - let ffi_module = ffi::sqlite3_module { - iVersion: version, - xCreate: Some(rust_create::), - xConnect: Some(rust_connect::), - xBestIndex: Some(rust_best_index::), - xDisconnect: Some(rust_disconnect::), - xDestroy: Some(rust_destroy::), - xOpen: Some(rust_open::), - xClose: Some(rust_close::), - xFilter: Some(rust_filter::), - xNext: Some(rust_next::), - xEof: Some(rust_eof::), - xColumn: Some(rust_column::), - xRowid: Some(rust_rowid::), - xUpdate: None, - xBegin: None, - xSync: None, - xCommit: None, - xRollback: None, - xFindFunction: None, - xRename: None, - xSavepoint: None, - xRelease: None, - xRollbackTo: None, - ..zeroed_module() - }; - Module { - base: ffi_module, + &Module { + base: ffi::sqlite3_module { + // We don't use V3 + iVersion: 2, // We don't use V2 or V3 features in read_only_module types + xCreate: Some(rust_create::), + xConnect: Some(rust_connect::), + xBestIndex: Some(rust_best_index::), + xDisconnect: Some(rust_disconnect::), + xDestroy: Some(rust_destroy::), + xOpen: Some(rust_open::), + xClose: Some(rust_close::), + xFilter: Some(rust_filter::), + xNext: Some(rust_next::), + xEof: Some(rust_eof::), + xColumn: Some(rust_column::), + xRowid: Some(rust_rowid::), + xUpdate: None, + xBegin: None, + xSync: None, + xCommit: None, + xRollback: None, + xFindFunction: None, + xRename: None, + xSavepoint: None, + xRelease: None, + xRollbackTo: None, + ..ZERO_MODULE + }, phantom: PhantomData::, } } @@ -117,38 +125,38 @@ pub fn read_only_module(version: c_int) -> Module { /// `feature = "vtab"` Create an eponymous only virtual table implementation. /// /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). -pub fn eponymous_only_module(version: c_int) -> Module { +pub fn eponymous_only_module() -> &'static Module { // A virtual table is eponymous if its xCreate method is the exact same function // as the xConnect method For eponymous-only virtual tables, the xCreate // method is NULL - let ffi_module = ffi::sqlite3_module { - iVersion: version, - xCreate: None, - xConnect: Some(rust_connect::), - xBestIndex: Some(rust_best_index::), - xDisconnect: Some(rust_disconnect::), - xDestroy: None, - xOpen: Some(rust_open::), - xClose: Some(rust_close::), - xFilter: Some(rust_filter::), - xNext: Some(rust_next::), - xEof: Some(rust_eof::), - xColumn: Some(rust_column::), - xRowid: Some(rust_rowid::), - xUpdate: None, - xBegin: None, - xSync: None, - xCommit: None, - xRollback: None, - xFindFunction: None, - xRename: None, - xSavepoint: None, - xRelease: None, - xRollbackTo: None, - ..zeroed_module() - }; - Module { - base: ffi_module, + &Module { + base: ffi::sqlite3_module { + // We don't use V3 + iVersion: 2, + xCreate: None, + xConnect: Some(rust_connect::), + xBestIndex: Some(rust_best_index::), + xDisconnect: Some(rust_disconnect::), + xDestroy: None, + xOpen: Some(rust_open::), + xClose: Some(rust_close::), + xFilter: Some(rust_filter::), + xNext: Some(rust_next::), + xEof: Some(rust_eof::), + xColumn: Some(rust_column::), + xRowid: Some(rust_rowid::), + xUpdate: None, + xBegin: None, + xSync: None, + xCommit: None, + xRollback: None, + xFindFunction: None, + xRename: None, + xSavepoint: None, + xRelease: None, + xRollbackTo: None, + ..ZERO_MODULE + }, phantom: PhantomData::, } } @@ -583,11 +591,12 @@ impl<'a> Iterator for ValueIter<'a> { impl Connection { /// `feature = "vtab"` Register a virtual table implementation. /// - /// Step 3 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). + /// Step 3 of [Creating New Virtual Table + /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). pub fn create_module( &self, module_name: &str, - module: &Module, + module: &'static Module, aux: Option, ) -> Result<()> { self.db.borrow_mut().create_module(module_name, module, aux) @@ -598,7 +607,7 @@ impl InnerConnection { fn create_module( &mut self, module_name: &str, - module: &Module, + module: &'static Module, aux: Option, ) -> Result<()> { let c_name = str_to_cstring(module_name)?; diff --git a/src/vtab/series.rs b/src/vtab/series.rs index 46eb28f..3f4f081 100644 --- a/src/vtab/series.rs +++ b/src/vtab/series.rs @@ -9,19 +9,15 @@ use std::os::raw::c_int; use crate::ffi; use crate::types::Type; use crate::vtab::{ - eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection, - VTabCursor, Values, + eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConnection, VTabCursor, + Values, }; use crate::{Connection, Result}; /// `feature = "series"` Register the "generate_series" module. pub fn load_module(conn: &Connection) -> Result<()> { let aux: Option<()> = None; - conn.create_module("generate_series", &SERIES_MODULE, aux) -} - -lazy_static::lazy_static! { - static ref SERIES_MODULE: Module = eponymous_only_module::(1); + conn.create_module("generate_series", eponymous_only_module::(), aux) } // Column numbers diff --git a/tests/vtab.rs b/tests/vtab.rs index 55069b7..d42bac6 100644 --- a/tests/vtab.rs +++ b/tests/vtab.rs @@ -11,7 +11,7 @@ fn test_dummy_module() { use rusqlite::{version_number, Connection, Result}; use std::os::raw::c_int; - let module = eponymous_only_module::(1); + let module = eponymous_only_module::(); #[repr(C)] struct DummyTab { @@ -19,7 +19,7 @@ fn test_dummy_module() { base: sqlite3_vtab, } - impl VTab for DummyTab { + unsafe impl VTab for DummyTab { type Aux = (); type Cursor = DummyTabCursor; @@ -53,7 +53,7 @@ fn test_dummy_module() { row_id: i64, } - impl VTabCursor for DummyTabCursor { + unsafe impl VTabCursor for DummyTabCursor { fn filter( &mut self, _idx_num: c_int,