mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-10-31 13:58:55 +08:00 
			
		
		
		
	Remove macros
This commit is contained in:
		| @@ -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 { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user