1 //! `feature = "vtab"` Create virtual tables.
2 //!
3 //! Follow these steps to create your own virtual table:
4 //! 1. Write implemenation of `VTab` and `VTabCursor` traits.
5 //! 2. Create an instance of the `Module` structure specialized for `VTab` impl.
6 //! from step 1.
7 //! 3. Register your `Module` structure using `Connection.create_module`.
8 //! 4. Run a `CREATE VIRTUAL TABLE` command that specifies the new module in the
9 //! `USING` clause.
10 //!
11 //! (See [SQLite doc](http://sqlite.org/vtab.html))
12 use std::borrow::Cow::{self, Borrowed, Owned};
13 use std::marker::PhantomData;
14 use std::marker::Sync;
15 use std::os::raw::{c_char, c_int, c_void};
16 use std::ptr;
17 use std::slice;
18 
19 use crate::context::set_result;
20 use crate::error::error_from_sqlite_code;
21 use crate::ffi;
22 pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor};
23 use crate::types::{FromSql, FromSqlError, ToSql, ValueRef};
24 use crate::{str_to_cstring, Connection, Error, InnerConnection, Result};
25 
26 // let conn: Connection = ...;
27 // let mod: Module = ...; // VTab builder
28 // conn.create_module("module", mod);
29 //
30 // conn.execute("CREATE VIRTUAL TABLE foo USING module(...)");
31 // \-> Module::xcreate
32 //  |-> let vtab: VTab = ...; // on the heap
33 //  \-> conn.declare_vtab("CREATE TABLE foo (...)");
34 // conn = Connection::open(...);
35 // \-> Module::xconnect
36 //  |-> let vtab: VTab = ...; // on the heap
37 //  \-> conn.declare_vtab("CREATE TABLE foo (...)");
38 //
39 // conn.close();
40 // \-> vtab.xdisconnect
41 // conn.execute("DROP TABLE foo");
42 // \-> vtab.xDestroy
43 //
44 // let stmt = conn.prepare("SELECT ... FROM foo WHERE ...");
45 // \-> vtab.xbestindex
46 // stmt.query().next();
47 // \-> vtab.xopen
48 //  |-> let cursor: VTabCursor = ...; // on the heap
49 //  |-> cursor.xfilter or xnext
50 //  |-> cursor.xeof
51 //  \-> if not eof { cursor.column or xrowid } else { cursor.xclose }
52 //
53 
54 // db: *mut ffi::sqlite3 => VTabConnection
55 // module: *const ffi::sqlite3_module => Module
56 // aux: *mut c_void => Module::Aux
57 // ffi::sqlite3_vtab => VTab
58 // ffi::sqlite3_vtab_cursor => VTabCursor
59 
60 /// `feature = "vtab"` Virtual table module
61 ///
62 /// (See [SQLite doc](https://sqlite.org/c3ref/module.html))
63 #[repr(transparent)]
64 pub struct Module<'vtab, T: VTab<'vtab>> {
65     base: ffi::sqlite3_module,
66     phantom: PhantomData<&'vtab T>,
67 }
68 
69 unsafe impl<'vtab, T: VTab<'vtab>> Send for Module<'vtab, T> {}
70 unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {}
71 
72 union ModuleZeroHack {
73     bytes: [u8; std::mem::size_of::<ffi::sqlite3_module>()],
74     module: ffi::sqlite3_module,
75 }
76 
77 // Used as a trailing initializer for sqlite3_module -- this way we avoid having
78 // the build fail if buildtime_bindgen is on. This is safe, as bindgen-generated
79 // structs are allowed to be zeroed.
80 const ZERO_MODULE: ffi::sqlite3_module = unsafe {
81     ModuleZeroHack {
82         bytes: [0u8; std::mem::size_of::<ffi::sqlite3_module>()],
83     }
84     .module
85 };
86 
87 /// `feature = "vtab"` Create a read-only virtual table implementation.
88 ///
89 /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T>90 pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> {
91     // The xConnect and xCreate methods do the same thing, but they must be
92     // different so that the virtual table is not an eponymous virtual table.
93     &Module {
94         base: ffi::sqlite3_module {
95             // We don't use V3
96             iVersion: 2, // We don't use V2 or V3 features in read_only_module types
97             xCreate: Some(rust_create::<T>),
98             xConnect: Some(rust_connect::<T>),
99             xBestIndex: Some(rust_best_index::<T>),
100             xDisconnect: Some(rust_disconnect::<T>),
101             xDestroy: Some(rust_destroy::<T>),
102             xOpen: Some(rust_open::<T>),
103             xClose: Some(rust_close::<T::Cursor>),
104             xFilter: Some(rust_filter::<T::Cursor>),
105             xNext: Some(rust_next::<T::Cursor>),
106             xEof: Some(rust_eof::<T::Cursor>),
107             xColumn: Some(rust_column::<T::Cursor>),
108             xRowid: Some(rust_rowid::<T::Cursor>),
109             xUpdate: None,
110             xBegin: None,
111             xSync: None,
112             xCommit: None,
113             xRollback: None,
114             xFindFunction: None,
115             xRename: None,
116             xSavepoint: None,
117             xRelease: None,
118             xRollbackTo: None,
119             ..ZERO_MODULE
120         },
121         phantom: PhantomData::<&'vtab T>,
122     }
123 }
124 
125 /// `feature = "vtab"` Create an eponymous only virtual table implementation.
126 ///
127 /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T>128 pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> {
129     // A virtual table is eponymous if its xCreate method is the exact same function
130     // as the xConnect method For eponymous-only virtual tables, the xCreate
131     // method is NULL
132     &Module {
133         base: ffi::sqlite3_module {
134             // We don't use V3
135             iVersion: 2,
136             xCreate: None,
137             xConnect: Some(rust_connect::<T>),
138             xBestIndex: Some(rust_best_index::<T>),
139             xDisconnect: Some(rust_disconnect::<T>),
140             xDestroy: None,
141             xOpen: Some(rust_open::<T>),
142             xClose: Some(rust_close::<T::Cursor>),
143             xFilter: Some(rust_filter::<T::Cursor>),
144             xNext: Some(rust_next::<T::Cursor>),
145             xEof: Some(rust_eof::<T::Cursor>),
146             xColumn: Some(rust_column::<T::Cursor>),
147             xRowid: Some(rust_rowid::<T::Cursor>),
148             xUpdate: None,
149             xBegin: None,
150             xSync: None,
151             xCommit: None,
152             xRollback: None,
153             xFindFunction: None,
154             xRename: None,
155             xSavepoint: None,
156             xRelease: None,
157             xRollbackTo: None,
158             ..ZERO_MODULE
159         },
160         phantom: PhantomData::<&'vtab T>,
161     }
162 }
163 
164 /// `feature = "vtab"`
165 pub struct VTabConnection(*mut ffi::sqlite3);
166 
167 impl VTabConnection {
168     // TODO sqlite3_vtab_config (http://sqlite.org/c3ref/vtab_config.html)
169 
170     // TODO sqlite3_vtab_on_conflict (http://sqlite.org/c3ref/vtab_on_conflict.html)
171 
172     /// Get access to the underlying SQLite database connection handle.
173     ///
174     /// # Warning
175     ///
176     /// You should not need to use this function. If you do need to, please
177     /// [open an issue on the rusqlite repository](https://github.com/rusqlite/rusqlite/issues) and describe
178     /// your use case.
179     ///
180     /// # Safety
181     ///
182     /// This function is unsafe because it gives you raw access
183     /// to the SQLite connection, and what you do with it could impact the
184     /// safety of this `Connection`.
handle(&mut self) -> *mut ffi::sqlite3185     pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
186         self.0
187     }
188 }
189 
190 /// `feature = "vtab"` Virtual table instance trait.
191 ///
192 /// # Safety
193 ///
194 /// The first item in a struct implementing VTab must be
195 /// `rusqlite::sqlite3_vtab`, and the struct must be `#[repr(C)]`.
196 ///
197 /// ```rust,ignore
198 /// #[repr(C)]
199 /// struct MyTab {
200 ///    /// Base class. Must be first
201 ///    base: ffi::sqlite3_vtab,
202 ///    /* Virtual table implementations will typically add additional fields */
203 /// }
204 /// ```
205 ///
206 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
207 pub unsafe trait VTab<'vtab>: Sized {
208     /// Client data passed to `Connection::create_module`.
209     type Aux;
210     /// Specific cursor implementation
211     type Cursor: VTabCursor;
212 
213     /// Establish a new connection to an existing virtual table.
214     ///
215     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xconnect_method))
connect( db: &mut VTabConnection, aux: Option<&Self::Aux>, args: &[&[u8]], ) -> Result<(String, Self)>216     fn connect(
217         db: &mut VTabConnection,
218         aux: Option<&Self::Aux>,
219         args: &[&[u8]],
220     ) -> Result<(String, Self)>;
221 
222     /// Determine the best way to access the virtual table.
223     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xbestindex_method))
best_index(&self, info: &mut IndexInfo) -> Result<()>224     fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
225 
226     /// Create a new cursor used for accessing a virtual table.
227     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xopen_method))
open(&'vtab self) -> Result<Self::Cursor>228     fn open(&'vtab self) -> Result<Self::Cursor>;
229 }
230 
231 /// `feature = "vtab"` Non-eponymous virtual table instance trait.
232 ///
233 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
234 pub trait CreateVTab<'vtab>: VTab<'vtab> {
235     /// Create a new instance of a virtual table in response to a CREATE VIRTUAL
236     /// TABLE statement. The `db` parameter is a pointer to the SQLite
237     /// database connection that is executing the CREATE VIRTUAL TABLE
238     /// statement.
239     ///
240     /// Call `connect` by default.
241     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcreate_method))
create( db: &mut VTabConnection, aux: Option<&Self::Aux>, args: &[&[u8]], ) -> Result<(String, Self)>242     fn create(
243         db: &mut VTabConnection,
244         aux: Option<&Self::Aux>,
245         args: &[&[u8]],
246     ) -> Result<(String, Self)> {
247         Self::connect(db, aux, args)
248     }
249 
250     /// Destroy the underlying table implementation. This method undoes the work
251     /// of `create`.
252     ///
253     /// Do nothing by default.
254     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xdestroy_method))
destroy(&self) -> Result<()>255     fn destroy(&self) -> Result<()> {
256         Ok(())
257     }
258 }
259 
260 /// `feature = "vtab"` Index constraint operator.
261 /// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
262 #[derive(Debug, PartialEq)]
263 #[allow(non_snake_case, non_camel_case_types, missing_docs)]
264 #[non_exhaustive]
265 pub enum IndexConstraintOp {
266     SQLITE_INDEX_CONSTRAINT_EQ,
267     SQLITE_INDEX_CONSTRAINT_GT,
268     SQLITE_INDEX_CONSTRAINT_LE,
269     SQLITE_INDEX_CONSTRAINT_LT,
270     SQLITE_INDEX_CONSTRAINT_GE,
271     SQLITE_INDEX_CONSTRAINT_MATCH,
272     SQLITE_INDEX_CONSTRAINT_LIKE,         // 3.10.0
273     SQLITE_INDEX_CONSTRAINT_GLOB,         // 3.10.0
274     SQLITE_INDEX_CONSTRAINT_REGEXP,       // 3.10.0
275     SQLITE_INDEX_CONSTRAINT_NE,           // 3.21.0
276     SQLITE_INDEX_CONSTRAINT_ISNOT,        // 3.21.0
277     SQLITE_INDEX_CONSTRAINT_ISNOTNULL,    // 3.21.0
278     SQLITE_INDEX_CONSTRAINT_ISNULL,       // 3.21.0
279     SQLITE_INDEX_CONSTRAINT_IS,           // 3.21.0
280     SQLITE_INDEX_CONSTRAINT_FUNCTION(u8), // 3.25.0
281 }
282 
283 impl From<u8> for IndexConstraintOp {
from(code: u8) -> IndexConstraintOp284     fn from(code: u8) -> IndexConstraintOp {
285         match code {
286             2 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ,
287             4 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GT,
288             8 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LE,
289             16 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LT,
290             32 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GE,
291             64 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_MATCH,
292             65 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIKE,
293             66 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GLOB,
294             67 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_REGEXP,
295             68 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_NE,
296             69 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOT,
297             70 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
298             71 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNULL,
299             72 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_IS,
300             v => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
301         }
302     }
303 }
304 
305 /// `feature = "vtab"` Pass information into and receive the reply from the
306 /// `VTab.best_index` method.
307 ///
308 /// (See [SQLite doc](http://sqlite.org/c3ref/index_info.html))
309 pub struct IndexInfo(*mut ffi::sqlite3_index_info);
310 
311 impl IndexInfo {
312     /// Record WHERE clause constraints.
constraints(&self) -> IndexConstraintIter<'_>313     pub fn constraints(&self) -> IndexConstraintIter<'_> {
314         let constraints =
315             unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
316         IndexConstraintIter {
317             iter: constraints.iter(),
318         }
319     }
320 
321     /// Information about the ORDER BY clause.
order_bys(&self) -> OrderByIter<'_>322     pub fn order_bys(&self) -> OrderByIter<'_> {
323         let order_bys =
324             unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
325         OrderByIter {
326             iter: order_bys.iter(),
327         }
328     }
329 
330     /// Number of terms in the ORDER BY clause
num_of_order_by(&self) -> usize331     pub fn num_of_order_by(&self) -> usize {
332         unsafe { (*self.0).nOrderBy as usize }
333     }
334 
335     /// Information about what parameters to pass to `VTabCursor.filter`.
constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_>336     pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
337         let constraint_usages = unsafe {
338             slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
339         };
340         IndexConstraintUsage(&mut constraint_usages[constraint_idx])
341     }
342 
343     /// Number used to identify the index
set_idx_num(&mut self, idx_num: c_int)344     pub fn set_idx_num(&mut self, idx_num: c_int) {
345         unsafe {
346             (*self.0).idxNum = idx_num;
347         }
348     }
349 
350     /// True if output is already ordered
set_order_by_consumed(&mut self, order_by_consumed: bool)351     pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
352         unsafe {
353             (*self.0).orderByConsumed = if order_by_consumed { 1 } else { 0 };
354         }
355     }
356 
357     /// Estimated cost of using this index
set_estimated_cost(&mut self, estimated_ost: f64)358     pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
359         unsafe {
360             (*self.0).estimatedCost = estimated_ost;
361         }
362     }
363 
364     /// Estimated number of rows returned.
365     #[cfg(feature = "modern_sqlite")] // SQLite >= 3.8.2
set_estimated_rows(&mut self, estimated_rows: i64)366     pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
367         unsafe {
368             (*self.0).estimatedRows = estimated_rows;
369         }
370     }
371 
372     // TODO idxFlags
373     // TODO colUsed
374 
375     // TODO sqlite3_vtab_collation (http://sqlite.org/c3ref/vtab_collation.html)
376 }
377 
378 /// `feature = "vtab"`
379 pub struct IndexConstraintIter<'a> {
380     iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
381 }
382 
383 impl<'a> Iterator for IndexConstraintIter<'a> {
384     type Item = IndexConstraint<'a>;
385 
next(&mut self) -> Option<IndexConstraint<'a>>386     fn next(&mut self) -> Option<IndexConstraint<'a>> {
387         self.iter.next().map(|raw| IndexConstraint(raw))
388     }
389 
size_hint(&self) -> (usize, Option<usize>)390     fn size_hint(&self) -> (usize, Option<usize>) {
391         self.iter.size_hint()
392     }
393 }
394 
395 /// `feature = "vtab"` WHERE clause constraint.
396 pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
397 
398 impl IndexConstraint<'_> {
399     /// Column constrained.  -1 for ROWID
column(&self) -> c_int400     pub fn column(&self) -> c_int {
401         self.0.iColumn
402     }
403 
404     /// Constraint operator
operator(&self) -> IndexConstraintOp405     pub fn operator(&self) -> IndexConstraintOp {
406         IndexConstraintOp::from(self.0.op)
407     }
408 
409     /// True if this constraint is usable
is_usable(&self) -> bool410     pub fn is_usable(&self) -> bool {
411         self.0.usable != 0
412     }
413 }
414 
415 /// `feature = "vtab"` Information about what parameters to pass to
416 /// `VTabCursor.filter`.
417 pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
418 
419 impl IndexConstraintUsage<'_> {
420     /// if `argv_index` > 0, constraint is part of argv to `VTabCursor.filter`
set_argv_index(&mut self, argv_index: c_int)421     pub fn set_argv_index(&mut self, argv_index: c_int) {
422         self.0.argvIndex = argv_index;
423     }
424 
425     /// if `omit`, do not code a test for this constraint
set_omit(&mut self, omit: bool)426     pub fn set_omit(&mut self, omit: bool) {
427         self.0.omit = if omit { 1 } else { 0 };
428     }
429 }
430 
431 /// `feature = "vtab"`
432 pub struct OrderByIter<'a> {
433     iter: slice::Iter<'a, ffi::sqlite3_index_info_sqlite3_index_orderby>,
434 }
435 
436 impl<'a> Iterator for OrderByIter<'a> {
437     type Item = OrderBy<'a>;
438 
next(&mut self) -> Option<OrderBy<'a>>439     fn next(&mut self) -> Option<OrderBy<'a>> {
440         self.iter.next().map(|raw| OrderBy(raw))
441     }
442 
size_hint(&self) -> (usize, Option<usize>)443     fn size_hint(&self) -> (usize, Option<usize>) {
444         self.iter.size_hint()
445     }
446 }
447 
448 /// `feature = "vtab"` A column of the ORDER BY clause.
449 pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
450 
451 impl OrderBy<'_> {
452     /// Column number
column(&self) -> c_int453     pub fn column(&self) -> c_int {
454         self.0.iColumn
455     }
456 
457     /// True for DESC.  False for ASC.
is_order_by_desc(&self) -> bool458     pub fn is_order_by_desc(&self) -> bool {
459         self.0.desc != 0
460     }
461 }
462 
463 /// `feature = "vtab"` Virtual table cursor trait.
464 ///
465 /// Implementations must be like:
466 /// ```rust,ignore
467 /// #[repr(C)]
468 /// struct MyTabCursor {
469 ///    /// Base class. Must be first
470 ///    base: ffi::sqlite3_vtab_cursor,
471 ///    /* Virtual table implementations will typically add additional fields */
472 /// }
473 /// ```
474 ///
475 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab_cursor.html))
476 pub unsafe trait VTabCursor: Sized {
477     /// Begin a search of a virtual table.
478     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xfilter_method))
filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>479     fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>;
480     /// Advance cursor to the next row of a result set initiated by `filter`.
481     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xnext_method))
next(&mut self) -> Result<()>482     fn next(&mut self) -> Result<()>;
483     /// Must return `false` if the cursor currently points to a valid row of
484     /// data, or `true` otherwise.
485     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xeof_method))
eof(&self) -> bool486     fn eof(&self) -> bool;
487     /// Find the value for the `i`-th column of the current row.
488     /// `i` is zero-based so the first column is numbered 0.
489     /// May return its result back to SQLite using one of the specified `ctx`.
490     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcolumn_method))
column(&self, ctx: &mut Context, i: c_int) -> Result<()>491     fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
492     /// Return the rowid of row that the cursor is currently pointing at.
493     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xrowid_method))
rowid(&self) -> Result<i64>494     fn rowid(&self) -> Result<i64>;
495 }
496 
497 /// `feature = "vtab"` Context is used by `VTabCursor.column` to specify the
498 /// cell value.
499 pub struct Context(*mut ffi::sqlite3_context);
500 
501 impl Context {
502     /// Set current cell value
set_result<T: ToSql>(&mut self, value: &T) -> Result<()>503     pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
504         let t = value.to_sql()?;
505         unsafe { set_result(self.0, &t) };
506         Ok(())
507     }
508 
509     // TODO sqlite3_vtab_nochange (http://sqlite.org/c3ref/vtab_nochange.html)
510 }
511 
512 /// `feature = "vtab"` Wrapper to `VTabCursor.filter` arguments, the values
513 /// requested by `VTab.best_index`.
514 pub struct Values<'a> {
515     args: &'a [*mut ffi::sqlite3_value],
516 }
517 
518 impl Values<'_> {
519     /// Returns the number of values.
len(&self) -> usize520     pub fn len(&self) -> usize {
521         self.args.len()
522     }
523 
524     /// Returns `true` if there is no value.
is_empty(&self) -> bool525     pub fn is_empty(&self) -> bool {
526         self.args.is_empty()
527     }
528 
529     /// Returns value at `idx`
get<T: FromSql>(&self, idx: usize) -> Result<T>530     pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
531         let arg = self.args[idx];
532         let value = unsafe { ValueRef::from_value(arg) };
533         FromSql::column_result(value).map_err(|err| match err {
534             FromSqlError::InvalidType => Error::InvalidFilterParameterType(idx, value.data_type()),
535             FromSqlError::Other(err) => {
536                 Error::FromSqlConversionFailure(idx, value.data_type(), err)
537             }
538             FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
539             #[cfg(feature = "i128_blob")]
540             FromSqlError::InvalidI128Size(_) => {
541                 Error::InvalidColumnType(idx, idx.to_string(), value.data_type())
542             }
543             #[cfg(feature = "uuid")]
544             FromSqlError::InvalidUuidSize(_) => {
545                 Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
546             }
547         })
548     }
549 
550     // `sqlite3_value_type` returns `SQLITE_NULL` for pointer.
551     // So it seems not possible to enhance `ValueRef::from_value`.
552     #[cfg(feature = "array")]
get_array(&self, idx: usize) -> Result<Option<array::Array>>553     fn get_array(&self, idx: usize) -> Result<Option<array::Array>> {
554         use crate::types::Value;
555         let arg = self.args[idx];
556         let ptr = unsafe { ffi::sqlite3_value_pointer(arg, array::ARRAY_TYPE) };
557         if ptr.is_null() {
558             Ok(None)
559         } else {
560             Ok(Some(unsafe {
561                 let rc = array::Array::from_raw(ptr as *const Vec<Value>);
562                 let array = rc.clone();
563                 array::Array::into_raw(rc); // don't consume it
564                 array
565             }))
566         }
567     }
568 
569     /// Turns `Values` into an iterator.
iter(&self) -> ValueIter<'_>570     pub fn iter(&self) -> ValueIter<'_> {
571         ValueIter {
572             iter: self.args.iter(),
573         }
574     }
575 }
576 
577 impl<'a> IntoIterator for &'a Values<'a> {
578     type IntoIter = ValueIter<'a>;
579     type Item = ValueRef<'a>;
580 
into_iter(self) -> ValueIter<'a>581     fn into_iter(self) -> ValueIter<'a> {
582         self.iter()
583     }
584 }
585 
586 /// `Values` iterator.
587 pub struct ValueIter<'a> {
588     iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
589 }
590 
591 impl<'a> Iterator for ValueIter<'a> {
592     type Item = ValueRef<'a>;
593 
next(&mut self) -> Option<ValueRef<'a>>594     fn next(&mut self) -> Option<ValueRef<'a>> {
595         self.iter
596             .next()
597             .map(|&raw| unsafe { ValueRef::from_value(raw) })
598     }
599 
size_hint(&self) -> (usize, Option<usize>)600     fn size_hint(&self) -> (usize, Option<usize>) {
601         self.iter.size_hint()
602     }
603 }
604 
605 impl Connection {
606     /// `feature = "vtab"` Register a virtual table implementation.
607     ///
608     /// Step 3 of [Creating New Virtual Table
609     /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
create_module<'vtab, T: VTab<'vtab>>( &self, module_name: &str, module: &'static Module<'vtab, T>, aux: Option<T::Aux>, ) -> Result<()>610     pub fn create_module<'vtab, T: VTab<'vtab>>(
611         &self,
612         module_name: &str,
613         module: &'static Module<'vtab, T>,
614         aux: Option<T::Aux>,
615     ) -> Result<()> {
616         self.db.borrow_mut().create_module(module_name, module, aux)
617     }
618 }
619 
620 impl InnerConnection {
create_module<'vtab, T: VTab<'vtab>>( &mut self, module_name: &str, module: &'static Module<'vtab, T>, aux: Option<T::Aux>, ) -> Result<()>621     fn create_module<'vtab, T: VTab<'vtab>>(
622         &mut self,
623         module_name: &str,
624         module: &'static Module<'vtab, T>,
625         aux: Option<T::Aux>,
626     ) -> Result<()> {
627         let c_name = str_to_cstring(module_name)?;
628         let r = match aux {
629             Some(aux) => {
630                 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
631                 unsafe {
632                     ffi::sqlite3_create_module_v2(
633                         self.db(),
634                         c_name.as_ptr(),
635                         &module.base,
636                         boxed_aux as *mut c_void,
637                         Some(free_boxed_value::<T::Aux>),
638                     )
639                 }
640             }
641             None => unsafe {
642                 ffi::sqlite3_create_module_v2(
643                     self.db(),
644                     c_name.as_ptr(),
645                     &module.base,
646                     ptr::null_mut(),
647                     None,
648                 )
649             },
650         };
651         self.decode_result(r)
652     }
653 }
654 
655 /// `feature = "vtab"` Escape double-quote (`"`) character occurences by
656 /// doubling them (`""`).
escape_double_quote(identifier: &str) -> Cow<'_, str>657 pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
658     if identifier.contains('"') {
659         // escape quote by doubling them
660         Owned(identifier.replace("\"", "\"\""))
661     } else {
662         Borrowed(identifier)
663     }
664 }
665 /// `feature = "vtab"` Dequote string
dequote(s: &str) -> &str666 pub fn dequote(s: &str) -> &str {
667     if s.len() < 2 {
668         return s;
669     }
670     match s.bytes().next() {
671         Some(b) if b == b'"' || b == b'\'' => match s.bytes().rev().next() {
672             Some(e) if e == b => &s[1..s.len() - 1],
673             _ => s,
674         },
675         _ => s,
676     }
677 }
678 /// `feature = "vtab"` The boolean can be one of:
679 /// ```text
680 /// 1 yes true on
681 /// 0 no false off
682 /// ```
parse_boolean(s: &str) -> Option<bool>683 pub fn parse_boolean(s: &str) -> Option<bool> {
684     if s.eq_ignore_ascii_case("yes")
685         || s.eq_ignore_ascii_case("on")
686         || s.eq_ignore_ascii_case("true")
687         || s.eq("1")
688     {
689         Some(true)
690     } else if s.eq_ignore_ascii_case("no")
691         || s.eq_ignore_ascii_case("off")
692         || s.eq_ignore_ascii_case("false")
693         || s.eq("0")
694     {
695         Some(false)
696     } else {
697         None
698     }
699 }
700 
701 // FIXME copy/paste from function.rs
free_boxed_value<T>(p: *mut c_void)702 unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
703     let _: Box<T> = Box::from_raw(p as *mut T);
704 }
705 
rust_create<'vtab, 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: CreateVTab<'vtab>,706 unsafe extern "C" fn rust_create<'vtab, T>(
707     db: *mut ffi::sqlite3,
708     aux: *mut c_void,
709     argc: c_int,
710     argv: *const *const c_char,
711     pp_vtab: *mut *mut ffi::sqlite3_vtab,
712     err_msg: *mut *mut c_char,
713 ) -> c_int
714 where
715     T: CreateVTab<'vtab>,
716 {
717     use std::ffi::CStr;
718 
719     let mut conn = VTabConnection(db);
720     let aux = aux as *mut T::Aux;
721     let args = slice::from_raw_parts(argv, argc as usize);
722     let vec = args
723         .iter()
724         .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
725         .collect::<Vec<_>>();
726     match T::create(&mut conn, aux.as_ref(), &vec[..]) {
727         Ok((sql, vtab)) => match ::std::ffi::CString::new(sql) {
728             Ok(c_sql) => {
729                 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
730                 if rc == ffi::SQLITE_OK {
731                     let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
732                     *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
733                     ffi::SQLITE_OK
734                 } else {
735                     let err = error_from_sqlite_code(rc, None);
736                     *err_msg = alloc(&err.to_string());
737                     rc
738                 }
739             }
740             Err(err) => {
741                 *err_msg = alloc(&err.to_string());
742                 ffi::SQLITE_ERROR
743             }
744         },
745         Err(Error::SqliteFailure(err, s)) => {
746             if let Some(s) = s {
747                 *err_msg = alloc(&s);
748             }
749             err.extended_code
750         }
751         Err(err) => {
752             *err_msg = alloc(&err.to_string());
753             ffi::SQLITE_ERROR
754         }
755     }
756 }
757 
rust_connect<'vtab, 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<'vtab>,758 unsafe extern "C" fn rust_connect<'vtab, T>(
759     db: *mut ffi::sqlite3,
760     aux: *mut c_void,
761     argc: c_int,
762     argv: *const *const c_char,
763     pp_vtab: *mut *mut ffi::sqlite3_vtab,
764     err_msg: *mut *mut c_char,
765 ) -> c_int
766 where
767     T: VTab<'vtab>,
768 {
769     use std::ffi::CStr;
770 
771     let mut conn = VTabConnection(db);
772     let aux = aux as *mut T::Aux;
773     let args = slice::from_raw_parts(argv, argc as usize);
774     let vec = args
775         .iter()
776         .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
777         .collect::<Vec<_>>();
778     match T::connect(&mut conn, aux.as_ref(), &vec[..]) {
779         Ok((sql, vtab)) => match ::std::ffi::CString::new(sql) {
780             Ok(c_sql) => {
781                 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
782                 if rc == ffi::SQLITE_OK {
783                     let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
784                     *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
785                     ffi::SQLITE_OK
786                 } else {
787                     let err = error_from_sqlite_code(rc, None);
788                     *err_msg = alloc(&err.to_string());
789                     rc
790                 }
791             }
792             Err(err) => {
793                 *err_msg = alloc(&err.to_string());
794                 ffi::SQLITE_ERROR
795             }
796         },
797         Err(Error::SqliteFailure(err, s)) => {
798             if let Some(s) = s {
799                 *err_msg = alloc(&s);
800             }
801             err.extended_code
802         }
803         Err(err) => {
804             *err_msg = alloc(&err.to_string());
805             ffi::SQLITE_ERROR
806         }
807     }
808 }
809 
rust_best_index<'vtab, T>( vtab: *mut ffi::sqlite3_vtab, info: *mut ffi::sqlite3_index_info, ) -> c_int where T: VTab<'vtab>,810 unsafe extern "C" fn rust_best_index<'vtab, T>(
811     vtab: *mut ffi::sqlite3_vtab,
812     info: *mut ffi::sqlite3_index_info,
813 ) -> c_int
814 where
815     T: VTab<'vtab>,
816 {
817     let vt = vtab as *mut T;
818     let mut idx_info = IndexInfo(info);
819     match (*vt).best_index(&mut idx_info) {
820         Ok(_) => ffi::SQLITE_OK,
821         Err(Error::SqliteFailure(err, s)) => {
822             if let Some(err_msg) = s {
823                 set_err_msg(vtab, &err_msg);
824             }
825             err.extended_code
826         }
827         Err(err) => {
828             set_err_msg(vtab, &err.to_string());
829             ffi::SQLITE_ERROR
830         }
831     }
832 }
833 
rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where T: VTab<'vtab>,834 unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
835 where
836     T: VTab<'vtab>,
837 {
838     if vtab.is_null() {
839         return ffi::SQLITE_OK;
840     }
841     let vtab = vtab as *mut T;
842     let _: Box<T> = Box::from_raw(vtab);
843     ffi::SQLITE_OK
844 }
845 
rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where T: CreateVTab<'vtab>,846 unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
847 where
848     T: CreateVTab<'vtab>,
849 {
850     if vtab.is_null() {
851         return ffi::SQLITE_OK;
852     }
853     let vt = vtab as *mut T;
854     match (*vt).destroy() {
855         Ok(_) => {
856             let _: Box<T> = Box::from_raw(vt);
857             ffi::SQLITE_OK
858         }
859         Err(Error::SqliteFailure(err, s)) => {
860             if let Some(err_msg) = s {
861                 set_err_msg(vtab, &err_msg);
862             }
863             err.extended_code
864         }
865         Err(err) => {
866             set_err_msg(vtab, &err.to_string());
867             ffi::SQLITE_ERROR
868         }
869     }
870 }
871 
rust_open<'vtab, T: 'vtab>( vtab: *mut ffi::sqlite3_vtab, pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor, ) -> c_int where T: VTab<'vtab>,872 unsafe extern "C" fn rust_open<'vtab, T: 'vtab>(
873     vtab: *mut ffi::sqlite3_vtab,
874     pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor,
875 ) -> c_int
876 where
877     T: VTab<'vtab>,
878 {
879     let vt = vtab as *mut T;
880     match (*vt).open() {
881         Ok(cursor) => {
882             let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
883             *pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor;
884             ffi::SQLITE_OK
885         }
886         Err(Error::SqliteFailure(err, s)) => {
887             if let Some(err_msg) = s {
888                 set_err_msg(vtab, &err_msg);
889             }
890             err.extended_code
891         }
892         Err(err) => {
893             set_err_msg(vtab, &err.to_string());
894             ffi::SQLITE_ERROR
895         }
896     }
897 }
898 
rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,899 unsafe extern "C" fn rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
900 where
901     C: VTabCursor,
902 {
903     let cr = cursor as *mut C;
904     let _: Box<C> = Box::from_raw(cr);
905     ffi::SQLITE_OK
906 }
907 
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 where C: VTabCursor,908 unsafe extern "C" fn rust_filter<C>(
909     cursor: *mut ffi::sqlite3_vtab_cursor,
910     idx_num: c_int,
911     idx_str: *const c_char,
912     argc: c_int,
913     argv: *mut *mut ffi::sqlite3_value,
914 ) -> c_int
915 where
916     C: VTabCursor,
917 {
918     use std::ffi::CStr;
919     use std::str;
920     let idx_name = if idx_str.is_null() {
921         None
922     } else {
923         let c_slice = CStr::from_ptr(idx_str).to_bytes();
924         Some(str::from_utf8_unchecked(c_slice))
925     };
926     let args = slice::from_raw_parts_mut(argv, argc as usize);
927     let values = Values { args };
928     let cr = cursor as *mut C;
929     cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values))
930 }
931 
rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,932 unsafe extern "C" fn rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
933 where
934     C: VTabCursor,
935 {
936     let cr = cursor as *mut C;
937     cursor_error(cursor, (*cr).next())
938 }
939 
rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,940 unsafe extern "C" fn rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
941 where
942     C: VTabCursor,
943 {
944     let cr = cursor as *mut C;
945     (*cr).eof() as c_int
946 }
947 
rust_column<C>( cursor: *mut ffi::sqlite3_vtab_cursor, ctx: *mut ffi::sqlite3_context, i: c_int, ) -> c_int where C: VTabCursor,948 unsafe extern "C" fn rust_column<C>(
949     cursor: *mut ffi::sqlite3_vtab_cursor,
950     ctx: *mut ffi::sqlite3_context,
951     i: c_int,
952 ) -> c_int
953 where
954     C: VTabCursor,
955 {
956     let cr = cursor as *mut C;
957     let mut ctxt = Context(ctx);
958     result_error(ctx, (*cr).column(&mut ctxt, i))
959 }
960 
rust_rowid<C>( cursor: *mut ffi::sqlite3_vtab_cursor, p_rowid: *mut ffi::sqlite3_int64, ) -> c_int where C: VTabCursor,961 unsafe extern "C" fn rust_rowid<C>(
962     cursor: *mut ffi::sqlite3_vtab_cursor,
963     p_rowid: *mut ffi::sqlite3_int64,
964 ) -> c_int
965 where
966     C: VTabCursor,
967 {
968     let cr = cursor as *mut C;
969     match (*cr).rowid() {
970         Ok(rowid) => {
971             *p_rowid = rowid;
972             ffi::SQLITE_OK
973         }
974         err => cursor_error(cursor, err),
975     }
976 }
977 
978 /// Virtual table cursors can set an error message by assigning a string to
979 /// `zErrMsg`.
cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int980 unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int {
981     match result {
982         Ok(_) => ffi::SQLITE_OK,
983         Err(Error::SqliteFailure(err, s)) => {
984             if let Some(err_msg) = s {
985                 set_err_msg((*cursor).pVtab, &err_msg);
986             }
987             err.extended_code
988         }
989         Err(err) => {
990             set_err_msg((*cursor).pVtab, &err.to_string());
991             ffi::SQLITE_ERROR
992         }
993     }
994 }
995 
996 /// Virtual tables methods can set an error message by assigning a string to
997 /// `zErrMsg`.
set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str)998 unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
999     if !(*vtab).zErrMsg.is_null() {
1000         ffi::sqlite3_free((*vtab).zErrMsg as *mut c_void);
1001     }
1002     (*vtab).zErrMsg = alloc(err_msg);
1003 }
1004 
1005 /// To raise an error, the `column` method should use this method to set the
1006 /// error message and return the error code.
result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int1007 unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
1008     match result {
1009         Ok(_) => ffi::SQLITE_OK,
1010         Err(Error::SqliteFailure(err, s)) => {
1011             match err.extended_code {
1012                 ffi::SQLITE_TOOBIG => {
1013                     ffi::sqlite3_result_error_toobig(ctx);
1014                 }
1015                 ffi::SQLITE_NOMEM => {
1016                     ffi::sqlite3_result_error_nomem(ctx);
1017                 }
1018                 code => {
1019                     ffi::sqlite3_result_error_code(ctx, code);
1020                     if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
1021                         ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1022                     }
1023                 }
1024             };
1025             err.extended_code
1026         }
1027         Err(err) => {
1028             ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_ERROR);
1029             if let Ok(cstr) = str_to_cstring(&err.to_string()) {
1030                 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1031             }
1032             ffi::SQLITE_ERROR
1033         }
1034     }
1035 }
1036 
1037 // Space to hold this string must be obtained
1038 // from an SQLite memory allocation function
alloc(s: &str) -> *mut c_char1039 fn alloc(s: &str) -> *mut c_char {
1040     crate::util::SqliteMallocString::from_str(s).into_raw()
1041 }
1042 
1043 #[cfg(feature = "array")]
1044 pub mod array;
1045 #[cfg(feature = "csvtab")]
1046 pub mod csvtab;
1047 #[cfg(feature = "series")]
1048 pub mod series; // SQLite >= 3.9.0
1049 
1050 #[cfg(test)]
1051 mod test {
1052     #[test]
test_dequote()1053     fn test_dequote() {
1054         assert_eq!("", super::dequote(""));
1055         assert_eq!("'", super::dequote("'"));
1056         assert_eq!("\"", super::dequote("\""));
1057         assert_eq!("'\"", super::dequote("'\""));
1058         assert_eq!("", super::dequote("''"));
1059         assert_eq!("", super::dequote("\"\""));
1060         assert_eq!("x", super::dequote("'x'"));
1061         assert_eq!("x", super::dequote("\"x\""));
1062         assert_eq!("x", super::dequote("x"));
1063     }
1064     #[test]
test_parse_boolean()1065     fn test_parse_boolean() {
1066         assert_eq!(None, super::parse_boolean(""));
1067         assert_eq!(Some(true), super::parse_boolean("1"));
1068         assert_eq!(Some(true), super::parse_boolean("yes"));
1069         assert_eq!(Some(true), super::parse_boolean("on"));
1070         assert_eq!(Some(true), super::parse_boolean("true"));
1071         assert_eq!(Some(false), super::parse_boolean("0"));
1072         assert_eq!(Some(false), super::parse_boolean("no"));
1073         assert_eq!(Some(false), super::parse_boolean("off"));
1074         assert_eq!(Some(false), super::parse_boolean("false"));
1075     }
1076 }
1077