rusqlite/vtab/
mod.rs

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