diff --git a/src/vtab/csvtab.rs b/src/vtab/csvtab.rs index 5d9ea31..694b47f 100644 --- a/src/vtab/csvtab.rs +++ b/src/vtab/csvtab.rs @@ -20,11 +20,11 @@ pub fn load_module(conn: &Connection) -> Result<()> { init_module!(CSV_MODULE, CSVTab, CSVTabCursor, - Some(csv_connect), + csv_create, csv_connect, csv_best_index, csv_disconnect, - Some(csv_disconnect), + csv_disconnect, csv_open, csv_close, csv_filter, diff --git a/src/vtab/int_array.rs b/src/vtab/int_array.rs index 6acddf6..14992ee 100644 --- a/src/vtab/int_array.rs +++ b/src/vtab/int_array.rs @@ -37,7 +37,7 @@ pub fn drop_int_array(conn: &Connection, name: &str) -> Result<()> { } -init_module!(INT_ARRAY_MODULE, +eponymous_module!(INT_ARRAY_MODULE, IntArrayVTab, IntArrayVTabCursor, Some(int_array_connect), diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index 0218ff6..07792ea 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -46,6 +46,11 @@ pub trait VTab>: Sized { /// Create a new instance of a virtual table in response to a CREATE VIRTUAL TABLE statement. /// The `db` parameter is a pointer to the SQLite database connection that is executing /// the CREATE VIRTUAL TABLE statement. + fn create(db: *mut ffi::sqlite3, aux: *mut c_void, args: &[&[u8]]) -> Result { + Self::connect(db, aux, args) + } + /// Similar to `create`. The difference is that `connect` is called to establish a new connection + /// to an _existing_ virtual table whereas `create` is called to create a new virtual table from scratch. fn connect(db: *mut ffi::sqlite3, aux: *mut c_void, args: &[&[u8]]) -> Result; /// Determine the best way to access the virtual table. fn best_index(&self, info: &mut IndexInfo) -> Result<()>; @@ -335,6 +340,54 @@ unsafe extern "C" fn free_boxed_value(p: *mut c_void) { #[macro_export] macro_rules! init_module { + ($module_name: ident, $vtab: ident, $cursor: ty, + $create: ident, $connect: ident, $best_index: ident, + $disconnect: ident, $destroy: ident, + $open: ident, $close: ident, + $filter: ident, $next: ident, $eof: ident, + $column: ident, $rowid: ident) => { + +static $module_name: ffi::sqlite3_module = ffi::sqlite3_module { + iVersion: 1, + xCreate: Some($create), + xConnect: Some($connect), + xBestIndex: Some($best_index), + xDisconnect: Some($disconnect), + xDestroy: Some($destroy), + xOpen: Some($open), + xClose: Some($close), + xFilter: Some($filter), + xNext: Some($next), + xEof: Some($eof), + xColumn: Some($column), + xRowid: Some($rowid), + xUpdate: None, // TODO + xBegin: None, + xSync: None, + xCommit: None, + xRollback: None, + xFindFunction: None, + xRename: None, + xSavepoint: None, + xRelease: None, + xRollbackTo: None, +}; + +// 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. +create_or_connect!($vtab, $create, create); +common_decl!($vtab, $cursor, + $connect, $best_index, + $disconnect, $destroy, + $open, $close, + $filter, $next, $eof, + $column, $rowid +); + } +} // init_module macro end + +#[macro_export] +macro_rules! eponymous_module { ($module_name: ident, $vtab: ident, $cursor: ty, $create: expr, $connect: ident, $best_index: ident, $disconnect: ident, $destroy: expr, @@ -369,7 +422,19 @@ static $module_name: ffi::sqlite3_module = ffi::sqlite3_module { xRollbackTo: None, }; -unsafe extern "C" fn $connect(db: *mut ffi::sqlite3, +common_decl!($vtab, $cursor, + $connect, $best_index, + $disconnect, $destroy, + $open, $close, + $filter, $next, $eof, + $column, $rowid +); + } +} // eponymous_module macro end + +macro_rules! create_or_connect { + ($vtab: ident, $create_or_connect: ident, $vtab_func: ident) => { +unsafe extern "C" fn $create_or_connect(db: *mut ffi::sqlite3, aux: *mut c_void, argc: c_int, argv: *const *const c_char, @@ -384,7 +449,7 @@ unsafe extern "C" fn $connect(db: *mut ffi::sqlite3, let vec = args.iter().map(|&cs| { CStr::from_ptr(cs).to_bytes() }).collect::>(); - match $vtab::connect(db, aux, &vec[..]) { + match $vtab::$vtab_func(db, aux, &vec[..]) { Ok(vtab) => { let boxed_vtab: *mut $vtab = Box::into_raw(Box::new(vtab)); *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab; @@ -402,6 +467,17 @@ unsafe extern "C" fn $connect(db: *mut ffi::sqlite3, } } } + } +} // create_or_connect macro end + +macro_rules! common_decl { + ($vtab: ident, $cursor: ty, + $connect: ident, $best_index: ident, + $disconnect: ident, $destroy: expr, + $open: ident, $close: ident, + $filter: ident, $next: ident, $eof: ident, + $column: ident, $rowid: ident) => { +create_or_connect!($vtab, $connect, connect); unsafe extern "C" fn $best_index(vtab: *mut ffi::sqlite3_vtab, info: *mut ffi::sqlite3_index_info) -> c_int { @@ -514,7 +590,7 @@ unsafe extern "C" fn $rowid(cursor: *mut ffi::sqlite3_vtab_cursor, } } } -} +} // common_decl macro end /// Virtual table cursors can set an error message by assigning a string to `zErrMsg`. pub unsafe fn cursor_error(cursor: *mut ffi::sqlite3_vtab_cursor, diff --git a/src/vtab/series.rs b/src/vtab/series.rs index f399324..b05468f 100644 --- a/src/vtab/series.rs +++ b/src/vtab/series.rs @@ -13,7 +13,7 @@ pub fn load_module(conn: &Connection) -> Result<()> { conn.create_module("generate_series", &SERIES_MODULE, aux) } -init_module!(SERIES_MODULE, +eponymous_module!(SERIES_MODULE, SeriesTab, SeriesTabCursor, None,