• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Create virtual tables.
2 //!
3 //! Follow these steps to create your own virtual table:
4 //! 1. Write implementation of [`VTab`] and [`VTabCursor`] traits.
5 //! 2. Create an instance of the [`Module`] structure specialized for [`VTab`]
6 //!    impl. 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::os::raw::{c_char, c_int, c_void};
15 use std::ptr;
16 use std::slice;
17 
18 use crate::context::set_result;
19 use crate::error::{error_from_sqlite_code, to_sqlite_error};
20 use crate::ffi;
21 pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor};
22 use crate::types::{FromSql, FromSqlError, ToSql, ValueRef};
23 use crate::util::alloc;
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 /// Virtual table kind
61 pub enum VTabKind {
62     /// Non-eponymous
63     Default,
64     /// [`create`](CreateVTab::create) == [`connect`](VTab::connect)
65     ///
66     /// See [SQLite doc](https://sqlite.org/vtab.html#eponymous_virtual_tables)
67     Eponymous,
68     /// No [`create`](CreateVTab::create) / [`destroy`](CreateVTab::destroy) or
69     /// not used
70     ///
71     /// SQLite >= 3.9.0
72     ///
73     /// See [SQLite doc](https://sqlite.org/vtab.html#eponymous_only_virtual_tables)
74     EponymousOnly,
75 }
76 
77 /// Virtual table module
78 ///
79 /// (See [SQLite doc](https://sqlite.org/c3ref/module.html))
80 #[repr(transparent)]
81 pub struct Module<'vtab, T: VTab<'vtab>> {
82     base: ffi::sqlite3_module,
83     phantom: PhantomData<&'vtab T>,
84 }
85 
86 unsafe impl<'vtab, T: VTab<'vtab>> Send for Module<'vtab, T> {}
87 unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {}
88 
89 union ModuleZeroHack {
90     bytes: [u8; std::mem::size_of::<ffi::sqlite3_module>()],
91     module: ffi::sqlite3_module,
92 }
93 
94 // Used as a trailing initializer for sqlite3_module -- this way we avoid having
95 // the build fail if buildtime_bindgen is on. This is safe, as bindgen-generated
96 // structs are allowed to be zeroed.
97 const ZERO_MODULE: ffi::sqlite3_module = unsafe {
98     ModuleZeroHack {
99         bytes: [0_u8; std::mem::size_of::<ffi::sqlite3_module>()],
100     }
101     .module
102 };
103 
104 macro_rules! module {
105     ($lt:lifetime, $vt:ty, $ct:ty, $xc:expr, $xd:expr, $xu:expr) => {
106     #[allow(clippy::needless_update)]
107     &Module {
108         base: ffi::sqlite3_module {
109             // We don't use V3
110             iVersion: 2,
111             xCreate: $xc,
112             xConnect: Some(rust_connect::<$vt>),
113             xBestIndex: Some(rust_best_index::<$vt>),
114             xDisconnect: Some(rust_disconnect::<$vt>),
115             xDestroy: $xd,
116             xOpen: Some(rust_open::<$vt>),
117             xClose: Some(rust_close::<$ct>),
118             xFilter: Some(rust_filter::<$ct>),
119             xNext: Some(rust_next::<$ct>),
120             xEof: Some(rust_eof::<$ct>),
121             xColumn: Some(rust_column::<$ct>),
122             xRowid: Some(rust_rowid::<$ct>), // FIXME optional
123             xUpdate: $xu,
124             xBegin: None,
125             xSync: None,
126             xCommit: None,
127             xRollback: None,
128             xFindFunction: None,
129             xRename: None,
130             xSavepoint: None,
131             xRelease: None,
132             xRollbackTo: None,
133             ..ZERO_MODULE
134         },
135         phantom: PhantomData::<&$lt $vt>,
136     }
137     };
138 }
139 
140 /// Create a modifiable virtual table implementation.
141 ///
142 /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
143 #[must_use]
update_module<'vtab, T: UpdateVTab<'vtab>>() -> &'static Module<'vtab, T>144 pub fn update_module<'vtab, T: UpdateVTab<'vtab>>() -> &'static Module<'vtab, T> {
145     match T::KIND {
146         VTabKind::EponymousOnly => {
147             module!('vtab, T, T::Cursor, None, None, Some(rust_update::<T>))
148         }
149         VTabKind::Eponymous => {
150             module!('vtab, T, T::Cursor, Some(rust_connect::<T>), Some(rust_disconnect::<T>), Some(rust_update::<T>))
151         }
152         _ => {
153             module!('vtab, T, T::Cursor, Some(rust_create::<T>), Some(rust_destroy::<T>), Some(rust_update::<T>))
154         }
155     }
156 }
157 
158 /// Create a read-only virtual table implementation.
159 ///
160 /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
161 #[must_use]
read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T>162 pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> {
163     match T::KIND {
164         VTabKind::EponymousOnly => eponymous_only_module(),
165         VTabKind::Eponymous => {
166             // A virtual table is eponymous if its xCreate method is the exact same function
167             // as the xConnect method
168             module!('vtab, T, T::Cursor, Some(rust_connect::<T>), Some(rust_disconnect::<T>), None)
169         }
170         _ => {
171             // The xConnect and xCreate methods may do the same thing, but they must be
172             // different so that the virtual table is not an eponymous virtual table.
173             module!('vtab, T, T::Cursor, Some(rust_create::<T>), Some(rust_destroy::<T>), None)
174         }
175     }
176 }
177 
178 /// Create an eponymous only virtual table implementation.
179 ///
180 /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
181 #[must_use]
eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T>182 pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> {
183     //  For eponymous-only virtual tables, the xCreate method is NULL
184     module!('vtab, T, T::Cursor, None, None, None)
185 }
186 
187 /// Virtual table configuration options
188 #[repr(i32)]
189 #[non_exhaustive]
190 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
191 pub enum VTabConfig {
192     /// Equivalent to SQLITE_VTAB_CONSTRAINT_SUPPORT
193     ConstraintSupport = 1,
194     /// Equivalent to SQLITE_VTAB_INNOCUOUS
195     Innocuous = 2,
196     /// Equivalent to SQLITE_VTAB_DIRECTONLY
197     DirectOnly = 3,
198     /// Equivalent to SQLITE_VTAB_USES_ALL_SCHEMAS
199     UsesAllSchemas = 4,
200 }
201 
202 /// `feature = "vtab"`
203 pub struct VTabConnection(*mut ffi::sqlite3);
204 
205 impl VTabConnection {
206     /// Configure various facets of the virtual table interface
config(&mut self, config: VTabConfig) -> Result<()>207     pub fn config(&mut self, config: VTabConfig) -> Result<()> {
208         crate::error::check(unsafe { ffi::sqlite3_vtab_config(self.0, config as c_int) })
209     }
210 
211     // TODO sqlite3_vtab_on_conflict (http://sqlite.org/c3ref/vtab_on_conflict.html) & xUpdate
212 
213     /// Get access to the underlying SQLite database connection handle.
214     ///
215     /// # Warning
216     ///
217     /// You should not need to use this function. If you do need to, please
218     /// [open an issue on the rusqlite repository](https://github.com/rusqlite/rusqlite/issues) and describe
219     /// your use case.
220     ///
221     /// # Safety
222     ///
223     /// This function is unsafe because it gives you raw access
224     /// to the SQLite connection, and what you do with it could impact the
225     /// safety of this `Connection`.
handle(&mut self) -> *mut ffi::sqlite3226     pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
227         self.0
228     }
229 }
230 
231 /// Eponymous-only virtual table instance trait.
232 ///
233 /// # Safety
234 ///
235 /// The first item in a struct implementing `VTab` must be
236 /// `rusqlite::sqlite3_vtab`, and the struct must be `#[repr(C)]`.
237 ///
238 /// ```rust,ignore
239 /// #[repr(C)]
240 /// struct MyTab {
241 ///    /// Base class. Must be first
242 ///    base: rusqlite::vtab::sqlite3_vtab,
243 ///    /* Virtual table implementations will typically add additional fields */
244 /// }
245 /// ```
246 ///
247 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
248 pub unsafe trait VTab<'vtab>: Sized {
249     /// Client data passed to [`Connection::create_module`].
250     type Aux;
251     /// Specific cursor implementation
252     type Cursor: VTabCursor;
253 
254     /// Establish a new connection to an existing virtual table.
255     ///
256     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xconnect_method))
connect( db: &mut VTabConnection, aux: Option<&Self::Aux>, args: &[&[u8]], ) -> Result<(String, Self)>257     fn connect(
258         db: &mut VTabConnection,
259         aux: Option<&Self::Aux>,
260         args: &[&[u8]],
261     ) -> Result<(String, Self)>;
262 
263     /// Determine the best way to access the virtual table.
264     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xbestindex_method))
best_index(&self, info: &mut IndexInfo) -> Result<()>265     fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
266 
267     /// Create a new cursor used for accessing a virtual table.
268     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xopen_method))
open(&'vtab mut self) -> Result<Self::Cursor>269     fn open(&'vtab mut self) -> Result<Self::Cursor>;
270 }
271 
272 /// Read-only virtual table instance trait.
273 ///
274 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
275 pub trait CreateVTab<'vtab>: VTab<'vtab> {
276     /// For [`EponymousOnly`](VTabKind::EponymousOnly),
277     /// [`create`](CreateVTab::create) and [`destroy`](CreateVTab::destroy) are
278     /// not called
279     const KIND: VTabKind;
280     /// Create a new instance of a virtual table in response to a CREATE VIRTUAL
281     /// TABLE statement. The `db` parameter is a pointer to the SQLite
282     /// database connection that is executing the CREATE VIRTUAL TABLE
283     /// statement.
284     ///
285     /// Call [`connect`](VTab::connect) by default.
286     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcreate_method))
create( db: &mut VTabConnection, aux: Option<&Self::Aux>, args: &[&[u8]], ) -> Result<(String, Self)>287     fn create(
288         db: &mut VTabConnection,
289         aux: Option<&Self::Aux>,
290         args: &[&[u8]],
291     ) -> Result<(String, Self)> {
292         Self::connect(db, aux, args)
293     }
294 
295     /// Destroy the underlying table implementation. This method undoes the work
296     /// of [`create`](CreateVTab::create).
297     ///
298     /// Do nothing by default.
299     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xdestroy_method))
destroy(&self) -> Result<()>300     fn destroy(&self) -> Result<()> {
301         Ok(())
302     }
303 }
304 
305 /// Writable virtual table instance trait.
306 ///
307 /// (See [SQLite doc](https://sqlite.org/vtab.html#xupdate))
308 pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
309     /// Delete rowid or PK
delete(&mut self, arg: ValueRef<'_>) -> Result<()>310     fn delete(&mut self, arg: ValueRef<'_>) -> Result<()>;
311     /// Insert: `args[0] == NULL: old rowid or PK, args[1]: new rowid or PK,
312     /// args[2]: ...`
313     ///
314     /// Return the new rowid.
315     // TODO Make the distinction between argv[1] == NULL and argv[1] != NULL ?
insert(&mut self, args: &Values<'_>) -> Result<i64>316     fn insert(&mut self, args: &Values<'_>) -> Result<i64>;
317     /// Update: `args[0] != NULL: old rowid or PK, args[1]: new row id or PK,
318     /// args[2]: ...`
update(&mut self, args: &Values<'_>) -> Result<()>319     fn update(&mut self, args: &Values<'_>) -> Result<()>;
320 }
321 
322 /// Index constraint operator.
323 /// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
324 #[derive(Debug, Eq, PartialEq)]
325 #[allow(non_snake_case, non_camel_case_types, missing_docs)]
326 #[allow(clippy::upper_case_acronyms)]
327 pub enum IndexConstraintOp {
328     SQLITE_INDEX_CONSTRAINT_EQ,
329     SQLITE_INDEX_CONSTRAINT_GT,
330     SQLITE_INDEX_CONSTRAINT_LE,
331     SQLITE_INDEX_CONSTRAINT_LT,
332     SQLITE_INDEX_CONSTRAINT_GE,
333     SQLITE_INDEX_CONSTRAINT_MATCH,
334     SQLITE_INDEX_CONSTRAINT_LIKE,         // 3.10.0
335     SQLITE_INDEX_CONSTRAINT_GLOB,         // 3.10.0
336     SQLITE_INDEX_CONSTRAINT_REGEXP,       // 3.10.0
337     SQLITE_INDEX_CONSTRAINT_NE,           // 3.21.0
338     SQLITE_INDEX_CONSTRAINT_ISNOT,        // 3.21.0
339     SQLITE_INDEX_CONSTRAINT_ISNOTNULL,    // 3.21.0
340     SQLITE_INDEX_CONSTRAINT_ISNULL,       // 3.21.0
341     SQLITE_INDEX_CONSTRAINT_IS,           // 3.21.0
342     SQLITE_INDEX_CONSTRAINT_LIMIT,        // 3.38.0
343     SQLITE_INDEX_CONSTRAINT_OFFSET,       // 3.38.0
344     SQLITE_INDEX_CONSTRAINT_FUNCTION(u8), // 3.25.0
345 }
346 
347 impl From<u8> for IndexConstraintOp {
from(code: u8) -> IndexConstraintOp348     fn from(code: u8) -> IndexConstraintOp {
349         match code {
350             2 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ,
351             4 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GT,
352             8 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LE,
353             16 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LT,
354             32 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GE,
355             64 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_MATCH,
356             65 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIKE,
357             66 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GLOB,
358             67 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_REGEXP,
359             68 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_NE,
360             69 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOT,
361             70 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
362             71 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNULL,
363             72 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_IS,
364             73 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIMIT,
365             74 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_OFFSET,
366             v => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
367         }
368     }
369 }
370 
371 bitflags::bitflags! {
372     /// Virtual table scan flags
373     /// See [Function Flags](https://sqlite.org/c3ref/c_index_scan_unique.html) for details.
374     #[repr(C)]
375     #[derive(Copy, Clone, Debug)]
376     pub struct IndexFlags: ::std::os::raw::c_int {
377         /// Default
378         const NONE     = 0;
379         /// Scan visits at most 1 row.
380         const SQLITE_INDEX_SCAN_UNIQUE  = ffi::SQLITE_INDEX_SCAN_UNIQUE;
381     }
382 }
383 
384 /// Pass information into and receive the reply from the
385 /// [`VTab::best_index`] method.
386 ///
387 /// (See [SQLite doc](http://sqlite.org/c3ref/index_info.html))
388 #[derive(Debug)]
389 pub struct IndexInfo(*mut ffi::sqlite3_index_info);
390 
391 impl IndexInfo {
392     /// Iterate on index constraint and its associated usage.
393     #[inline]
constraints_and_usages(&mut self) -> IndexConstraintAndUsageIter<'_>394     pub fn constraints_and_usages(&mut self) -> IndexConstraintAndUsageIter<'_> {
395         let constraints =
396             unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
397         let constraint_usages = unsafe {
398             slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
399         };
400         IndexConstraintAndUsageIter {
401             iter: constraints.iter().zip(constraint_usages.iter_mut()),
402         }
403     }
404 
405     /// Record WHERE clause constraints.
406     #[inline]
407     #[must_use]
constraints(&self) -> IndexConstraintIter<'_>408     pub fn constraints(&self) -> IndexConstraintIter<'_> {
409         let constraints =
410             unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
411         IndexConstraintIter {
412             iter: constraints.iter(),
413         }
414     }
415 
416     /// Information about the ORDER BY clause.
417     #[inline]
418     #[must_use]
order_bys(&self) -> OrderByIter<'_>419     pub fn order_bys(&self) -> OrderByIter<'_> {
420         let order_bys =
421             unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
422         OrderByIter {
423             iter: order_bys.iter(),
424         }
425     }
426 
427     /// Number of terms in the ORDER BY clause
428     #[inline]
429     #[must_use]
num_of_order_by(&self) -> usize430     pub fn num_of_order_by(&self) -> usize {
431         unsafe { (*self.0).nOrderBy as usize }
432     }
433 
434     /// Information about what parameters to pass to [`VTabCursor::filter`].
435     #[inline]
constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_>436     pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
437         let constraint_usages = unsafe {
438             slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
439         };
440         IndexConstraintUsage(&mut constraint_usages[constraint_idx])
441     }
442 
443     /// Number used to identify the index
444     #[inline]
set_idx_num(&mut self, idx_num: c_int)445     pub fn set_idx_num(&mut self, idx_num: c_int) {
446         unsafe {
447             (*self.0).idxNum = idx_num;
448         }
449     }
450 
451     /// String used to identify the index
set_idx_str(&mut self, idx_str: &str)452     pub fn set_idx_str(&mut self, idx_str: &str) {
453         unsafe {
454             (*self.0).idxStr = alloc(idx_str);
455             (*self.0).needToFreeIdxStr = 1;
456         }
457     }
458 
459     /// True if output is already ordered
460     #[inline]
set_order_by_consumed(&mut self, order_by_consumed: bool)461     pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
462         unsafe {
463             (*self.0).orderByConsumed = order_by_consumed as c_int;
464         }
465     }
466 
467     /// Estimated cost of using this index
468     #[inline]
set_estimated_cost(&mut self, estimated_ost: f64)469     pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
470         unsafe {
471             (*self.0).estimatedCost = estimated_ost;
472         }
473     }
474 
475     /// Estimated number of rows returned.
476     #[inline]
set_estimated_rows(&mut self, estimated_rows: i64)477     pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
478         unsafe {
479             (*self.0).estimatedRows = estimated_rows;
480         }
481     }
482 
483     /// Mask of SQLITE_INDEX_SCAN_* flags.
484     #[inline]
set_idx_flags(&mut self, flags: IndexFlags)485     pub fn set_idx_flags(&mut self, flags: IndexFlags) {
486         unsafe { (*self.0).idxFlags = flags.bits() };
487     }
488 
489     /// Mask of columns used by statement
490     #[inline]
col_used(&self) -> u64491     pub fn col_used(&self) -> u64 {
492         unsafe { (*self.0).colUsed }
493     }
494 
495     /// Determine the collation for a virtual table constraint
496     #[cfg(feature = "modern_sqlite")] // SQLite >= 3.22.0
497     #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
collation(&self, constraint_idx: usize) -> Result<&str>498     pub fn collation(&self, constraint_idx: usize) -> Result<&str> {
499         use std::ffi::CStr;
500         let idx = constraint_idx as c_int;
501         let collation = unsafe { ffi::sqlite3_vtab_collation(self.0, idx) };
502         if collation.is_null() {
503             return Err(Error::SqliteFailure(
504                 ffi::Error::new(ffi::SQLITE_MISUSE),
505                 Some(format!("{constraint_idx} is out of range")),
506             ));
507         }
508         Ok(unsafe { CStr::from_ptr(collation) }.to_str()?)
509     }
510 
511     /*/// Determine if a virtual table query is DISTINCT
512     #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
513     #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
514     pub fn distinct(&self) -> c_int {
515         unsafe { ffi::sqlite3_vtab_distinct(self.0) }
516     }
517 
518     /// Constraint values
519     #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
520     #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
521     pub fn set_rhs_value(&mut self, constraint_idx: c_int, value: ValueRef) -> Result<()> {
522         // TODO ValueRef to sqlite3_value
523         crate::error::check(unsafe { ffi::sqlite3_vtab_rhs_value(self.O, constraint_idx, value) })
524     }
525 
526     /// Identify and handle IN constraints
527     #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
528     #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
529     pub fn set_in_constraint(&mut self, constraint_idx: c_int, b_handle: c_int) -> bool {
530         unsafe { ffi::sqlite3_vtab_in(self.0, constraint_idx, b_handle) != 0 }
531     } // TODO sqlite3_vtab_in_first / sqlite3_vtab_in_next https://sqlite.org/c3ref/vtab_in_first.html
532     */
533 }
534 
535 /// Iterate on index constraint and its associated usage.
536 pub struct IndexConstraintAndUsageIter<'a> {
537     iter: std::iter::Zip<
538         slice::Iter<'a, ffi::sqlite3_index_constraint>,
539         slice::IterMut<'a, ffi::sqlite3_index_constraint_usage>,
540     >,
541 }
542 
543 impl<'a> Iterator for IndexConstraintAndUsageIter<'a> {
544     type Item = (IndexConstraint<'a>, IndexConstraintUsage<'a>);
545 
546     #[inline]
next(&mut self) -> Option<(IndexConstraint<'a>, IndexConstraintUsage<'a>)>547     fn next(&mut self) -> Option<(IndexConstraint<'a>, IndexConstraintUsage<'a>)> {
548         self.iter
549             .next()
550             .map(|raw| (IndexConstraint(raw.0), IndexConstraintUsage(raw.1)))
551     }
552 
553     #[inline]
size_hint(&self) -> (usize, Option<usize>)554     fn size_hint(&self) -> (usize, Option<usize>) {
555         self.iter.size_hint()
556     }
557 }
558 
559 /// `feature = "vtab"`
560 pub struct IndexConstraintIter<'a> {
561     iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
562 }
563 
564 impl<'a> Iterator for IndexConstraintIter<'a> {
565     type Item = IndexConstraint<'a>;
566 
567     #[inline]
next(&mut self) -> Option<IndexConstraint<'a>>568     fn next(&mut self) -> Option<IndexConstraint<'a>> {
569         self.iter.next().map(IndexConstraint)
570     }
571 
572     #[inline]
size_hint(&self) -> (usize, Option<usize>)573     fn size_hint(&self) -> (usize, Option<usize>) {
574         self.iter.size_hint()
575     }
576 }
577 
578 /// WHERE clause constraint.
579 pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
580 
581 impl IndexConstraint<'_> {
582     /// Column constrained.  -1 for ROWID
583     #[inline]
584     #[must_use]
column(&self) -> c_int585     pub fn column(&self) -> c_int {
586         self.0.iColumn
587     }
588 
589     /// Constraint operator
590     #[inline]
591     #[must_use]
operator(&self) -> IndexConstraintOp592     pub fn operator(&self) -> IndexConstraintOp {
593         IndexConstraintOp::from(self.0.op)
594     }
595 
596     /// True if this constraint is usable
597     #[inline]
598     #[must_use]
is_usable(&self) -> bool599     pub fn is_usable(&self) -> bool {
600         self.0.usable != 0
601     }
602 }
603 
604 /// Information about what parameters to pass to
605 /// [`VTabCursor::filter`].
606 pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
607 
608 impl IndexConstraintUsage<'_> {
609     /// if `argv_index` > 0, constraint is part of argv to
610     /// [`VTabCursor::filter`]
611     #[inline]
set_argv_index(&mut self, argv_index: c_int)612     pub fn set_argv_index(&mut self, argv_index: c_int) {
613         self.0.argvIndex = argv_index;
614     }
615 
616     /// if `omit`, do not code a test for this constraint
617     #[inline]
set_omit(&mut self, omit: bool)618     pub fn set_omit(&mut self, omit: bool) {
619         self.0.omit = omit as std::os::raw::c_uchar;
620     }
621 }
622 
623 /// `feature = "vtab"`
624 pub struct OrderByIter<'a> {
625     iter: slice::Iter<'a, ffi::sqlite3_index_orderby>,
626 }
627 
628 impl<'a> Iterator for OrderByIter<'a> {
629     type Item = OrderBy<'a>;
630 
631     #[inline]
next(&mut self) -> Option<OrderBy<'a>>632     fn next(&mut self) -> Option<OrderBy<'a>> {
633         self.iter.next().map(OrderBy)
634     }
635 
636     #[inline]
size_hint(&self) -> (usize, Option<usize>)637     fn size_hint(&self) -> (usize, Option<usize>) {
638         self.iter.size_hint()
639     }
640 }
641 
642 /// A column of the ORDER BY clause.
643 pub struct OrderBy<'a>(&'a ffi::sqlite3_index_orderby);
644 
645 impl OrderBy<'_> {
646     /// Column number
647     #[inline]
648     #[must_use]
column(&self) -> c_int649     pub fn column(&self) -> c_int {
650         self.0.iColumn
651     }
652 
653     /// True for DESC.  False for ASC.
654     #[inline]
655     #[must_use]
is_order_by_desc(&self) -> bool656     pub fn is_order_by_desc(&self) -> bool {
657         self.0.desc != 0
658     }
659 }
660 
661 /// Virtual table cursor trait.
662 ///
663 /// # Safety
664 ///
665 /// Implementations must be like:
666 /// ```rust,ignore
667 /// #[repr(C)]
668 /// struct MyTabCursor {
669 ///    /// Base class. Must be first
670 ///    base: rusqlite::vtab::sqlite3_vtab_cursor,
671 ///    /* Virtual table implementations will typically add additional fields */
672 /// }
673 /// ```
674 ///
675 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab_cursor.html))
676 pub unsafe trait VTabCursor: Sized {
677     /// Begin a search of a virtual table.
678     /// (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<()>679     fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>;
680     /// Advance cursor to the next row of a result set initiated by
681     /// [`filter`](VTabCursor::filter). (See [SQLite doc](https://sqlite.org/vtab.html#the_xnext_method))
next(&mut self) -> Result<()>682     fn next(&mut self) -> Result<()>;
683     /// Must return `false` if the cursor currently points to a valid row of
684     /// data, or `true` otherwise.
685     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xeof_method))
eof(&self) -> bool686     fn eof(&self) -> bool;
687     /// Find the value for the `i`-th column of the current row.
688     /// `i` is zero-based so the first column is numbered 0.
689     /// May return its result back to SQLite using one of the specified `ctx`.
690     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcolumn_method))
column(&self, ctx: &mut Context, i: c_int) -> Result<()>691     fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
692     /// Return the rowid of row that the cursor is currently pointing at.
693     /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xrowid_method))
rowid(&self) -> Result<i64>694     fn rowid(&self) -> Result<i64>;
695 }
696 
697 /// Context is used by [`VTabCursor::column`] to specify the
698 /// cell value.
699 pub struct Context(*mut ffi::sqlite3_context);
700 
701 impl Context {
702     /// Set current cell value
703     #[inline]
set_result<T: ToSql>(&mut self, value: &T) -> Result<()>704     pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
705         let t = value.to_sql()?;
706         unsafe { set_result(self.0, &[], &t) };
707         Ok(())
708     }
709 
710     // TODO sqlite3_vtab_nochange (http://sqlite.org/c3ref/vtab_nochange.html) // 3.22.0 & xColumn
711 }
712 
713 /// Wrapper to [`VTabCursor::filter`] arguments, the values
714 /// requested by [`VTab::best_index`].
715 pub struct Values<'a> {
716     args: &'a [*mut ffi::sqlite3_value],
717 }
718 
719 impl Values<'_> {
720     /// Returns the number of values.
721     #[inline]
722     #[must_use]
len(&self) -> usize723     pub fn len(&self) -> usize {
724         self.args.len()
725     }
726 
727     /// Returns `true` if there is no value.
728     #[inline]
729     #[must_use]
is_empty(&self) -> bool730     pub fn is_empty(&self) -> bool {
731         self.args.is_empty()
732     }
733 
734     /// Returns value at `idx`
get<T: FromSql>(&self, idx: usize) -> Result<T>735     pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
736         let arg = self.args[idx];
737         let value = unsafe { ValueRef::from_value(arg) };
738         FromSql::column_result(value).map_err(|err| match err {
739             FromSqlError::InvalidType => Error::InvalidFilterParameterType(idx, value.data_type()),
740             FromSqlError::Other(err) => {
741                 Error::FromSqlConversionFailure(idx, value.data_type(), err)
742             }
743             FromSqlError::InvalidBlobSize { .. } => {
744                 Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
745             }
746             FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
747         })
748     }
749 
750     // `sqlite3_value_type` returns `SQLITE_NULL` for pointer.
751     // So it seems not possible to enhance `ValueRef::from_value`.
752     #[cfg(feature = "array")]
753     #[cfg_attr(docsrs, doc(cfg(feature = "array")))]
get_array(&self, idx: usize) -> Option<array::Array>754     fn get_array(&self, idx: usize) -> Option<array::Array> {
755         use crate::types::Value;
756         let arg = self.args[idx];
757         let ptr = unsafe { ffi::sqlite3_value_pointer(arg, array::ARRAY_TYPE) };
758         if ptr.is_null() {
759             None
760         } else {
761             Some(unsafe {
762                 let ptr = ptr as *const Vec<Value>;
763                 array::Array::increment_strong_count(ptr); // don't consume it
764                 array::Array::from_raw(ptr)
765             })
766         }
767     }
768 
769     /// Turns `Values` into an iterator.
770     #[inline]
771     #[must_use]
iter(&self) -> ValueIter<'_>772     pub fn iter(&self) -> ValueIter<'_> {
773         ValueIter {
774             iter: self.args.iter(),
775         }
776     }
777     // TODO sqlite3_vtab_in_first / sqlite3_vtab_in_next https://sqlite.org/c3ref/vtab_in_first.html & 3.38.0
778 }
779 
780 impl<'a> IntoIterator for &'a Values<'a> {
781     type IntoIter = ValueIter<'a>;
782     type Item = ValueRef<'a>;
783 
784     #[inline]
into_iter(self) -> ValueIter<'a>785     fn into_iter(self) -> ValueIter<'a> {
786         self.iter()
787     }
788 }
789 
790 /// [`Values`] iterator.
791 pub struct ValueIter<'a> {
792     iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
793 }
794 
795 impl<'a> Iterator for ValueIter<'a> {
796     type Item = ValueRef<'a>;
797 
798     #[inline]
next(&mut self) -> Option<ValueRef<'a>>799     fn next(&mut self) -> Option<ValueRef<'a>> {
800         self.iter
801             .next()
802             .map(|&raw| unsafe { ValueRef::from_value(raw) })
803     }
804 
805     #[inline]
size_hint(&self) -> (usize, Option<usize>)806     fn size_hint(&self) -> (usize, Option<usize>) {
807         self.iter.size_hint()
808     }
809 }
810 
811 impl Connection {
812     /// Register a virtual table implementation.
813     ///
814     /// Step 3 of [Creating New Virtual Table
815     /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
816     #[inline]
create_module<'vtab, T: VTab<'vtab>>( &self, module_name: &str, module: &'static Module<'vtab, T>, aux: Option<T::Aux>, ) -> Result<()>817     pub fn create_module<'vtab, T: VTab<'vtab>>(
818         &self,
819         module_name: &str,
820         module: &'static Module<'vtab, T>,
821         aux: Option<T::Aux>,
822     ) -> Result<()> {
823         self.db.borrow_mut().create_module(module_name, module, aux)
824     }
825 }
826 
827 impl InnerConnection {
create_module<'vtab, T: VTab<'vtab>>( &mut self, module_name: &str, module: &'static Module<'vtab, T>, aux: Option<T::Aux>, ) -> Result<()>828     fn create_module<'vtab, T: VTab<'vtab>>(
829         &mut self,
830         module_name: &str,
831         module: &'static Module<'vtab, T>,
832         aux: Option<T::Aux>,
833     ) -> Result<()> {
834         use crate::version;
835         if version::version_number() < 3_009_000 && module.base.xCreate.is_none() {
836             return Err(Error::ModuleError(format!(
837                 "Eponymous-only virtual table not supported by SQLite version {}",
838                 version::version()
839             )));
840         }
841         let c_name = str_to_cstring(module_name)?;
842         let r = match aux {
843             Some(aux) => {
844                 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
845                 unsafe {
846                     ffi::sqlite3_create_module_v2(
847                         self.db(),
848                         c_name.as_ptr(),
849                         &module.base,
850                         boxed_aux.cast::<c_void>(),
851                         Some(free_boxed_value::<T::Aux>),
852                     )
853                 }
854             }
855             None => unsafe {
856                 ffi::sqlite3_create_module_v2(
857                     self.db(),
858                     c_name.as_ptr(),
859                     &module.base,
860                     ptr::null_mut(),
861                     None,
862                 )
863             },
864         };
865         self.decode_result(r)
866     }
867 }
868 
869 /// Escape double-quote (`"`) character occurrences by
870 /// doubling them (`""`).
871 #[must_use]
escape_double_quote(identifier: &str) -> Cow<'_, str>872 pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
873     if identifier.contains('"') {
874         // escape quote by doubling them
875         Owned(identifier.replace('"', "\"\""))
876     } else {
877         Borrowed(identifier)
878     }
879 }
880 /// Dequote string
881 #[must_use]
dequote(s: &str) -> &str882 pub fn dequote(s: &str) -> &str {
883     if s.len() < 2 {
884         return s;
885     }
886     match s.bytes().next() {
887         Some(b) if b == b'"' || b == b'\'' => match s.bytes().next_back() {
888             Some(e) if e == b => &s[1..s.len() - 1], // FIXME handle inner escaped quote(s)
889             _ => s,
890         },
891         _ => s,
892     }
893 }
894 /// The boolean can be one of:
895 /// ```text
896 /// 1 yes true on
897 /// 0 no false off
898 /// ```
899 #[must_use]
parse_boolean(s: &str) -> Option<bool>900 pub fn parse_boolean(s: &str) -> Option<bool> {
901     if s.eq_ignore_ascii_case("yes")
902         || s.eq_ignore_ascii_case("on")
903         || s.eq_ignore_ascii_case("true")
904         || s.eq("1")
905     {
906         Some(true)
907     } else if s.eq_ignore_ascii_case("no")
908         || s.eq_ignore_ascii_case("off")
909         || s.eq_ignore_ascii_case("false")
910         || s.eq("0")
911     {
912         Some(false)
913     } else {
914         None
915     }
916 }
917 
918 /// `<param_name>=['"]?<param_value>['"]?` => `(<param_name>, <param_value>)`
parameter(c_slice: &[u8]) -> Result<(&str, &str)>919 pub fn parameter(c_slice: &[u8]) -> Result<(&str, &str)> {
920     let arg = std::str::from_utf8(c_slice)?.trim();
921     let mut split = arg.split('=');
922     if let Some(key) = split.next() {
923         if let Some(value) = split.next() {
924             let param = key.trim();
925             let value = dequote(value.trim());
926             return Ok((param, value));
927         }
928     }
929     Err(Error::ModuleError(format!("illegal argument: '{arg}'")))
930 }
931 
932 // FIXME copy/paste from function.rs
free_boxed_value<T>(p: *mut c_void)933 unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
934     drop(Box::from_raw(p.cast::<T>()));
935 }
936 
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>,937 unsafe extern "C" fn rust_create<'vtab, T>(
938     db: *mut ffi::sqlite3,
939     aux: *mut c_void,
940     argc: c_int,
941     argv: *const *const c_char,
942     pp_vtab: *mut *mut ffi::sqlite3_vtab,
943     err_msg: *mut *mut c_char,
944 ) -> c_int
945 where
946     T: CreateVTab<'vtab>,
947 {
948     use std::ffi::CStr;
949 
950     let mut conn = VTabConnection(db);
951     let aux = aux.cast::<T::Aux>();
952     let args = slice::from_raw_parts(argv, argc as usize);
953     let vec = args
954         .iter()
955         .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
956         .collect::<Vec<_>>();
957     match T::create(&mut conn, aux.as_ref(), &vec[..]) {
958         Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
959             Ok(c_sql) => {
960                 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
961                 if rc == ffi::SQLITE_OK {
962                     let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
963                     *pp_vtab = boxed_vtab.cast::<ffi::sqlite3_vtab>();
964                     ffi::SQLITE_OK
965                 } else {
966                     let err = error_from_sqlite_code(rc, None);
967                     to_sqlite_error(&err, err_msg)
968                 }
969             }
970             Err(err) => {
971                 *err_msg = alloc(&err.to_string());
972                 ffi::SQLITE_ERROR
973             }
974         },
975         Err(err) => to_sqlite_error(&err, err_msg),
976     }
977 }
978 
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>,979 unsafe extern "C" fn rust_connect<'vtab, T>(
980     db: *mut ffi::sqlite3,
981     aux: *mut c_void,
982     argc: c_int,
983     argv: *const *const c_char,
984     pp_vtab: *mut *mut ffi::sqlite3_vtab,
985     err_msg: *mut *mut c_char,
986 ) -> c_int
987 where
988     T: VTab<'vtab>,
989 {
990     use std::ffi::CStr;
991 
992     let mut conn = VTabConnection(db);
993     let aux = aux.cast::<T::Aux>();
994     let args = slice::from_raw_parts(argv, argc as usize);
995     let vec = args
996         .iter()
997         .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
998         .collect::<Vec<_>>();
999     match T::connect(&mut conn, aux.as_ref(), &vec[..]) {
1000         Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
1001             Ok(c_sql) => {
1002                 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
1003                 if rc == ffi::SQLITE_OK {
1004                     let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1005                     *pp_vtab = boxed_vtab.cast::<ffi::sqlite3_vtab>();
1006                     ffi::SQLITE_OK
1007                 } else {
1008                     let err = error_from_sqlite_code(rc, None);
1009                     to_sqlite_error(&err, err_msg)
1010                 }
1011             }
1012             Err(err) => {
1013                 *err_msg = alloc(&err.to_string());
1014                 ffi::SQLITE_ERROR
1015             }
1016         },
1017         Err(err) => to_sqlite_error(&err, err_msg),
1018     }
1019 }
1020 
rust_best_index<'vtab, T>( vtab: *mut ffi::sqlite3_vtab, info: *mut ffi::sqlite3_index_info, ) -> c_int where T: VTab<'vtab>,1021 unsafe extern "C" fn rust_best_index<'vtab, T>(
1022     vtab: *mut ffi::sqlite3_vtab,
1023     info: *mut ffi::sqlite3_index_info,
1024 ) -> c_int
1025 where
1026     T: VTab<'vtab>,
1027 {
1028     let vt = vtab.cast::<T>();
1029     let mut idx_info = IndexInfo(info);
1030     match (*vt).best_index(&mut idx_info) {
1031         Ok(_) => ffi::SQLITE_OK,
1032         Err(Error::SqliteFailure(err, s)) => {
1033             if let Some(err_msg) = s {
1034                 set_err_msg(vtab, &err_msg);
1035             }
1036             err.extended_code
1037         }
1038         Err(err) => {
1039             set_err_msg(vtab, &err.to_string());
1040             ffi::SQLITE_ERROR
1041         }
1042     }
1043 }
1044 
rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where T: VTab<'vtab>,1045 unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
1046 where
1047     T: VTab<'vtab>,
1048 {
1049     if vtab.is_null() {
1050         return ffi::SQLITE_OK;
1051     }
1052     let vtab = vtab.cast::<T>();
1053     drop(Box::from_raw(vtab));
1054     ffi::SQLITE_OK
1055 }
1056 
rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where T: CreateVTab<'vtab>,1057 unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
1058 where
1059     T: CreateVTab<'vtab>,
1060 {
1061     if vtab.is_null() {
1062         return ffi::SQLITE_OK;
1063     }
1064     let vt = vtab.cast::<T>();
1065     match (*vt).destroy() {
1066         Ok(_) => {
1067             drop(Box::from_raw(vt));
1068             ffi::SQLITE_OK
1069         }
1070         Err(Error::SqliteFailure(err, s)) => {
1071             if let Some(err_msg) = s {
1072                 set_err_msg(vtab, &err_msg);
1073             }
1074             err.extended_code
1075         }
1076         Err(err) => {
1077             set_err_msg(vtab, &err.to_string());
1078             ffi::SQLITE_ERROR
1079         }
1080     }
1081 }
1082 
rust_open<'vtab, T>( vtab: *mut ffi::sqlite3_vtab, pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor, ) -> c_int where T: VTab<'vtab> + 'vtab,1083 unsafe extern "C" fn rust_open<'vtab, T>(
1084     vtab: *mut ffi::sqlite3_vtab,
1085     pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor,
1086 ) -> c_int
1087 where
1088     T: VTab<'vtab> + 'vtab,
1089 {
1090     let vt = vtab.cast::<T>();
1091     match (*vt).open() {
1092         Ok(cursor) => {
1093             let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
1094             *pp_cursor = boxed_cursor.cast::<ffi::sqlite3_vtab_cursor>();
1095             ffi::SQLITE_OK
1096         }
1097         Err(Error::SqliteFailure(err, s)) => {
1098             if let Some(err_msg) = s {
1099                 set_err_msg(vtab, &err_msg);
1100             }
1101             err.extended_code
1102         }
1103         Err(err) => {
1104             set_err_msg(vtab, &err.to_string());
1105             ffi::SQLITE_ERROR
1106         }
1107     }
1108 }
1109 
rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,1110 unsafe extern "C" fn rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1111 where
1112     C: VTabCursor,
1113 {
1114     let cr = cursor.cast::<C>();
1115     drop(Box::from_raw(cr));
1116     ffi::SQLITE_OK
1117 }
1118 
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,1119 unsafe extern "C" fn rust_filter<C>(
1120     cursor: *mut ffi::sqlite3_vtab_cursor,
1121     idx_num: c_int,
1122     idx_str: *const c_char,
1123     argc: c_int,
1124     argv: *mut *mut ffi::sqlite3_value,
1125 ) -> c_int
1126 where
1127     C: VTabCursor,
1128 {
1129     use std::ffi::CStr;
1130     use std::str;
1131     let idx_name = if idx_str.is_null() {
1132         None
1133     } else {
1134         let c_slice = CStr::from_ptr(idx_str).to_bytes();
1135         Some(str::from_utf8_unchecked(c_slice))
1136     };
1137     let args = slice::from_raw_parts_mut(argv, argc as usize);
1138     let values = Values { args };
1139     let cr = cursor as *mut C;
1140     cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values))
1141 }
1142 
rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,1143 unsafe extern "C" fn rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1144 where
1145     C: VTabCursor,
1146 {
1147     let cr = cursor as *mut C;
1148     cursor_error(cursor, (*cr).next())
1149 }
1150 
rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,1151 unsafe extern "C" fn rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1152 where
1153     C: VTabCursor,
1154 {
1155     let cr = cursor.cast::<C>();
1156     (*cr).eof() as c_int
1157 }
1158 
rust_column<C>( cursor: *mut ffi::sqlite3_vtab_cursor, ctx: *mut ffi::sqlite3_context, i: c_int, ) -> c_int where C: VTabCursor,1159 unsafe extern "C" fn rust_column<C>(
1160     cursor: *mut ffi::sqlite3_vtab_cursor,
1161     ctx: *mut ffi::sqlite3_context,
1162     i: c_int,
1163 ) -> c_int
1164 where
1165     C: VTabCursor,
1166 {
1167     let cr = cursor.cast::<C>();
1168     let mut ctxt = Context(ctx);
1169     result_error(ctx, (*cr).column(&mut ctxt, i))
1170 }
1171 
rust_rowid<C>( cursor: *mut ffi::sqlite3_vtab_cursor, p_rowid: *mut ffi::sqlite3_int64, ) -> c_int where C: VTabCursor,1172 unsafe extern "C" fn rust_rowid<C>(
1173     cursor: *mut ffi::sqlite3_vtab_cursor,
1174     p_rowid: *mut ffi::sqlite3_int64,
1175 ) -> c_int
1176 where
1177     C: VTabCursor,
1178 {
1179     let cr = cursor.cast::<C>();
1180     match (*cr).rowid() {
1181         Ok(rowid) => {
1182             *p_rowid = rowid;
1183             ffi::SQLITE_OK
1184         }
1185         err => cursor_error(cursor, err),
1186     }
1187 }
1188 
rust_update<'vtab, T>( vtab: *mut ffi::sqlite3_vtab, argc: c_int, argv: *mut *mut ffi::sqlite3_value, p_rowid: *mut ffi::sqlite3_int64, ) -> c_int where T: UpdateVTab<'vtab> + 'vtab,1189 unsafe extern "C" fn rust_update<'vtab, T>(
1190     vtab: *mut ffi::sqlite3_vtab,
1191     argc: c_int,
1192     argv: *mut *mut ffi::sqlite3_value,
1193     p_rowid: *mut ffi::sqlite3_int64,
1194 ) -> c_int
1195 where
1196     T: UpdateVTab<'vtab> + 'vtab,
1197 {
1198     assert!(argc >= 1);
1199     let args = slice::from_raw_parts_mut(argv, argc as usize);
1200     let vt = vtab.cast::<T>();
1201     let r = if args.len() == 1 {
1202         (*vt).delete(ValueRef::from_value(args[0]))
1203     } else if ffi::sqlite3_value_type(args[0]) == ffi::SQLITE_NULL {
1204         // TODO Make the distinction between argv[1] == NULL and argv[1] != NULL ?
1205         let values = Values { args };
1206         match (*vt).insert(&values) {
1207             Ok(rowid) => {
1208                 *p_rowid = rowid;
1209                 Ok(())
1210             }
1211             Err(e) => Err(e),
1212         }
1213     } else {
1214         let values = Values { args };
1215         (*vt).update(&values)
1216     };
1217     match r {
1218         Ok(_) => ffi::SQLITE_OK,
1219         Err(Error::SqliteFailure(err, s)) => {
1220             if let Some(err_msg) = s {
1221                 set_err_msg(vtab, &err_msg);
1222             }
1223             err.extended_code
1224         }
1225         Err(err) => {
1226             set_err_msg(vtab, &err.to_string());
1227             ffi::SQLITE_ERROR
1228         }
1229     }
1230 }
1231 
1232 /// Virtual table cursors can set an error message by assigning a string to
1233 /// `zErrMsg`.
1234 #[cold]
cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int1235 unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int {
1236     match result {
1237         Ok(_) => ffi::SQLITE_OK,
1238         Err(Error::SqliteFailure(err, s)) => {
1239             if let Some(err_msg) = s {
1240                 set_err_msg((*cursor).pVtab, &err_msg);
1241             }
1242             err.extended_code
1243         }
1244         Err(err) => {
1245             set_err_msg((*cursor).pVtab, &err.to_string());
1246             ffi::SQLITE_ERROR
1247         }
1248     }
1249 }
1250 
1251 /// Virtual tables methods can set an error message by assigning a string to
1252 /// `zErrMsg`.
1253 #[cold]
set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str)1254 unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
1255     if !(*vtab).zErrMsg.is_null() {
1256         ffi::sqlite3_free((*vtab).zErrMsg.cast::<c_void>());
1257     }
1258     (*vtab).zErrMsg = alloc(err_msg);
1259 }
1260 
1261 /// To raise an error, the `column` method should use this method to set the
1262 /// error message and return the error code.
1263 #[cold]
result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int1264 unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
1265     match result {
1266         Ok(_) => ffi::SQLITE_OK,
1267         Err(Error::SqliteFailure(err, s)) => {
1268             match err.extended_code {
1269                 ffi::SQLITE_TOOBIG => {
1270                     ffi::sqlite3_result_error_toobig(ctx);
1271                 }
1272                 ffi::SQLITE_NOMEM => {
1273                     ffi::sqlite3_result_error_nomem(ctx);
1274                 }
1275                 code => {
1276                     ffi::sqlite3_result_error_code(ctx, code);
1277                     if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
1278                         ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1279                     }
1280                 }
1281             };
1282             err.extended_code
1283         }
1284         Err(err) => {
1285             ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_ERROR);
1286             if let Ok(cstr) = str_to_cstring(&err.to_string()) {
1287                 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1288             }
1289             ffi::SQLITE_ERROR
1290         }
1291     }
1292 }
1293 
1294 #[cfg(feature = "array")]
1295 #[cfg_attr(docsrs, doc(cfg(feature = "array")))]
1296 pub mod array;
1297 #[cfg(feature = "csvtab")]
1298 #[cfg_attr(docsrs, doc(cfg(feature = "csvtab")))]
1299 pub mod csvtab;
1300 #[cfg(feature = "series")]
1301 #[cfg_attr(docsrs, doc(cfg(feature = "series")))]
1302 pub mod series; // SQLite >= 3.9.0
1303 #[cfg(all(test, feature = "modern_sqlite"))]
1304 mod vtablog;
1305 
1306 #[cfg(test)]
1307 mod test {
1308     #[test]
test_dequote()1309     fn test_dequote() {
1310         assert_eq!("", super::dequote(""));
1311         assert_eq!("'", super::dequote("'"));
1312         assert_eq!("\"", super::dequote("\""));
1313         assert_eq!("'\"", super::dequote("'\""));
1314         assert_eq!("", super::dequote("''"));
1315         assert_eq!("", super::dequote("\"\""));
1316         assert_eq!("x", super::dequote("'x'"));
1317         assert_eq!("x", super::dequote("\"x\""));
1318         assert_eq!("x", super::dequote("x"));
1319     }
1320     #[test]
test_parse_boolean()1321     fn test_parse_boolean() {
1322         assert_eq!(None, super::parse_boolean(""));
1323         assert_eq!(Some(true), super::parse_boolean("1"));
1324         assert_eq!(Some(true), super::parse_boolean("yes"));
1325         assert_eq!(Some(true), super::parse_boolean("on"));
1326         assert_eq!(Some(true), super::parse_boolean("true"));
1327         assert_eq!(Some(false), super::parse_boolean("0"));
1328         assert_eq!(Some(false), super::parse_boolean("no"));
1329         assert_eq!(Some(false), super::parse_boolean("off"));
1330         assert_eq!(Some(false), super::parse_boolean("false"));
1331     }
1332 }
1333