Fix vtab::Module lifetime

This commit is contained in:
Thom Chiovoloni 2020-04-14 07:09:50 -07:00 committed by Thom Chiovoloni
parent e85963852d
commit 3c6b57fe1b
5 changed files with 87 additions and 90 deletions

View File

@ -33,8 +33,8 @@ use std::rc::Rc;
use crate::ffi; use crate::ffi;
use crate::types::{ToSql, ToSqlOutput, Value}; use crate::types::{ToSql, ToSqlOutput, Value};
use crate::vtab::{ use crate::vtab::{
eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection, eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConnection, VTabCursor,
VTabCursor, Values, Values,
}; };
use crate::{Connection, Result}; use crate::{Connection, Result};
@ -57,11 +57,7 @@ impl ToSql for Array {
/// `feature = "array"` Register the "rarray" module. /// `feature = "array"` Register the "rarray" module.
pub fn load_module(conn: &Connection) -> Result<()> { pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None; let aux: Option<()> = None;
conn.create_module("rarray", &ARRAY_MODULE, aux) conn.create_module("rarray", eponymous_only_module::<ArrayTab>(), aux)
}
lazy_static::lazy_static! {
static ref ARRAY_MODULE: Module<ArrayTab> = eponymous_only_module::<ArrayTab>(1);
} }
// Column numbers // Column numbers

View File

@ -30,7 +30,7 @@ use crate::ffi;
use crate::types::Null; use crate::types::Null;
use crate::vtab::{ use crate::vtab::{
dequote, escape_double_quote, parse_boolean, read_only_module, Context, CreateVTab, IndexInfo, 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}; use crate::{Connection, Error, Result};
@ -47,11 +47,7 @@ use crate::{Connection, Error, Result};
/// ``` /// ```
pub fn load_module(conn: &Connection) -> Result<()> { pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None; let aux: Option<()> = None;
conn.create_module("csv", &CSV_MODULE, aux) conn.create_module("csv", read_only_module::<CSVTab>(), aux)
}
lazy_static::lazy_static! {
static ref CSV_MODULE: Module<CSVTab> = read_only_module::<CSVTab>(1);
} }
/// An instance of the CSV virtual table /// An instance of the CSV virtual table

View File

@ -60,7 +60,7 @@ use crate::{str_to_cstring, Connection, Error, InnerConnection, Result};
/// `feature = "vtab"` Virtual table module /// `feature = "vtab"` Virtual table module
/// ///
/// (See [SQLite doc](https://sqlite.org/c3ref/module.html)) /// (See [SQLite doc](https://sqlite.org/c3ref/module.html))
#[repr(C)] #[repr(transparent)]
pub struct Module<T: VTab> { pub struct Module<T: VTab> {
base: ffi::sqlite3_module, base: ffi::sqlite3_module,
phantom: PhantomData<T>, phantom: PhantomData<T>,
@ -69,21 +69,31 @@ pub struct Module<T: VTab> {
unsafe impl<T: VTab> Send for Module<T> {} unsafe impl<T: VTab> Send for Module<T> {}
unsafe impl<T: VTab> Sync for Module<T> {} unsafe impl<T: VTab> Sync for Module<T> {}
// Used as a trailing initializer for sqlite3_module -- this way we avoid having union ModuleZeroHack {
// the build fail if buildtime_bindgen is on bytes: [u8; std::mem::size_of::<ffi::sqlite3_module>()],
fn zeroed_module() -> ffi::sqlite3_module { module: ffi::sqlite3_module,
// This is safe, as bindgen-generated structs are allowed to be zeroed.
unsafe { std::mem::MaybeUninit::zeroed().assume_init() }
} }
// 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::<ffi::sqlite3_module>()],
}
.module
};
/// `feature = "vtab"` Create a read-only virtual table implementation. /// `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). /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
pub fn read_only_module<T: CreateVTab>(version: c_int) -> Module<T> { pub fn read_only_module<T: CreateVTab>() -> &'static Module<T> {
// The xConnect and xCreate methods do the same thing, but they must be // 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. // different so that the virtual table is not an eponymous virtual table.
let ffi_module = ffi::sqlite3_module { &Module {
iVersion: version, 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::<T>), xCreate: Some(rust_create::<T>),
xConnect: Some(rust_connect::<T>), xConnect: Some(rust_connect::<T>),
xBestIndex: Some(rust_best_index::<T>), xBestIndex: Some(rust_best_index::<T>),
@ -106,10 +116,8 @@ pub fn read_only_module<T: CreateVTab>(version: c_int) -> Module<T> {
xSavepoint: None, xSavepoint: None,
xRelease: None, xRelease: None,
xRollbackTo: None, xRollbackTo: None,
..zeroed_module() ..ZERO_MODULE
}; },
Module {
base: ffi_module,
phantom: PhantomData::<T>, phantom: PhantomData::<T>,
} }
} }
@ -117,12 +125,14 @@ pub fn read_only_module<T: CreateVTab>(version: c_int) -> Module<T> {
/// `feature = "vtab"` Create an eponymous only virtual table implementation. /// `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). /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
pub fn eponymous_only_module<T: VTab>(version: c_int) -> Module<T> { pub fn eponymous_only_module<T: VTab>() -> &'static Module<T> {
// A virtual table is eponymous if its xCreate method is the exact same function // 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 // as the xConnect method For eponymous-only virtual tables, the xCreate
// method is NULL // method is NULL
let ffi_module = ffi::sqlite3_module { &Module {
iVersion: version, base: ffi::sqlite3_module {
// We don't use V3
iVersion: 2,
xCreate: None, xCreate: None,
xConnect: Some(rust_connect::<T>), xConnect: Some(rust_connect::<T>),
xBestIndex: Some(rust_best_index::<T>), xBestIndex: Some(rust_best_index::<T>),
@ -145,10 +155,8 @@ pub fn eponymous_only_module<T: VTab>(version: c_int) -> Module<T> {
xSavepoint: None, xSavepoint: None,
xRelease: None, xRelease: None,
xRollbackTo: None, xRollbackTo: None,
..zeroed_module() ..ZERO_MODULE
}; },
Module {
base: ffi_module,
phantom: PhantomData::<T>, phantom: PhantomData::<T>,
} }
} }
@ -583,11 +591,12 @@ impl<'a> Iterator for ValueIter<'a> {
impl Connection { impl Connection {
/// `feature = "vtab"` Register a virtual table implementation. /// `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<T: VTab>( pub fn create_module<T: VTab>(
&self, &self,
module_name: &str, module_name: &str,
module: &Module<T>, module: &'static Module<T>,
aux: Option<T::Aux>, aux: Option<T::Aux>,
) -> Result<()> { ) -> Result<()> {
self.db.borrow_mut().create_module(module_name, module, aux) self.db.borrow_mut().create_module(module_name, module, aux)
@ -598,7 +607,7 @@ impl InnerConnection {
fn create_module<T: VTab>( fn create_module<T: VTab>(
&mut self, &mut self,
module_name: &str, module_name: &str,
module: &Module<T>, module: &'static Module<T>,
aux: Option<T::Aux>, aux: Option<T::Aux>,
) -> Result<()> { ) -> Result<()> {
let c_name = str_to_cstring(module_name)?; let c_name = str_to_cstring(module_name)?;

View File

@ -9,19 +9,15 @@ use std::os::raw::c_int;
use crate::ffi; use crate::ffi;
use crate::types::Type; use crate::types::Type;
use crate::vtab::{ use crate::vtab::{
eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection, eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConnection, VTabCursor,
VTabCursor, Values, Values,
}; };
use crate::{Connection, Result}; use crate::{Connection, Result};
/// `feature = "series"` Register the "generate_series" module. /// `feature = "series"` Register the "generate_series" module.
pub fn load_module(conn: &Connection) -> Result<()> { pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None; let aux: Option<()> = None;
conn.create_module("generate_series", &SERIES_MODULE, aux) conn.create_module("generate_series", eponymous_only_module::<SeriesTab>(), aux)
}
lazy_static::lazy_static! {
static ref SERIES_MODULE: Module<SeriesTab> = eponymous_only_module::<SeriesTab>(1);
} }
// Column numbers // Column numbers

View File

@ -11,7 +11,7 @@ fn test_dummy_module() {
use rusqlite::{version_number, Connection, Result}; use rusqlite::{version_number, Connection, Result};
use std::os::raw::c_int; use std::os::raw::c_int;
let module = eponymous_only_module::<DummyTab>(1); let module = eponymous_only_module::<DummyTab>();
#[repr(C)] #[repr(C)]
struct DummyTab { struct DummyTab {
@ -19,7 +19,7 @@ fn test_dummy_module() {
base: sqlite3_vtab, base: sqlite3_vtab,
} }
impl VTab for DummyTab { unsafe impl VTab for DummyTab {
type Aux = (); type Aux = ();
type Cursor = DummyTabCursor; type Cursor = DummyTabCursor;
@ -53,7 +53,7 @@ fn test_dummy_module() {
row_id: i64, row_id: i64,
} }
impl VTabCursor for DummyTabCursor { unsafe impl VTabCursor for DummyTabCursor {
fn filter( fn filter(
&mut self, &mut self,
_idx_num: c_int, _idx_num: c_int,