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