mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-24 18:01:37 +08:00
Remove macros
This commit is contained in:
parent
b19d050e39
commit
e2df03f474
@ -29,7 +29,7 @@ limits = []
|
||||
hooks = []
|
||||
sqlcipher = ["libsqlite3-sys/sqlcipher"]
|
||||
unlock_notify = ["libsqlite3-sys/unlock_notify"]
|
||||
vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
|
||||
vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7", "lazy_static"]
|
||||
csvtab = ["csv", "vtab"]
|
||||
# pointer passing interfaces: 3.20.0
|
||||
array = ["vtab"]
|
||||
@ -41,6 +41,7 @@ lru-cache = "0.1"
|
||||
chrono = { version = "0.4", optional = true }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
csv = { version = "1.0", optional = true }
|
||||
lazy_static = { version = "1.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
@ -62,7 +63,7 @@ name = "deny_single_threaded_sqlite_config"
|
||||
name = "vtab"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = [ "backup", "blob", "chrono", "functions", "limits", "load_extension", "serde_json", "trace" ]
|
||||
features = [ "backup", "blob", "chrono", "functions", "limits", "load_extension", "serde_json", "trace", "vtab" ]
|
||||
all-features = false
|
||||
no-default-features = true
|
||||
default-target = "x86_64-unknown-linux-gnu"
|
||||
|
@ -216,12 +216,12 @@ impl error::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
// These are public but not re-exported by lib.rs, so only visible within crate.
|
||||
|
||||
pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
|
||||
Error::SqliteFailure(ffi::Error::new(code), message)
|
||||
}
|
||||
|
||||
// These are public but not re-exported by lib.rs, so only visible within crate.
|
||||
|
||||
pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
|
||||
let message = if db.is_null() {
|
||||
None
|
||||
|
@ -56,7 +56,7 @@ extern crate libsqlite3_sys as ffi;
|
||||
extern crate lru_cache;
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
#[cfg(all(test, feature = "trace"))]
|
||||
#[cfg(any(all(test, feature = "trace"), feature = "vtab"))]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
@ -75,7 +75,7 @@ use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||
use std::os::raw::{c_int, c_char};
|
||||
|
||||
use types::{ToSql, ValueRef};
|
||||
use error::error_from_handle;
|
||||
use error::{error_from_sqlite_code, error_from_handle};
|
||||
use raw_statement::RawStatement;
|
||||
use cache::StatementCache;
|
||||
|
||||
@ -91,7 +91,7 @@ pub use transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior}
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub use error::SqliteError;
|
||||
pub use error::{Error, error_from_sqlite_code};
|
||||
pub use error::Error;
|
||||
pub use ffi::ErrorCode;
|
||||
|
||||
pub use cache::CachedStatement;
|
||||
|
@ -4,11 +4,10 @@ use std::default::Default;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::rc::Rc;
|
||||
|
||||
use error::error_from_sqlite_code;
|
||||
use ffi;
|
||||
use types::{ToSql, ToSqlOutput, Value};
|
||||
use vtab::{self, Context, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
|
||||
use {Connection, Error, Result};
|
||||
use vtab::{eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
|
||||
use {Connection, Result};
|
||||
|
||||
// http://sqlite.org/bindptr.html
|
||||
|
||||
@ -29,50 +28,11 @@ impl ToSql for Array {
|
||||
/// Register the "rarray" module.
|
||||
pub fn load_module(conn: &Connection) -> Result<()> {
|
||||
let aux: Option<()> = None;
|
||||
conn.create_module("rarray", ArrayModule(&ARRAY_MODULE), aux)
|
||||
conn.create_module::<ArrayTab>("rarray", &ARRAY_MODULE, aux)
|
||||
}
|
||||
|
||||
eponymous_module!(
|
||||
ARRAY_MODULE,
|
||||
ArrayModule,
|
||||
ArrayTab,
|
||||
(),
|
||||
ArrayTabCursor,
|
||||
None,
|
||||
array_connect,
|
||||
array_best_index,
|
||||
array_disconnect,
|
||||
None,
|
||||
array_open,
|
||||
array_close,
|
||||
array_filter,
|
||||
array_next,
|
||||
array_eof,
|
||||
array_column,
|
||||
array_rowid
|
||||
);
|
||||
|
||||
#[repr(C)]
|
||||
struct ArrayModule(&'static ffi::sqlite3_module);
|
||||
|
||||
impl Module for ArrayModule {
|
||||
type Aux = ();
|
||||
type Table = ArrayTab;
|
||||
|
||||
fn as_ptr(&self) -> *const ffi::sqlite3_module {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
_aux: Option<&()>,
|
||||
_args: &[&[u8]],
|
||||
) -> Result<(String, ArrayTab)> {
|
||||
let vtab = ArrayTab {
|
||||
base: ffi::sqlite3_vtab::default(),
|
||||
};
|
||||
Ok(("CREATE TABLE x(value,pointer hidden)".to_owned(), vtab))
|
||||
}
|
||||
lazy_static! {
|
||||
static ref ARRAY_MODULE: Module<ArrayTab> = eponymous_only_module::<ArrayTab>();
|
||||
}
|
||||
|
||||
// Column numbers
|
||||
@ -87,8 +47,20 @@ struct ArrayTab {
|
||||
}
|
||||
|
||||
impl VTab for ArrayTab {
|
||||
type Aux = ();
|
||||
type Cursor = ArrayTabCursor;
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
_aux: Option<&()>,
|
||||
_args: &[&[u8]],
|
||||
) -> Result<(String, ArrayTab)> {
|
||||
let vtab = ArrayTab {
|
||||
base: ffi::sqlite3_vtab::default(),
|
||||
};
|
||||
Ok(("CREATE TABLE x(value,pointer hidden)".to_owned(), vtab))
|
||||
}
|
||||
|
||||
fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
|
||||
// Index of the pointer= constraint
|
||||
let mut ptr_idx = None;
|
||||
@ -96,7 +68,7 @@ impl VTab for ArrayTab {
|
||||
if !constraint.is_usable() {
|
||||
continue;
|
||||
}
|
||||
if constraint.operator() != vtab::IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ {
|
||||
if constraint.operator() != IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ {
|
||||
continue;
|
||||
}
|
||||
if let CARRAY_COLUMN_POINTER = constraint.column() {
|
||||
|
@ -2,16 +2,15 @@
|
||||
//! Port of [csv](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/csv.c) C extension.
|
||||
extern crate csv;
|
||||
use std::fs::File;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::os::raw::c_int;
|
||||
use std::path::Path;
|
||||
use std::result;
|
||||
use std::str;
|
||||
|
||||
use error::error_from_sqlite_code;
|
||||
use ffi;
|
||||
use types::Null;
|
||||
use vtab::{
|
||||
dequote, escape_double_quote, parse_boolean, Context, IndexInfo, Module, VTab, VTabConnection,
|
||||
dequote, escape_double_quote, parse_boolean, simple_module, Context, IndexInfo, Module, VTab, VTabConnection,
|
||||
VTabCursor, Values,
|
||||
};
|
||||
use {Connection, Error, Result};
|
||||
@ -29,32 +28,36 @@ use {Connection, Error, Result};
|
||||
/// ```
|
||||
pub fn load_module(conn: &Connection) -> Result<()> {
|
||||
let aux: Option<()> = None;
|
||||
conn.create_module("csv", CSVModule(&CSV_MODULE), aux)
|
||||
conn.create_module::<CSVTab>("csv", &CSV_MODULE, aux)
|
||||
}
|
||||
|
||||
init_module!(
|
||||
CSV_MODULE,
|
||||
CSVModule,
|
||||
CSVTab,
|
||||
(),
|
||||
CSVTabCursor,
|
||||
csv_create,
|
||||
csv_connect,
|
||||
csv_best_index,
|
||||
csv_disconnect,
|
||||
csv_disconnect,
|
||||
csv_open,
|
||||
csv_close,
|
||||
csv_filter,
|
||||
csv_next,
|
||||
csv_eof,
|
||||
csv_column,
|
||||
csv_rowid
|
||||
);
|
||||
lazy_static! {
|
||||
static ref CSV_MODULE: Module<CSVTab> = simple_module::<CSVTab>();
|
||||
}
|
||||
|
||||
struct CSVModule(&'static ffi::sqlite3_module);
|
||||
/// An instance of the CSV virtual table
|
||||
#[repr(C)]
|
||||
struct CSVTab {
|
||||
/// Base class. Must be first
|
||||
base: ffi::sqlite3_vtab,
|
||||
/// Name of the CSV file
|
||||
filename: String,
|
||||
has_headers: bool,
|
||||
delimiter: u8,
|
||||
quote: u8,
|
||||
/// Offset to start of data
|
||||
offset_first_row: csv::Position,
|
||||
}
|
||||
|
||||
impl CSVTab {
|
||||
fn reader(&self) -> result::Result<csv::Reader<File>, csv::Error> {
|
||||
csv::ReaderBuilder::new()
|
||||
.has_headers(self.has_headers)
|
||||
.delimiter(self.delimiter)
|
||||
.quote(self.quote)
|
||||
.from_path(&self.filename)
|
||||
}
|
||||
|
||||
impl CSVModule {
|
||||
fn parameter(c_slice: &[u8]) -> Result<(&str, &str)> {
|
||||
let arg = try!(str::from_utf8(c_slice)).trim();
|
||||
let mut split = arg.split('=');
|
||||
@ -77,13 +80,9 @@ impl CSVModule {
|
||||
}
|
||||
}
|
||||
|
||||
impl Module for CSVModule {
|
||||
impl VTab for CSVTab {
|
||||
type Aux = ();
|
||||
type Table = CSVTab;
|
||||
|
||||
fn as_ptr(&self) -> *const ffi::sqlite3_module {
|
||||
self.0
|
||||
}
|
||||
type Cursor = CSVTabCursor;
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
@ -107,7 +106,7 @@ impl Module for CSVModule {
|
||||
|
||||
let args = &args[3..];
|
||||
for c_slice in args {
|
||||
let (param, value) = try!(CSVModule::parameter(c_slice));
|
||||
let (param, value) = try!(CSVTab::parameter(c_slice));
|
||||
match param {
|
||||
"filename" => {
|
||||
if !Path::new(value).exists() {
|
||||
@ -151,7 +150,7 @@ impl Module for CSVModule {
|
||||
}
|
||||
}
|
||||
"delimiter" => {
|
||||
if let Some(b) = CSVModule::parse_byte(value) {
|
||||
if let Some(b) = CSVTab::parse_byte(value) {
|
||||
vtab.delimiter = b;
|
||||
} else {
|
||||
return Err(Error::ModuleError(format!(
|
||||
@ -161,7 +160,7 @@ impl Module for CSVModule {
|
||||
}
|
||||
}
|
||||
"quote" => {
|
||||
if let Some(b) = CSVModule::parse_byte(value) {
|
||||
if let Some(b) = CSVTab::parse_byte(value) {
|
||||
if b == b'0' {
|
||||
vtab.quote = 0;
|
||||
} else {
|
||||
@ -237,34 +236,6 @@ impl Module for CSVModule {
|
||||
|
||||
Ok((schema.unwrap().to_owned(), vtab))
|
||||
}
|
||||
}
|
||||
|
||||
/// An instance of the CSV virtual table
|
||||
#[repr(C)]
|
||||
struct CSVTab {
|
||||
/// Base class. Must be first
|
||||
base: ffi::sqlite3_vtab,
|
||||
/// Name of the CSV file
|
||||
filename: String,
|
||||
has_headers: bool,
|
||||
delimiter: u8,
|
||||
quote: u8,
|
||||
/// Offset to start of data
|
||||
offset_first_row: csv::Position,
|
||||
}
|
||||
|
||||
impl CSVTab {
|
||||
fn reader(&self) -> result::Result<csv::Reader<File>, csv::Error> {
|
||||
csv::ReaderBuilder::new()
|
||||
.has_headers(self.has_headers)
|
||||
.delimiter(self.delimiter)
|
||||
.quote(self.quote)
|
||||
.from_path(&self.filename)
|
||||
}
|
||||
}
|
||||
|
||||
impl VTab for CSVTab {
|
||||
type Cursor = CSVTabCursor;
|
||||
|
||||
// Only a forward full table scan is supported.
|
||||
fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
|
||||
|
442
src/vtab/mod.rs
442
src/vtab/mod.rs
@ -2,11 +2,14 @@
|
||||
//! (See http://sqlite.org/vtab.html)
|
||||
use std::borrow::Cow::{self, Borrowed, Owned};
|
||||
use std::ffi::CString;
|
||||
use std::marker::PhantomData;
|
||||
use std::marker::Sync;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
use context::set_result;
|
||||
use error::error_from_sqlite_code;
|
||||
use ffi;
|
||||
use types::{FromSql, FromSqlError, ToSql, ValueRef};
|
||||
use {str_to_cstring, Connection, Error, InnerConnection, Result};
|
||||
@ -39,13 +42,91 @@ use {str_to_cstring, Connection, Error, InnerConnection, Result};
|
||||
// \-> if not eof { cursor.column or xrowid } else { cursor.xclose }
|
||||
//
|
||||
|
||||
// db: *mut ffi::sqlite3
|
||||
// db: *mut ffi::sqlite3 => VTabConnection
|
||||
// module: *const ffi::sqlite3_module => Module
|
||||
// aux: *mut c_void => Module::Aux
|
||||
// ffi::sqlite3_vtab => VTab
|
||||
// ffi::sqlite3_vtab_cursor => VTabCursor
|
||||
|
||||
pub struct VTabConnection(pub *mut ffi::sqlite3);
|
||||
#[repr(C)]
|
||||
pub struct Module<T: VTab> {
|
||||
base: ffi::sqlite3_module,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T: VTab> Sync for Module<T> {}
|
||||
|
||||
/// Create a read-only virtual table implementation.
|
||||
pub fn simple_module<T: VTab>() -> Module<T> {
|
||||
// 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: 1,
|
||||
xCreate: Some(rust_create::<T>),
|
||||
xConnect: Some(rust_connect::<T>),
|
||||
xBestIndex: Some(rust_best_index::<T>),
|
||||
xDisconnect: Some(rust_disconnect::<T>),
|
||||
xDestroy: Some(rust_disconnect::<T>), // TODO Validate: no rust_destroy
|
||||
xOpen: Some(rust_open::<T>),
|
||||
xClose: Some(rust_close::<T::Cursor>),
|
||||
xFilter: Some(rust_filter::<T::Cursor>),
|
||||
xNext: Some(rust_next::<T::Cursor>),
|
||||
xEof: Some(rust_eof::<T::Cursor>),
|
||||
xColumn: Some(rust_column::<T::Cursor>),
|
||||
xRowid: Some(rust_rowid::<T::Cursor>),
|
||||
xUpdate: None,
|
||||
xBegin: None,
|
||||
xSync: None,
|
||||
xCommit: None,
|
||||
xRollback: None,
|
||||
xFindFunction: None,
|
||||
xRename: None,
|
||||
xSavepoint: None,
|
||||
xRelease: None,
|
||||
xRollbackTo: None,
|
||||
};
|
||||
Module {
|
||||
base: ffi_module,
|
||||
phantom: PhantomData::<T>,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an eponymous only virtual table implementation.
|
||||
pub fn eponymous_only_module<T: VTab>() -> Module<T> {
|
||||
// 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: 1,
|
||||
xCreate: None,
|
||||
xConnect: Some(rust_connect::<T>),
|
||||
xBestIndex: Some(rust_best_index::<T>),
|
||||
xDisconnect: Some(rust_disconnect::<T>),
|
||||
xDestroy: None,
|
||||
xOpen: Some(rust_open::<T>),
|
||||
xClose: Some(rust_close::<T::Cursor>),
|
||||
xFilter: Some(rust_filter::<T::Cursor>),
|
||||
xNext: Some(rust_next::<T::Cursor>),
|
||||
xEof: Some(rust_eof::<T::Cursor>),
|
||||
xColumn: Some(rust_column::<T::Cursor>),
|
||||
xRowid: Some(rust_rowid::<T::Cursor>),
|
||||
xUpdate: None,
|
||||
xBegin: None,
|
||||
xSync: None,
|
||||
xCommit: None,
|
||||
xRollback: None,
|
||||
xFindFunction: None,
|
||||
xRename: None,
|
||||
xSavepoint: None,
|
||||
xRelease: None,
|
||||
xRollbackTo: None,
|
||||
};
|
||||
Module {
|
||||
base: ffi_module,
|
||||
phantom: PhantomData::<T>,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VTabConnection(*mut ffi::sqlite3);
|
||||
|
||||
impl VTabConnection {
|
||||
/// Get access to the underlying SQLite database connection handle.
|
||||
@ -61,12 +142,10 @@ impl VTabConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/// Module instance trait
|
||||
pub trait Module {
|
||||
/// Virtual table instance trait.
|
||||
pub trait VTab: Sized {
|
||||
type Aux;
|
||||
type Table: VTab;
|
||||
|
||||
fn as_ptr(&self) -> *const ffi::sqlite3_module;
|
||||
type Cursor: VTabCursor;
|
||||
|
||||
/// 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
|
||||
@ -75,22 +154,19 @@ pub trait Module {
|
||||
db: &mut VTabConnection,
|
||||
aux: Option<&Self::Aux>,
|
||||
args: &[&[u8]],
|
||||
) -> Result<(String, Self::Table)> {
|
||||
) -> Result<(String, Self)> {
|
||||
Self::connect(db, aux, args)
|
||||
}
|
||||
|
||||
// TODO Validate: no destroy
|
||||
|
||||
/// 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 VTabConnection,
|
||||
aux: Option<&Self::Aux>,
|
||||
args: &[&[u8]],
|
||||
) -> Result<(String, Self::Table)>;
|
||||
}
|
||||
|
||||
/// Virtual table instance trait.
|
||||
pub trait VTab: Sized {
|
||||
type Cursor: VTabCursor;
|
||||
|
||||
) -> Result<(String, Self)>;
|
||||
/// Determine the best way to access the virtual table.
|
||||
fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
|
||||
/// Create a new cursor used for accessing a virtual table.
|
||||
@ -110,7 +186,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IndexInfo(pub *mut ffi::sqlite3_index_info);
|
||||
pub struct IndexInfo(*mut ffi::sqlite3_index_info);
|
||||
|
||||
impl IndexInfo {
|
||||
pub fn constraints(&self) -> IndexConstraintIter {
|
||||
@ -265,7 +341,7 @@ pub trait VTabCursor: Sized {
|
||||
fn rowid(&self) -> Result<i64>;
|
||||
}
|
||||
|
||||
pub struct Context(pub *mut ffi::sqlite3_context);
|
||||
pub struct Context(*mut ffi::sqlite3_context);
|
||||
|
||||
impl Context {
|
||||
pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
|
||||
@ -276,7 +352,7 @@ impl Context {
|
||||
}
|
||||
|
||||
pub struct Values<'a> {
|
||||
pub args: &'a [*mut ffi::sqlite3_value],
|
||||
args: &'a [*mut ffi::sqlite3_value],
|
||||
}
|
||||
|
||||
impl<'a> Values<'a> {
|
||||
@ -352,34 +428,34 @@ impl<'a> Iterator for ValueIter<'a> {
|
||||
|
||||
impl Connection {
|
||||
/// Register a virtual table implementation.
|
||||
pub fn create_module<M: Module>(
|
||||
pub fn create_module<T: VTab>(
|
||||
&self,
|
||||
module_name: &str,
|
||||
module: M,
|
||||
aux: Option<M::Aux>,
|
||||
module: &Module<T>,
|
||||
aux: Option<T::Aux>,
|
||||
) -> Result<()> {
|
||||
self.db.borrow_mut().create_module(module_name, module, aux)
|
||||
self.db.borrow_mut().create_module::<T>(module_name, module, aux)
|
||||
}
|
||||
}
|
||||
|
||||
impl InnerConnection {
|
||||
fn create_module<M: Module>(
|
||||
fn create_module<T: VTab>(
|
||||
&mut self,
|
||||
module_name: &str,
|
||||
module: M,
|
||||
aux: Option<M::Aux>,
|
||||
module: &Module<T>,
|
||||
aux: Option<T::Aux>,
|
||||
) -> Result<()> {
|
||||
let c_name = try!(str_to_cstring(module_name));
|
||||
let r = match aux {
|
||||
Some(aux) => {
|
||||
let boxed_aux: *mut M::Aux = Box::into_raw(Box::new(aux));
|
||||
let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
|
||||
unsafe {
|
||||
ffi::sqlite3_create_module_v2(
|
||||
self.db(),
|
||||
c_name.as_ptr(),
|
||||
module.as_ptr(),
|
||||
&module.base,
|
||||
boxed_aux as *mut c_void,
|
||||
Some(free_boxed_value::<M::Aux>),
|
||||
Some(free_boxed_value::<T::Aux>),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -387,7 +463,7 @@ impl InnerConnection {
|
||||
ffi::sqlite3_create_module_v2(
|
||||
self.db(),
|
||||
c_name.as_ptr(),
|
||||
module.as_ptr(),
|
||||
&module.base,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
)
|
||||
@ -447,174 +523,33 @@ unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
|
||||
let _: Box<T> = Box::from_raw(p as *mut T);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! init_module {
|
||||
(
|
||||
$module_name:ident,
|
||||
$module:ident,
|
||||
$vtab:ident,
|
||||
$aux:ty,
|
||||
$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!($module, $vtab, $aux, $create, create);
|
||||
common_decl!(
|
||||
$module,
|
||||
$vtab,
|
||||
$aux,
|
||||
$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,
|
||||
$module:ident,
|
||||
$vtab:ident,
|
||||
$aux:ty,
|
||||
$cursor:ty,
|
||||
$create:expr,
|
||||
$connect:ident,
|
||||
$best_index:ident,
|
||||
$disconnect:ident,
|
||||
$destroy:expr,
|
||||
$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: $create, /* For eponymous-only virtual tables, the xCreate method is NULL */
|
||||
xConnect: Some($connect), /* A virtual table is eponymous if its xCreate method is
|
||||
the exact same function as the xConnect method */
|
||||
xBestIndex: Some($best_index),
|
||||
xDisconnect: Some($disconnect),
|
||||
xDestroy: $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,
|
||||
};
|
||||
|
||||
common_decl!(
|
||||
$module,
|
||||
$vtab,
|
||||
$aux,
|
||||
$cursor,
|
||||
$connect,
|
||||
$best_index,
|
||||
$disconnect,
|
||||
$destroy,
|
||||
$open,
|
||||
$close,
|
||||
$filter,
|
||||
$next,
|
||||
$eof,
|
||||
$column,
|
||||
$rowid
|
||||
);
|
||||
};
|
||||
} // eponymous_module macro end
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! create_or_connect {
|
||||
($module:ident, $vtab:ident, $aux:ty, $create_or_connect:ident, $module_func:ident) => {
|
||||
unsafe extern "C" fn $create_or_connect(
|
||||
unsafe extern "C" fn rust_create<T>(
|
||||
db: *mut ffi::sqlite3,
|
||||
aux: *mut c_void,
|
||||
argc: c_int,
|
||||
argv: *const *const c_char,
|
||||
pp_vtab: *mut *mut ffi::sqlite3_vtab,
|
||||
err_msg: *mut *mut c_char,
|
||||
) -> c_int {
|
||||
) -> c_int
|
||||
where T: VTab {
|
||||
use std::error::Error as StdError;
|
||||
use std::ffi::CStr;
|
||||
use std::slice;
|
||||
use $crate::vtab::mprintf;
|
||||
|
||||
let mut conn = VTabConnection(db);
|
||||
let aux = aux as *mut $aux;
|
||||
let aux = aux as *mut T::Aux;
|
||||
let args = slice::from_raw_parts(argv, argc as usize);
|
||||
let vec = args
|
||||
.iter()
|
||||
.map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
|
||||
.collect::<Vec<_>>();
|
||||
match $module::$module_func(&mut conn, aux.as_ref(), &vec[..]) {
|
||||
match T::create(&mut conn, aux.as_ref(), &vec[..]) {
|
||||
Ok((sql, vtab)) => {
|
||||
match ::std::ffi::CString::new(sql) {
|
||||
Ok(c_sql) => {
|
||||
let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
|
||||
if rc == ffi::SQLITE_OK {
|
||||
let boxed_vtab: *mut $vtab = Box::into_raw(Box::new(vtab));
|
||||
let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
|
||||
*pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
|
||||
ffi::SQLITE_OK
|
||||
} else {
|
||||
@ -641,36 +576,68 @@ macro_rules! create_or_connect {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // create_or_connect macro end
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! common_decl {
|
||||
(
|
||||
$module:ident,
|
||||
$vtab:ident,
|
||||
$aux:ty,
|
||||
$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!($module, $vtab, $aux, $connect, connect);
|
||||
unsafe extern "C" fn $best_index(
|
||||
unsafe extern "C" fn rust_connect<T>(
|
||||
db: *mut ffi::sqlite3,
|
||||
aux: *mut c_void,
|
||||
argc: c_int,
|
||||
argv: *const *const c_char,
|
||||
pp_vtab: *mut *mut ffi::sqlite3_vtab,
|
||||
err_msg: *mut *mut c_char,
|
||||
) -> c_int
|
||||
where T: VTab {
|
||||
use std::error::Error as StdError;
|
||||
use std::ffi::CStr;
|
||||
use std::slice;
|
||||
|
||||
let mut conn = VTabConnection(db);
|
||||
let aux = aux as *mut T::Aux;
|
||||
let args = slice::from_raw_parts(argv, argc as usize);
|
||||
let vec = args
|
||||
.iter()
|
||||
.map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
|
||||
.collect::<Vec<_>>();
|
||||
match T::connect(&mut conn, aux.as_ref(), &vec[..]) {
|
||||
Ok((sql, vtab)) => {
|
||||
match ::std::ffi::CString::new(sql) {
|
||||
Ok(c_sql) => {
|
||||
let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
|
||||
if rc == ffi::SQLITE_OK {
|
||||
let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
|
||||
*pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
|
||||
ffi::SQLITE_OK
|
||||
} else {
|
||||
let err = error_from_sqlite_code(rc, None);
|
||||
*err_msg = mprintf(err.description());
|
||||
rc
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
*err_msg = mprintf(err.description());
|
||||
ffi::SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::SqliteFailure(err, s)) => {
|
||||
if let Some(s) = s {
|
||||
*err_msg = mprintf(&s);
|
||||
}
|
||||
err.extended_code
|
||||
}
|
||||
Err(err) => {
|
||||
*err_msg = mprintf(err.description());
|
||||
ffi::SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn rust_best_index<T>(
|
||||
vtab: *mut ffi::sqlite3_vtab,
|
||||
info: *mut ffi::sqlite3_index_info,
|
||||
) -> c_int {
|
||||
) -> c_int
|
||||
where T: VTab {
|
||||
use std::error::Error as StdError;
|
||||
use $crate::vtab::set_err_msg;
|
||||
let vt = vtab as *mut $vtab;
|
||||
let vt = vtab as *mut T;
|
||||
let mut idx_info = IndexInfo(info);
|
||||
match (*vt).best_index(&mut idx_info) {
|
||||
Ok(_) => ffi::SQLITE_OK,
|
||||
@ -686,22 +653,24 @@ macro_rules! common_decl {
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe extern "C" fn $disconnect(vtab: *mut ffi::sqlite3_vtab) -> c_int {
|
||||
let vtab = vtab as *mut $vtab;
|
||||
let _: Box<$vtab> = Box::from_raw(vtab);
|
||||
|
||||
unsafe extern "C" fn rust_disconnect<T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
|
||||
where T: VTab {
|
||||
let vtab = vtab as *mut T;
|
||||
let _: Box<T> = Box::from_raw(vtab);
|
||||
ffi::SQLITE_OK
|
||||
}
|
||||
|
||||
unsafe extern "C" fn $open(
|
||||
unsafe extern "C" fn rust_open<T>(
|
||||
vtab: *mut ffi::sqlite3_vtab,
|
||||
pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor,
|
||||
) -> c_int {
|
||||
) -> c_int
|
||||
where T: VTab {
|
||||
use std::error::Error as StdError;
|
||||
use $crate::vtab::set_err_msg;
|
||||
let vt = vtab as *mut $vtab;
|
||||
let vt = vtab as *mut T;
|
||||
match (*vt).open() {
|
||||
Ok(cursor) => {
|
||||
let boxed_cursor: *mut $cursor = Box::into_raw(Box::new(cursor));
|
||||
let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
|
||||
*pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor;
|
||||
ffi::SQLITE_OK
|
||||
}
|
||||
@ -717,23 +686,25 @@ macro_rules! common_decl {
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe extern "C" fn $close(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int {
|
||||
let cr = cursor as *mut $cursor;
|
||||
let _: Box<$cursor> = Box::from_raw(cr);
|
||||
|
||||
unsafe extern "C" fn rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
|
||||
where C: VTabCursor {
|
||||
let cr = cursor as *mut C;
|
||||
let _: Box<C> = Box::from_raw(cr);
|
||||
ffi::SQLITE_OK
|
||||
}
|
||||
|
||||
unsafe extern "C" fn $filter(
|
||||
unsafe extern "C" fn rust_filter<C>(
|
||||
cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||
idx_num: c_int,
|
||||
idx_str: *const c_char,
|
||||
argc: c_int,
|
||||
argv: *mut *mut ffi::sqlite3_value,
|
||||
) -> c_int {
|
||||
) -> c_int
|
||||
where C: VTabCursor {
|
||||
use std::ffi::CStr;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
use $crate::vtab::{cursor_error, Values};
|
||||
let idx_name = if idx_str.is_null() {
|
||||
None
|
||||
} else {
|
||||
@ -742,34 +713,39 @@ macro_rules! common_decl {
|
||||
};
|
||||
let args = slice::from_raw_parts_mut(argv, argc as usize);
|
||||
let values = Values { args: args };
|
||||
let cr = cursor as *mut $cursor;
|
||||
let cr = cursor as *mut C;
|
||||
cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values))
|
||||
}
|
||||
unsafe extern "C" fn $next(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int {
|
||||
use $crate::vtab::cursor_error;
|
||||
let cr = cursor as *mut $cursor;
|
||||
|
||||
unsafe extern "C" fn rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
|
||||
where C: VTabCursor {
|
||||
let cr = cursor as *mut C;
|
||||
cursor_error(cursor, (*cr).next())
|
||||
}
|
||||
unsafe extern "C" fn $eof(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int {
|
||||
let cr = cursor as *mut $cursor;
|
||||
|
||||
unsafe extern "C" fn rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
|
||||
where C: VTabCursor {
|
||||
let cr = cursor as *mut C;
|
||||
(*cr).eof() as c_int
|
||||
}
|
||||
unsafe extern "C" fn $column(
|
||||
|
||||
unsafe extern "C" fn rust_column<C>(
|
||||
cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||
ctx: *mut ffi::sqlite3_context,
|
||||
i: c_int,
|
||||
) -> c_int {
|
||||
use $crate::vtab::{result_error, Context};
|
||||
let cr = cursor as *mut $cursor;
|
||||
) -> c_int
|
||||
where C: VTabCursor {
|
||||
let cr = cursor as *mut C;
|
||||
let mut ctxt = Context(ctx);
|
||||
result_error(ctx, (*cr).column(&mut ctxt, i))
|
||||
}
|
||||
unsafe extern "C" fn $rowid(
|
||||
|
||||
unsafe extern "C" fn rust_rowid<C>(
|
||||
cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||
p_rowid: *mut ffi::sqlite3_int64,
|
||||
) -> c_int {
|
||||
use $crate::vtab::cursor_error;
|
||||
let cr = cursor as *mut $cursor;
|
||||
) -> c_int
|
||||
where C: VTabCursor {
|
||||
let cr = cursor as *mut C;
|
||||
match (*cr).rowid() {
|
||||
Ok(rowid) => {
|
||||
*p_rowid = rowid;
|
||||
@ -778,8 +754,6 @@ macro_rules! common_decl {
|
||||
err => cursor_error(cursor, err),
|
||||
}
|
||||
}
|
||||
};
|
||||
} // common_decl macro end
|
||||
|
||||
/// Virtual table cursors can set an error message by assigning a string to `zErrMsg`.
|
||||
pub unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int {
|
||||
@ -800,7 +774,7 @@ pub unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Res
|
||||
}
|
||||
|
||||
/// Virtual tables methods can set an error message by assigning a string to `zErrMsg`.
|
||||
pub unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
|
||||
unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
|
||||
if !(*vtab).zErrMsg.is_null() {
|
||||
ffi::sqlite3_free((*vtab).zErrMsg as *mut c_void);
|
||||
}
|
||||
@ -809,7 +783,7 @@ pub unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
|
||||
|
||||
/// To raise an error, the `column` method should use this method to set the error message
|
||||
/// and return the error code.
|
||||
pub unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
|
||||
unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
|
||||
use std::error::Error as StdError;
|
||||
match result {
|
||||
Ok(_) => ffi::SQLITE_OK,
|
||||
|
@ -1,64 +1,21 @@
|
||||
//! generate series virtual table.
|
||||
//! Port of C [generate series "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c).
|
||||
use std::default::Default;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use error::error_from_sqlite_code;
|
||||
use ffi;
|
||||
use types::Type;
|
||||
use vtab::{self, Context, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
|
||||
use {Connection, Error, Result};
|
||||
use vtab::{eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
|
||||
use {Connection, Result};
|
||||
|
||||
/// Register the "generate_series" module.
|
||||
pub fn load_module(conn: &Connection) -> Result<()> {
|
||||
let aux: Option<()> = None;
|
||||
conn.create_module("generate_series", Series(&SERIES_MODULE), aux)
|
||||
conn.create_module::<SeriesTab>("generate_series", &SERIES_MODULE, aux)
|
||||
}
|
||||
|
||||
eponymous_module!(
|
||||
SERIES_MODULE,
|
||||
Series,
|
||||
SeriesTab,
|
||||
(),
|
||||
SeriesTabCursor,
|
||||
None,
|
||||
series_connect,
|
||||
series_best_index,
|
||||
series_disconnect,
|
||||
None,
|
||||
series_open,
|
||||
series_close,
|
||||
series_filter,
|
||||
series_next,
|
||||
series_eof,
|
||||
series_column,
|
||||
series_rowid
|
||||
);
|
||||
|
||||
#[repr(C)]
|
||||
struct Series(&'static ffi::sqlite3_module);
|
||||
|
||||
impl Module for Series {
|
||||
type Aux = ();
|
||||
type Table = SeriesTab;
|
||||
|
||||
fn as_ptr(&self) -> *const ffi::sqlite3_module {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
_aux: Option<&()>,
|
||||
_args: &[&[u8]],
|
||||
) -> Result<(String, SeriesTab)> {
|
||||
let vtab = SeriesTab {
|
||||
base: ffi::sqlite3_vtab::default(),
|
||||
};
|
||||
Ok((
|
||||
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)".to_owned(),
|
||||
vtab,
|
||||
))
|
||||
}
|
||||
lazy_static! {
|
||||
static ref SERIES_MODULE: Module<SeriesTab> = eponymous_only_module::<SeriesTab>();
|
||||
}
|
||||
|
||||
// Column numbers
|
||||
@ -91,8 +48,23 @@ struct SeriesTab {
|
||||
}
|
||||
|
||||
impl VTab for SeriesTab {
|
||||
type Aux = ();
|
||||
type Cursor = SeriesTabCursor;
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
_aux: Option<&()>,
|
||||
_args: &[&[u8]],
|
||||
) -> Result<(String, SeriesTab)> {
|
||||
let vtab = SeriesTab {
|
||||
base: ffi::sqlite3_vtab::default(),
|
||||
};
|
||||
Ok((
|
||||
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)".to_owned(),
|
||||
vtab,
|
||||
))
|
||||
}
|
||||
|
||||
fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
|
||||
// The query plan bitmask
|
||||
let mut idx_num: QueryPlanFlags = QueryPlanFlags::empty();
|
||||
@ -106,7 +78,7 @@ impl VTab for SeriesTab {
|
||||
if !constraint.is_usable() {
|
||||
continue;
|
||||
}
|
||||
if constraint.operator() != vtab::IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ {
|
||||
if constraint.operator() != IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ {
|
||||
continue;
|
||||
}
|
||||
match constraint.column() {
|
||||
|
@ -1,7 +1,6 @@
|
||||
//! Ensure Virtual tables can be declared outside `rusqlite` crate.
|
||||
|
||||
#[cfg(feature = "vtab")]
|
||||
#[macro_use]
|
||||
extern crate rusqlite;
|
||||
extern crate libsqlite3_sys as ffi;
|
||||
|
||||
@ -9,41 +8,22 @@ extern crate libsqlite3_sys as ffi;
|
||||
#[test]
|
||||
fn test_dummy_module() {
|
||||
use ffi;
|
||||
use rusqlite::vtab::{Context, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
|
||||
use rusqlite::{error_from_sqlite_code, Connection, Error, Result};
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use rusqlite::vtab::{eponymous_only_module, Context, IndexInfo, VTab, VTabConnection, VTabCursor, Values};
|
||||
use rusqlite::{Connection, Result};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
eponymous_module!(
|
||||
DUMMY_MODULE,
|
||||
DummyModule,
|
||||
DummyTab,
|
||||
(),
|
||||
DummyTabCursor,
|
||||
None,
|
||||
dummy_connect,
|
||||
dummy_best_index,
|
||||
dummy_disconnect,
|
||||
None,
|
||||
dummy_open,
|
||||
dummy_close,
|
||||
dummy_filter,
|
||||
dummy_next,
|
||||
dummy_eof,
|
||||
dummy_column,
|
||||
dummy_rowid
|
||||
);
|
||||
let module = eponymous_only_module::<DummyTab>();
|
||||
|
||||
#[repr(C)]
|
||||
struct DummyModule(&'static ffi::sqlite3_module);
|
||||
|
||||
impl Module for DummyModule {
|
||||
type Aux = ();
|
||||
type Table = DummyTab;
|
||||
|
||||
fn as_ptr(&self) -> *const ffi::sqlite3_module {
|
||||
self.0
|
||||
struct DummyTab {
|
||||
/// Base class. Must be first
|
||||
base: ffi::sqlite3_vtab,
|
||||
}
|
||||
|
||||
impl VTab for DummyTab {
|
||||
type Aux = ();
|
||||
type Cursor = DummyTabCursor;
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
_aux: Option<&()>,
|
||||
@ -54,16 +34,6 @@ fn test_dummy_module() {
|
||||
};
|
||||
Ok(("CREATE TABLE x(value)".to_owned(), vtab))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct DummyTab {
|
||||
/// Base class. Must be first
|
||||
base: ffi::sqlite3_vtab,
|
||||
}
|
||||
|
||||
impl VTab for DummyTab {
|
||||
type Cursor = DummyTabCursor;
|
||||
|
||||
fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
|
||||
info.set_estimated_cost(1.);
|
||||
@ -116,9 +86,7 @@ fn test_dummy_module() {
|
||||
|
||||
let db = Connection::open_in_memory().unwrap();
|
||||
|
||||
let module = DummyModule(&DUMMY_MODULE);
|
||||
|
||||
db.create_module("dummy", module, None).unwrap();
|
||||
db.create_module::<DummyTab>("dummy", &module, None).unwrap();
|
||||
|
||||
let version = unsafe { ffi::sqlite3_libversion_number() };
|
||||
if version < 3008012 {
|
||||
|
Loading…
Reference in New Issue
Block a user