Skip to main content

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::ffi::{c_char, c_int, c_void, CStr};
14use std::marker::PhantomData;
15use std::ops::Deref;
16use std::ptr;
17use std::slice;
18
19use crate::ffi::sqlite3_free;
20
21use crate::context::set_result;
22use crate::error::{check, error_from_sqlite_code, to_sqlite_error};
23use crate::ffi;
24pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor};
25use crate::types::{FromSql, FromSqlError, ToSql, ValueRef};
26use crate::util::{alloc, free_boxed_value};
27use crate::{str_to_cstring, Connection, Error, InnerConnection, Name, Result};
28
29// let conn: Connection = ...;
30// let mod: Module = ...; // VTab builder
31// conn.create_module("module", mod);
32//
33// conn.execute("CREATE VIRTUAL TABLE foo USING module(...)");
34// \-> Module::xcreate
35//  |-> let vtab: VTab = ...; // on the heap
36//  \-> conn.declare_vtab("CREATE TABLE foo (...)");
37// conn = Connection::open(...);
38// \-> Module::xconnect
39//  |-> let vtab: VTab = ...; // on the heap
40//  \-> conn.declare_vtab("CREATE TABLE foo (...)");
41//
42// conn.close();
43// \-> vtab.xdisconnect
44// conn.execute("DROP TABLE foo");
45// \-> vtab.xDestroy
46//
47// let stmt = conn.prepare("SELECT ... FROM foo WHERE ...");
48// \-> vtab.xbestindex
49// stmt.query().next();
50// \-> vtab.xopen
51//  |-> let cursor: VTabCursor = ...; // on the heap
52//  |-> cursor.xfilter or xnext
53//  |-> cursor.xeof
54//  \-> if not eof { cursor.column or xrowid } else { cursor.xclose }
55//
56
57// db: *mut ffi::sqlite3 => VTabConnection
58// module: *const ffi::sqlite3_module => Module
59// aux: *mut c_void => Module::Aux
60// ffi::sqlite3_vtab => VTab
61// ffi::sqlite3_vtab_cursor => VTabCursor
62
63/// Virtual table kind
64pub enum VTabKind {
65    /// Non-eponymous
66    Default,
67    /// [`create`](CreateVTab::create) == [`connect`](VTab::connect)
68    ///
69    /// See [SQLite doc](https://sqlite.org/vtab.html#eponymous_virtual_tables)
70    Eponymous,
71    /// No [`create`](CreateVTab::create) / [`destroy`](CreateVTab::destroy) or
72    /// not used
73    ///
74    /// SQLite >= 3.9.0
75    ///
76    /// See [SQLite doc](https://sqlite.org/vtab.html#eponymous_only_virtual_tables)
77    EponymousOnly,
78}
79
80/// Virtual table module
81///
82/// (See [SQLite doc](https://sqlite.org/c3ref/module.html))
83#[repr(transparent)]
84pub struct Module<'vtab, T: VTab<'vtab>> {
85    base: ffi::sqlite3_module,
86    phantom: PhantomData<&'vtab T>,
87}
88
89union ModuleZeroHack {
90    bytes: [u8; 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; size_of::<ffi::sqlite3_module>()],
100    }
101    .module
102};
103
104impl<'vtab, T: VTab<'vtab>> Module<'vtab, T> {
105    /// Create an eponymous only virtual table implementation.
106    ///
107    /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
108    #[must_use]
109    pub const fn eponymous_only_module() -> Self {
110        //  For eponymous-only virtual tables, the xCreate method is NULL
111        Module {
112            base: ffi::sqlite3_module {
113                // We don't use methods provided by versions > 1
114                iVersion: 1,
115                xCreate: None,
116                xConnect: Some(rust_connect::<T>),
117                xBestIndex: Some(rust_best_index::<T>),
118                xDisconnect: Some(rust_disconnect::<T>),
119                xDestroy: None,
120                xOpen: Some(rust_open::<T>),
121                xClose: Some(rust_close::<T::Cursor>),
122                xFilter: Some(rust_filter::<T::Cursor>),
123                xNext: Some(rust_next::<T::Cursor>),
124                xEof: Some(rust_eof::<T::Cursor>),
125                xColumn: Some(rust_column::<T::Cursor>),
126                xRowid: Some(rust_rowid::<T::Cursor>),
127                xUpdate: None,
128                xBegin: None,
129                xSync: None,
130                xCommit: None,
131                xRollback: None,
132                xFindFunction: None,
133                xRename: None,
134                ..ZERO_MODULE
135            },
136            phantom: PhantomData::<&'vtab T>,
137        }
138    }
139
140    /// Create a read-only 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]
144    pub const fn read_only_module() -> Self
145    where
146        T: CreateVTab<'vtab>,
147    {
148        let mut module = Self::eponymous_only_module();
149        match T::KIND {
150            VTabKind::EponymousOnly => module,
151            VTabKind::Eponymous => {
152                // A virtual table is eponymous if its xCreate method is the exact same function
153                // as the xConnect method
154                module.base.xCreate = module.base.xConnect;
155                module.base.xDestroy = module.base.xDisconnect;
156                module
157            }
158            _ => {
159                // The xConnect and xCreate methods may do the same thing, but they must be
160                // different so that the virtual table is not an eponymous virtual table.
161                module.base.xCreate = Some(rust_create::<T>);
162                module.base.xDestroy = Some(rust_destroy::<T>);
163                module
164            }
165        }
166    }
167
168    /// Create a modifiable virtual table implementation.
169    ///
170    /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
171    #[must_use]
172    pub const fn update_module() -> Self
173    where
174        T: UpdateVTab<'vtab>,
175    {
176        let mut module = Self::read_only_module();
177        module.base.xUpdate = Some(rust_update::<T>);
178        module
179    }
180
181    /// Create a modifiable virtual table implementation with support for transactions.
182    ///
183    /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
184    #[must_use]
185    pub const fn update_module_with_tx() -> Self
186    where
187        T: TransactionVTab<'vtab>,
188    {
189        let mut module = Self::update_module();
190        module.base.xBegin = Some(rust_begin::<T>);
191        module.base.xSync = Some(rust_sync::<T>);
192        module.base.xCommit = Some(rust_commit::<T>);
193        module.base.xRollback = Some(rust_rollback::<T>);
194        module
195    }
196
197    /// No `xRowid`
198    pub const fn without_rowid(mut self) -> Self {
199        self.base.xRowid = None;
200        self
201    }
202
203    /// No `xSync`
204    pub const fn without_sync(mut self) -> Self
205    where
206        T: TransactionVTab<'vtab>,
207    {
208        self.base.xSync = None;
209        self
210    }
211}
212
213/// Virtual table configuration options
214#[repr(i32)]
215#[non_exhaustive]
216#[derive(Debug, Clone, Copy, Eq, PartialEq)]
217pub enum VTabConfig {
218    /// Equivalent to `SQLITE_VTAB_CONSTRAINT_SUPPORT`
219    ConstraintSupport = 1,
220    /// Equivalent to `SQLITE_VTAB_INNOCUOUS`
221    Innocuous = 2,
222    /// Equivalent to `SQLITE_VTAB_DIRECTONLY`
223    DirectOnly = 3,
224    /// Equivalent to `SQLITE_VTAB_USES_ALL_SCHEMAS`
225    UsesAllSchemas = 4,
226}
227
228/// `feature = "vtab"`
229pub struct VTabConnection(*mut ffi::sqlite3);
230
231impl VTabConnection {
232    /// Configure various facets of the virtual table interface
233    pub fn config(&mut self, config: VTabConfig) -> Result<()> {
234        check(unsafe { ffi::sqlite3_vtab_config(self.0, config as c_int) })
235    }
236
237    /// Get access to the underlying SQLite database connection handle.
238    ///
239    /// # Warning
240    ///
241    /// You should not need to use this function. If you do need to, please
242    /// [open an issue on the rusqlite repository](https://github.com/rusqlite/rusqlite/issues) and describe
243    /// your use case.
244    ///
245    /// # Safety
246    ///
247    /// This function is unsafe because it gives you raw access
248    /// to the SQLite connection, and what you do with it could impact the
249    /// safety of this `Connection`.
250    pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
251        self.0
252    }
253}
254
255/// Eponymous-only virtual table instance trait.
256///
257/// # Safety
258///
259/// The first item in a struct implementing `VTab` must be
260/// `rusqlite::sqlite3_vtab`, and the struct must be `#[repr(C)]`.
261///
262/// ```rust,ignore
263/// #[repr(C)]
264/// struct MyTab {
265///    /// Base class. Must be first
266///    base: rusqlite::vtab::sqlite3_vtab,
267///    /* Virtual table implementations will typically add additional fields */
268/// }
269/// ```
270///
271/// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
272pub unsafe trait VTab<'vtab>: Sized {
273    /// Client data passed to [`Connection::create_module`].
274    type Aux: Send + Sync + 'static;
275    /// Specific cursor implementation
276    type Cursor: VTabCursor;
277
278    /// Establish a new connection to an existing virtual table.
279    ///
280    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xconnect_method))
281    fn connect(
282        db: &mut VTabConnection,
283        aux: Option<&Self::Aux>,
284        module_name: &[u8],
285        database_name: &[u8],
286        table_name: &[u8],
287        args: &[&[u8]],
288    ) -> Result<(Cow<'static, CStr>, Self)>;
289
290    /// Determine the best way to access the virtual table.
291    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xbestindex_method))
292    /// Returning `Ok(false)` means unusable / `SQLITE_CONSTRAINT`.
293    fn best_index(&self, info: &mut IndexInfo) -> Result<bool>;
294
295    /// Create a new cursor used for accessing a virtual table.
296    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xopen_method))
297    fn open(&'vtab mut self) -> Result<Self::Cursor>;
298}
299
300/// Read-only virtual table instance trait.
301///
302/// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
303pub trait CreateVTab<'vtab>: VTab<'vtab> {
304    /// For [`EponymousOnly`](VTabKind::EponymousOnly),
305    /// [`create`](CreateVTab::create) and [`destroy`](CreateVTab::destroy) are
306    /// not called
307    const KIND: VTabKind;
308    /// Create a new instance of a virtual table in response to a CREATE VIRTUAL
309    /// TABLE statement. The `db` parameter is a pointer to the SQLite
310    /// database connection that is executing the CREATE VIRTUAL TABLE
311    /// statement.
312    ///
313    /// Call [`connect`](VTab::connect) by default.
314    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcreate_method))
315    fn create(
316        db: &mut VTabConnection,
317        aux: Option<&Self::Aux>,
318        module_name: &[u8],
319        database_name: &[u8],
320        table_name: &[u8],
321        args: &[&[u8]],
322    ) -> Result<(Cow<'static, CStr>, Self)> {
323        Self::connect(db, aux, module_name, database_name, table_name, args)
324    }
325
326    /// Destroy the underlying table implementation. This method undoes the work
327    /// of [`create`](CreateVTab::create).
328    ///
329    /// Do nothing by default.
330    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xdestroy_method))
331    fn destroy(&self) -> Result<()> {
332        Ok(())
333    }
334}
335
336/// Writable virtual table instance trait.
337///
338/// (See [SQLite doc](https://sqlite.org/vtab.html#xupdate))
339pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
340    /// Delete rowid or PK
341    fn delete(&mut self, arg: ValueRef<'_>) -> Result<()>;
342    /// Insert: `args[0] == NULL: old rowid or PK, args[1]: new rowid or PK,
343    /// args[2]: ...`
344    ///
345    /// Return the new rowid.
346    // TODO Make the distinction between argv[1] == NULL and argv[1] != NULL ?
347    fn insert(&mut self, args: &Inserts<'_>) -> Result<i64>;
348    /// Update: `args[0] != NULL: old rowid or PK, args[1]: new row id or PK,
349    /// args[2]: ...`
350    fn update(&mut self, args: &Updates<'_>) -> Result<()>;
351}
352
353/// Writable virtual table instance with transaction support trait.
354///
355/// See [SQLite doc](https://sqlite.org/vtab.html#the_xbegin_method)
356pub trait TransactionVTab<'vtab>: UpdateVTab<'vtab> {
357    /// Start a new transaction
358    fn begin(&mut self) -> Result<()> {
359        Ok(())
360    }
361    /// Begin two-phase commit
362    fn sync(&mut self) -> Result<()> {
363        Ok(())
364    }
365    /// Commit the current transaction
366    fn commit(&mut self) -> Result<()> {
367        Ok(())
368    }
369    /// Abandon the current transaction
370    fn rollback(&mut self) -> Result<()> {
371        Ok(())
372    }
373}
374
375/// Index constraint operator.
376/// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
377#[derive(Debug, Eq, PartialEq)]
378#[allow(missing_docs)]
379#[expect(non_camel_case_types)]
380pub enum IndexConstraintOp {
381    SQLITE_INDEX_CONSTRAINT_EQ,
382    SQLITE_INDEX_CONSTRAINT_GT,
383    SQLITE_INDEX_CONSTRAINT_LE,
384    SQLITE_INDEX_CONSTRAINT_LT,
385    SQLITE_INDEX_CONSTRAINT_GE,
386    SQLITE_INDEX_CONSTRAINT_MATCH,
387    SQLITE_INDEX_CONSTRAINT_LIKE,         // 3.10.0
388    SQLITE_INDEX_CONSTRAINT_GLOB,         // 3.10.0
389    SQLITE_INDEX_CONSTRAINT_REGEXP,       // 3.10.0
390    SQLITE_INDEX_CONSTRAINT_NE,           // 3.21.0
391    SQLITE_INDEX_CONSTRAINT_ISNOT,        // 3.21.0
392    SQLITE_INDEX_CONSTRAINT_ISNOTNULL,    // 3.21.0
393    SQLITE_INDEX_CONSTRAINT_ISNULL,       // 3.21.0
394    SQLITE_INDEX_CONSTRAINT_IS,           // 3.21.0
395    SQLITE_INDEX_CONSTRAINT_LIMIT,        // 3.38.0
396    SQLITE_INDEX_CONSTRAINT_OFFSET,       // 3.38.0
397    SQLITE_INDEX_CONSTRAINT_FUNCTION(u8), // 3.25.0
398}
399
400impl From<u8> for IndexConstraintOp {
401    fn from(code: u8) -> Self {
402        match code {
403            2 => Self::SQLITE_INDEX_CONSTRAINT_EQ,
404            4 => Self::SQLITE_INDEX_CONSTRAINT_GT,
405            8 => Self::SQLITE_INDEX_CONSTRAINT_LE,
406            16 => Self::SQLITE_INDEX_CONSTRAINT_LT,
407            32 => Self::SQLITE_INDEX_CONSTRAINT_GE,
408            64 => Self::SQLITE_INDEX_CONSTRAINT_MATCH,
409            65 => Self::SQLITE_INDEX_CONSTRAINT_LIKE,
410            66 => Self::SQLITE_INDEX_CONSTRAINT_GLOB,
411            67 => Self::SQLITE_INDEX_CONSTRAINT_REGEXP,
412            68 => Self::SQLITE_INDEX_CONSTRAINT_NE,
413            69 => Self::SQLITE_INDEX_CONSTRAINT_ISNOT,
414            70 => Self::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
415            71 => Self::SQLITE_INDEX_CONSTRAINT_ISNULL,
416            72 => Self::SQLITE_INDEX_CONSTRAINT_IS,
417            73 => Self::SQLITE_INDEX_CONSTRAINT_LIMIT,
418            74 => Self::SQLITE_INDEX_CONSTRAINT_OFFSET,
419            v => Self::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
420        }
421    }
422}
423
424bitflags::bitflags! {
425    /// Virtual table scan flags
426    /// See [Function Flags](https://sqlite.org/c3ref/c_index_scan_unique.html) for details.
427    #[repr(C)]
428    #[derive(Copy, Clone, Debug)]
429    pub struct IndexFlags: c_int {
430        /// Default
431        const NONE     = 0;
432        /// Scan visits at most 1 row.
433        const SQLITE_INDEX_SCAN_UNIQUE  = ffi::SQLITE_INDEX_SCAN_UNIQUE;
434        /// Display idxNum as hex in EXPLAIN QUERY PLAN
435        const SQLITE_INDEX_SCAN_HEX  = 0x0000_0002; // 3.47.0
436    }
437}
438
439/// Pass information into and receive the reply from the
440/// [`VTab::best_index`] method.
441///
442/// (See [SQLite doc](http://sqlite.org/c3ref/index_info.html))
443#[derive(Debug)]
444pub struct IndexInfo(*mut ffi::sqlite3_index_info);
445
446impl IndexInfo {
447    /// Iterate on index constraint and its associated usage.
448    #[inline]
449    pub fn constraints_and_usages(&mut self) -> IndexConstraintAndUsageIter<'_> {
450        let constraints =
451            unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
452        let constraint_usages = unsafe {
453            slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
454        };
455        IndexConstraintAndUsageIter {
456            iter: constraints.iter().zip(constraint_usages.iter_mut()),
457        }
458    }
459
460    /// Record WHERE clause constraints.
461    #[inline]
462    #[must_use]
463    pub fn constraints(&self) -> IndexConstraintIter<'_> {
464        let constraints =
465            unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
466        IndexConstraintIter {
467            iter: constraints.iter(),
468        }
469    }
470
471    /// Information about the ORDER BY clause.
472    #[inline]
473    #[must_use]
474    pub fn order_bys(&self) -> OrderByIter<'_> {
475        let order_bys =
476            unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
477        OrderByIter {
478            iter: order_bys.iter(),
479        }
480    }
481
482    /// Number of terms in the ORDER BY clause
483    #[inline]
484    #[must_use]
485    pub fn num_of_order_by(&self) -> usize {
486        unsafe { (*self.0).nOrderBy as usize }
487    }
488
489    /// Information about what parameters to pass to [`VTabCursor::filter`].
490    #[inline]
491    pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
492        let constraint_usages = unsafe {
493            slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
494        };
495        IndexConstraintUsage(&mut constraint_usages[constraint_idx])
496    }
497
498    /// Number used to identify the index
499    #[inline]
500    pub fn set_idx_num(&mut self, idx_num: c_int) {
501        unsafe {
502            (*self.0).idxNum = idx_num;
503        }
504    }
505
506    /// String used to identify the index
507    pub fn set_idx_str(&mut self, idx_str: &str) {
508        unsafe {
509            if (*self.0).needToFreeIdxStr == 1 {
510                sqlite3_free((*self.0).idxStr as _);
511            }
512            (*self.0).idxStr = alloc(idx_str);
513            (*self.0).needToFreeIdxStr = 1;
514        }
515    }
516    /// String used to identify the index
517    pub fn set_idx_cstr(&mut self, idx_str: &'static CStr) {
518        unsafe {
519            if (*self.0).needToFreeIdxStr == 1 {
520                sqlite3_free((*self.0).idxStr as _);
521            }
522            (*self.0).idxStr = idx_str.as_ptr() as _;
523            (*self.0).needToFreeIdxStr = 0;
524        }
525    }
526
527    /// True if output is already ordered
528    #[inline]
529    pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
530        unsafe {
531            (*self.0).orderByConsumed = order_by_consumed as c_int;
532        }
533    }
534
535    /// Estimated cost of using this index
536    #[inline]
537    pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
538        unsafe {
539            (*self.0).estimatedCost = estimated_ost;
540        }
541    }
542
543    /// Estimated number of rows returned.
544    #[inline]
545    pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
546        unsafe {
547            (*self.0).estimatedRows = estimated_rows;
548        }
549    }
550
551    /// Mask of `SQLITE_INDEX_SCAN_*` flags.
552    #[inline]
553    pub fn set_idx_flags(&mut self, flags: IndexFlags) {
554        unsafe { (*self.0).idxFlags = flags.bits() };
555    }
556
557    /// Mask of columns used by statement
558    #[inline]
559    pub fn col_used(&self) -> u64 {
560        unsafe { (*self.0).colUsed }
561    }
562
563    /// Determine the collation for a virtual table constraint
564    pub fn collation(&self, constraint_idx: usize) -> Result<&str> {
565        let idx = constraint_idx as c_int;
566        let collation = unsafe { ffi::sqlite3_vtab_collation(self.0, idx) };
567        if collation.is_null() {
568            return Err(err!(ffi::SQLITE_MISUSE, "{constraint_idx} is out of range"));
569        }
570        Ok(unsafe { CStr::from_ptr(collation) }.to_str()?)
571    }
572
573    /// Determine if a virtual table query is DISTINCT
574    #[must_use]
575    #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
576    pub fn distinct(&self) -> DistinctMode {
577        match unsafe { ffi::sqlite3_vtab_distinct(self.0) } {
578            0 => DistinctMode::Ordered,
579            1 => DistinctMode::Grouped,
580            2 => DistinctMode::Distinct,
581            3 => DistinctMode::DistinctOrdered,
582            _ => DistinctMode::Ordered,
583        }
584    }
585
586    /// Constraint value
587    #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
588    pub fn rhs_value(&self, constraint_idx: usize) -> Result<Option<ValueRef<'_>>> {
589        let idx = constraint_idx as c_int;
590        let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
591        let rc = unsafe { ffi::sqlite3_vtab_rhs_value(self.0, idx, &mut p_value) };
592        if rc == ffi::SQLITE_NOTFOUND {
593            return Ok(None);
594        }
595        check(rc)?;
596        assert!(!p_value.is_null());
597        Ok(Some(unsafe { ValueRef::from_value(p_value) }))
598    }
599
600    /// Identify IN constraints
601    #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
602    pub fn is_in_constraint(&self, constraint_idx: usize) -> Result<bool> {
603        self.check_constraint_index(constraint_idx)?;
604        let idx = constraint_idx as c_int;
605        Ok(unsafe { ffi::sqlite3_vtab_in(self.0, idx, -1) != 0 })
606    }
607    /// Handle IN constraints
608    #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
609    pub fn set_in_constraint(&mut self, constraint_idx: usize, filter_all: bool) -> Result<bool> {
610        self.check_constraint_index(constraint_idx)?;
611        let idx = constraint_idx as c_int;
612        Ok(unsafe { ffi::sqlite3_vtab_in(self.0, idx, filter_all as c_int) != 0 })
613    }
614
615    #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
616    fn check_constraint_index(&self, idx: usize) -> Result<()> {
617        if idx >= unsafe { (*self.0).nConstraint } as usize {
618            return Err(err!(ffi::SQLITE_MISUSE, "{idx} is out of range"));
619        }
620        Ok(())
621    }
622}
623
624/// Determine if a virtual table query is DISTINCT
625#[non_exhaustive]
626#[derive(Debug, Eq, PartialEq)]
627pub enum DistinctMode {
628    /// This is the default expectation.
629    Ordered,
630    /// This mode is used when the query planner is doing a GROUP BY.
631    Grouped,
632    /// This mode is used for a DISTINCT query.
633    Distinct,
634    /// This mode is used for queries that have both DISTINCT and ORDER BY clauses.
635    DistinctOrdered,
636}
637
638/// Iterate on index constraint and its associated usage.
639pub struct IndexConstraintAndUsageIter<'a> {
640    iter: std::iter::Zip<
641        slice::Iter<'a, ffi::sqlite3_index_constraint>,
642        slice::IterMut<'a, ffi::sqlite3_index_constraint_usage>,
643    >,
644}
645
646impl<'a> Iterator for IndexConstraintAndUsageIter<'a> {
647    type Item = (IndexConstraint<'a>, IndexConstraintUsage<'a>);
648
649    #[inline]
650    fn next(&mut self) -> Option<(IndexConstraint<'a>, IndexConstraintUsage<'a>)> {
651        self.iter
652            .next()
653            .map(|raw| (IndexConstraint(raw.0), IndexConstraintUsage(raw.1)))
654    }
655
656    #[inline]
657    fn size_hint(&self) -> (usize, Option<usize>) {
658        self.iter.size_hint()
659    }
660}
661
662/// `feature = "vtab"`
663pub struct IndexConstraintIter<'a> {
664    iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
665}
666
667impl<'a> Iterator for IndexConstraintIter<'a> {
668    type Item = IndexConstraint<'a>;
669
670    #[inline]
671    fn next(&mut self) -> Option<IndexConstraint<'a>> {
672        self.iter.next().map(IndexConstraint)
673    }
674
675    #[inline]
676    fn size_hint(&self) -> (usize, Option<usize>) {
677        self.iter.size_hint()
678    }
679}
680
681/// WHERE clause constraint.
682pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
683
684impl IndexConstraint<'_> {
685    /// Column constrained.  -1 for ROWID
686    #[inline]
687    #[must_use]
688    pub fn column(&self) -> c_int {
689        self.0.iColumn
690    }
691
692    /// Constraint operator
693    #[inline]
694    #[must_use]
695    pub fn operator(&self) -> IndexConstraintOp {
696        IndexConstraintOp::from(self.0.op)
697    }
698
699    /// True if this constraint is usable
700    #[inline]
701    #[must_use]
702    pub fn is_usable(&self) -> bool {
703        self.0.usable != 0
704    }
705}
706
707/// Information about what parameters to pass to
708/// [`VTabCursor::filter`].
709pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
710
711impl IndexConstraintUsage<'_> {
712    /// if `argv_index` > 0, constraint is part of argv to
713    /// [`VTabCursor::filter`]
714    #[inline]
715    pub fn set_argv_index(&mut self, argv_index: c_int) {
716        self.0.argvIndex = argv_index;
717    }
718
719    /// if `omit`, do not code a test for this constraint
720    #[inline]
721    pub fn set_omit(&mut self, omit: bool) {
722        self.0.omit = omit as std::ffi::c_uchar;
723    }
724}
725
726/// `feature = "vtab"`
727pub struct OrderByIter<'a> {
728    iter: slice::Iter<'a, ffi::sqlite3_index_orderby>,
729}
730
731impl<'a> Iterator for OrderByIter<'a> {
732    type Item = OrderBy<'a>;
733
734    #[inline]
735    fn next(&mut self) -> Option<OrderBy<'a>> {
736        self.iter.next().map(OrderBy)
737    }
738
739    #[inline]
740    fn size_hint(&self) -> (usize, Option<usize>) {
741        self.iter.size_hint()
742    }
743}
744
745/// A column of the ORDER BY clause.
746pub struct OrderBy<'a>(&'a ffi::sqlite3_index_orderby);
747
748impl OrderBy<'_> {
749    /// Column number
750    #[inline]
751    #[must_use]
752    pub fn column(&self) -> c_int {
753        self.0.iColumn
754    }
755
756    /// True for DESC.  False for ASC.
757    #[inline]
758    #[must_use]
759    pub fn is_order_by_desc(&self) -> bool {
760        self.0.desc != 0
761    }
762}
763
764/// Virtual table cursor trait.
765///
766/// # Safety
767///
768/// Implementations must be like:
769/// ```rust,ignore
770/// #[repr(C)]
771/// struct MyTabCursor {
772///    /// Base class. Must be first
773///    base: rusqlite::vtab::sqlite3_vtab_cursor,
774///    /* Virtual table implementations will typically add additional fields */
775/// }
776/// ```
777///
778/// (See [SQLite doc](https://sqlite.org/c3ref/vtab_cursor.html))
779pub unsafe trait VTabCursor: Sized {
780    /// Begin a search of a virtual table.
781    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xfilter_method))
782    fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Filters<'_>) -> Result<()>;
783    /// Advance cursor to the next row of a result set initiated by
784    /// [`filter`](VTabCursor::filter). (See [SQLite doc](https://sqlite.org/vtab.html#the_xnext_method))
785    fn next(&mut self) -> Result<()>;
786    /// Must return `false` if the cursor currently points to a valid row of
787    /// data, or `true` otherwise.
788    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xeof_method))
789    fn eof(&self) -> bool;
790    /// Find the value for the `i`-th column of the current row.
791    /// `i` is zero-based so the first column is numbered 0.
792    /// May return its result back to SQLite using one of the specified `ctx`.
793    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcolumn_method))
794    fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
795    /// Return the rowid of row that the cursor is currently pointing at.
796    /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xrowid_method))
797    fn rowid(&self) -> Result<i64>;
798}
799
800/// Context is used by [`VTabCursor::column`] to specify the
801/// cell value.
802pub struct Context(*mut ffi::sqlite3_context);
803
804impl Context {
805    /// Set current cell value
806    #[inline]
807    pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
808        let t = value.to_sql()?;
809        unsafe { set_result(self.0, &[], &t) };
810        Ok(())
811    }
812
813    /// Determine if column access is for UPDATE
814    #[inline]
815    #[must_use]
816    pub fn no_change(&self) -> bool {
817        unsafe { ffi::sqlite3_vtab_nochange(self.0) != 0 }
818    }
819
820    /// Get the db connection handle via [sqlite3_context_db_handle](https://www.sqlite.org/c3ref/context_db_handle.html)
821    ///
822    /// # Safety
823    ///
824    /// This function is unsafe because improper use may impact the Connection.
825    pub unsafe fn get_connection(&self) -> Result<ConnectionRef<'_>> {
826        let handle = ffi::sqlite3_context_db_handle(self.0);
827        Ok(ConnectionRef {
828            conn: Connection::from_handle(handle)?,
829            phantom: PhantomData,
830        })
831    }
832}
833
834/// A reference to a connection handle with a lifetime bound to context.
835pub struct ConnectionRef<'ctx> {
836    // comes from Connection::from_handle(sqlite3_context_db_handle(...))
837    // and is non-owning
838    conn: Connection,
839    phantom: PhantomData<&'ctx Context>,
840}
841
842impl Deref for ConnectionRef<'_> {
843    type Target = Connection;
844
845    #[inline]
846    fn deref(&self) -> &Connection {
847        &self.conn
848    }
849}
850
851/// Wrapper to [`VTabCursor::filter`] arguments, the values
852/// requested by [`VTab::best_index`].
853pub struct Filters<'a> {
854    values: Values<'a>,
855}
856impl<'a> Deref for Filters<'a> {
857    type Target = Values<'a>;
858
859    fn deref(&self) -> &Self::Target {
860        &self.values
861    }
862}
863#[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
864impl<'a> Filters<'a> {
865    /// Find all elements on the right-hand side of an IN constraint
866    pub fn in_values(&self, idx: usize) -> Result<InValues<'_>> {
867        let list = self.args[idx];
868        Ok(InValues {
869            list,
870            phantom: PhantomData,
871            first: true,
872        })
873    }
874}
875
876/// IN values
877#[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
878pub struct InValues<'a> {
879    list: *mut ffi::sqlite3_value,
880    phantom: PhantomData<Filters<'a>>,
881    first: bool,
882}
883#[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
884impl<'a> fallible_iterator::FallibleIterator for InValues<'a> {
885    type Error = Error;
886    type Item = ValueRef<'a>;
887
888    fn next(&mut self) -> Result<Option<Self::Item>> {
889        let mut val: *mut ffi::sqlite3_value = ptr::null_mut();
890        let rc = unsafe {
891            if self.first {
892                self.first = false;
893                ffi::sqlite3_vtab_in_first(self.list, &mut val)
894            } else {
895                ffi::sqlite3_vtab_in_next(self.list, &mut val)
896            }
897        };
898        match rc {
899            ffi::SQLITE_OK => Ok(Some(unsafe { ValueRef::from_value(val) })),
900            ffi::SQLITE_DONE => Ok(None),
901            _ => Err(error_from_sqlite_code(rc, None)),
902        }
903    }
904}
905
906/// Wrapper to [ffi::sqlite3_value]s
907pub struct Values<'a> {
908    args: &'a [*mut ffi::sqlite3_value],
909}
910
911impl Values<'_> {
912    /// Returns the number of values.
913    #[inline]
914    #[must_use]
915    pub fn len(&self) -> usize {
916        self.args.len()
917    }
918
919    /// Returns `true` if there is no value.
920    #[inline]
921    #[must_use]
922    pub fn is_empty(&self) -> bool {
923        self.args.is_empty()
924    }
925
926    /// Returns value at `idx`
927    pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
928        let arg = self.args[idx];
929        let value = unsafe { ValueRef::from_value(arg) };
930        FromSql::column_result(value).map_err(|err| match err {
931            FromSqlError::InvalidType => Error::InvalidFilterParameterType(idx, value.data_type()),
932            FromSqlError::Other(err) => {
933                Error::FromSqlConversionFailure(idx, value.data_type(), err)
934            }
935            FromSqlError::InvalidBlobSize { .. } => {
936                Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
937            }
938            FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
939            FromSqlError::Utf8Error(err) => Error::Utf8Error(idx, err),
940        })
941    }
942
943    /// Return raw pointer at `idx`
944    /// # Safety
945    /// This function is unsafe because it uses raw pointer and cast
946    // `sqlite3_value_type` returns `SQLITE_NULL` for pointer.
947    // So it seems not possible to enhance `ValueRef::from_value`.
948    #[cfg(feature = "pointer")]
949    pub unsafe fn get_pointer<'a, T: 'static>(
950        &self,
951        idx: usize,
952        ptr_type: &'static CStr,
953    ) -> Option<&'a T> {
954        let arg = self.args[idx];
955        debug_assert_eq!(unsafe { ffi::sqlite3_value_type(arg) }, ffi::SQLITE_NULL);
956        unsafe {
957            ffi::sqlite3_value_pointer(arg, ptr_type.as_ptr())
958                .cast::<T>()
959                .as_ref()
960        }
961    }
962
963    /// Turns `Values` into an iterator.
964    #[inline]
965    #[must_use]
966    pub fn iter(&self) -> ValueIter<'_> {
967        ValueIter {
968            iter: self.args.iter(),
969        }
970    }
971}
972
973impl<'a> IntoIterator for &'a Values<'a> {
974    type IntoIter = ValueIter<'a>;
975    type Item = ValueRef<'a>;
976
977    #[inline]
978    fn into_iter(self) -> ValueIter<'a> {
979        self.iter()
980    }
981}
982
983/// [`Values`] iterator.
984pub struct ValueIter<'a> {
985    iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
986}
987
988impl<'a> Iterator for ValueIter<'a> {
989    type Item = ValueRef<'a>;
990
991    #[inline]
992    fn next(&mut self) -> Option<ValueRef<'a>> {
993        self.iter
994            .next()
995            .map(|&raw| unsafe { ValueRef::from_value(raw) })
996    }
997
998    #[inline]
999    fn size_hint(&self) -> (usize, Option<usize>) {
1000        self.iter.size_hint()
1001    }
1002}
1003
1004/// Wrapper to [`UpdateVTab::insert`] arguments
1005pub struct Inserts<'a> {
1006    values: Values<'a>,
1007}
1008impl<'a> Deref for Inserts<'a> {
1009    type Target = Values<'a>;
1010
1011    fn deref(&self) -> &Self::Target {
1012        &self.values
1013    }
1014}
1015impl Inserts<'_> {
1016    /// Determine the virtual table conflict policy
1017    ///
1018    /// # Safety
1019    /// This function is unsafe because it uses raw pointer
1020    #[must_use]
1021    pub unsafe fn on_conflict(&self, db: *mut ffi::sqlite3) -> ConflictMode {
1022        ConflictMode::from(unsafe { ffi::sqlite3_vtab_on_conflict(db) })
1023    }
1024}
1025
1026/// Wrapper to [`UpdateVTab::update`] arguments
1027pub struct Updates<'a> {
1028    values: Values<'a>,
1029}
1030impl<'a> Deref for Updates<'a> {
1031    type Target = Values<'a>;
1032
1033    fn deref(&self) -> &Self::Target {
1034        &self.values
1035    }
1036}
1037impl Updates<'_> {
1038    /// Returns `true` if and only
1039    /// - if the column corresponding to `idx` is unchanged by the UPDATE operation that the [`UpdateVTab::update`] method call was invoked to implement
1040    /// - and if and the prior [`VTabCursor::column`] method call that was invoked to extract the value for that column returned without setting a result.
1041    #[inline]
1042    #[must_use]
1043    pub fn no_change(&self, idx: usize) -> bool {
1044        unsafe { ffi::sqlite3_value_nochange(self.values.args[idx]) != 0 }
1045    }
1046
1047    /// Determine the virtual table conflict policy
1048    ///
1049    /// # Safety
1050    /// This function is unsafe because it uses raw pointer
1051    #[must_use]
1052    pub unsafe fn on_conflict(&self, db: *mut ffi::sqlite3) -> ConflictMode {
1053        ConflictMode::from(unsafe { ffi::sqlite3_vtab_on_conflict(db) })
1054    }
1055}
1056
1057/// Conflict resolution modes
1058#[non_exhaustive]
1059#[derive(Debug, Eq, PartialEq)]
1060pub enum ConflictMode {
1061    /// SQLITE_ROLLBACK
1062    Rollback,
1063    /// SQLITE_IGNORE
1064    Ignore,
1065    /// SQLITE_FAIL
1066    Fail,
1067    /// SQLITE_ABORT
1068    Abort,
1069    /// SQLITE_REPLACE
1070    Replace,
1071}
1072impl From<c_int> for ConflictMode {
1073    fn from(value: c_int) -> Self {
1074        match value {
1075            ffi::SQLITE_ROLLBACK => ConflictMode::Rollback,
1076            ffi::SQLITE_IGNORE => ConflictMode::Ignore,
1077            ffi::SQLITE_FAIL => ConflictMode::Fail,
1078            ffi::SQLITE_ABORT => ConflictMode::Abort,
1079            ffi::SQLITE_REPLACE => ConflictMode::Replace,
1080            _ => unreachable!("sqlite3_vtab_on_conflict returned invalid value"),
1081        }
1082    }
1083}
1084
1085impl Connection {
1086    /// Register a virtual table implementation.
1087    ///
1088    /// Step 3 of [Creating New Virtual Table
1089    /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
1090    #[inline]
1091    pub fn create_module<'vtab, T: VTab<'vtab>, M: Name>(
1092        &self,
1093        module_name: M,
1094        module: &'static Module<'vtab, T>,
1095        aux: Option<T::Aux>,
1096    ) -> Result<()> {
1097        self.db.borrow_mut().create_module(module_name, module, aux)
1098    }
1099}
1100
1101impl InnerConnection {
1102    fn create_module<'vtab, T: VTab<'vtab>, M: Name>(
1103        &mut self,
1104        module_name: M,
1105        module: &'static Module<'vtab, T>,
1106        aux: Option<T::Aux>,
1107    ) -> Result<()> {
1108        use crate::version;
1109        if version::version_number() < 3_009_000 && module.base.xCreate.is_none() {
1110            return Err(Error::ModuleError(format!(
1111                "Eponymous-only virtual table not supported by SQLite version {}",
1112                version::version()
1113            )));
1114        }
1115        let c_name = module_name.as_cstr()?;
1116        let r = match aux {
1117            Some(aux) => {
1118                let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
1119                unsafe {
1120                    ffi::sqlite3_create_module_v2(
1121                        self.db(),
1122                        c_name.as_ptr(),
1123                        &module.base,
1124                        boxed_aux.cast::<c_void>(),
1125                        Some(free_boxed_value::<T::Aux>),
1126                    )
1127                }
1128            }
1129            None => unsafe {
1130                ffi::sqlite3_create_module_v2(
1131                    self.db(),
1132                    c_name.as_ptr(),
1133                    &module.base,
1134                    ptr::null_mut(),
1135                    None,
1136                )
1137            },
1138        };
1139        self.decode_result(r)
1140    }
1141}
1142
1143/// Escape double-quote (`"`) character occurrences by
1144/// doubling them (`""`).
1145#[must_use]
1146pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
1147    if identifier.contains('"') {
1148        // escape quote by doubling them
1149        Owned(identifier.replace('"', "\"\""))
1150    } else {
1151        Borrowed(identifier)
1152    }
1153}
1154/// Dequote string
1155#[must_use]
1156pub fn dequote(mut s: &str) -> Cow<'_, str> {
1157    let mut chars = s.chars();
1158    let (Some(first), Some(last)) = (chars.next(), chars.next_back()) else {
1159        return Cow::Borrowed(s);
1160    };
1161    if (first == '"' || first == '\'' || first == '`' || first == '[')
1162        && (last == first || first == '[' && last == ']')
1163    {
1164        s = chars.as_str();
1165        if first != '[' && s.contains(first) {
1166            // handle inner escaped quote(s)
1167            let mut owned = String::with_capacity(s.len());
1168            let mut escaped = false;
1169            for c in s.chars() {
1170                if c == first {
1171                    if !escaped {
1172                        escaped = true;
1173                        continue;
1174                    } else {
1175                        escaped = false;
1176                    }
1177                } else if escaped {
1178                    // not properly escaped
1179                    return Cow::Borrowed(s);
1180                }
1181                owned.push(c);
1182            }
1183            if !escaped {
1184                return Cow::Owned(owned);
1185            }
1186        }
1187    }
1188    Cow::Borrowed(s)
1189}
1190/// The boolean can be one of:
1191/// ```text
1192/// 1 yes true on
1193/// 0 no false off
1194/// ```
1195#[must_use]
1196pub fn parse_boolean(s: &str) -> Option<bool> {
1197    if s.eq_ignore_ascii_case("yes")
1198        || s.eq_ignore_ascii_case("on")
1199        || s.eq_ignore_ascii_case("true")
1200        || s.eq("1")
1201    {
1202        Some(true)
1203    } else if s.eq_ignore_ascii_case("no")
1204        || s.eq_ignore_ascii_case("off")
1205        || s.eq_ignore_ascii_case("false")
1206        || s.eq("0")
1207    {
1208        Some(false)
1209    } else {
1210        None
1211    }
1212}
1213
1214/// `<param_name>=['"`[]?<param_value>['"`]]?` => `(<param_name>, <param_value>)`
1215pub fn parameter(c_slice: &[u8]) -> Result<(&str, Cow<'_, str>)> {
1216    let arg = std::str::from_utf8(c_slice)?.trim();
1217    match arg.split_once('=') {
1218        Some((key, value)) => {
1219            let param = key.trim();
1220            let value = dequote(value.trim());
1221            Ok((param, value))
1222        }
1223        _ => Err(Error::ModuleError(format!("illegal argument: '{arg}'"))),
1224    }
1225}
1226
1227unsafe extern "C" fn rust_create<'vtab, T>(
1228    db: *mut ffi::sqlite3,
1229    aux: *mut c_void,
1230    argc: c_int,
1231    argv: *const *const c_char,
1232    pp_vtab: *mut *mut sqlite3_vtab,
1233    err_msg: *mut *mut c_char,
1234) -> c_int
1235where
1236    T: CreateVTab<'vtab>,
1237{
1238    let mut conn = VTabConnection(db);
1239    let aux = aux.cast::<T::Aux>();
1240    let args = slice::from_raw_parts(argv, argc as usize);
1241    let vec = args
1242        .iter()
1243        .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
1244        .collect::<Vec<_>>();
1245    match T::create(&mut conn, aux.as_ref(), vec[0], vec[1], vec[2], &vec[3..]) {
1246        Ok((sql, vtab)) => {
1247            let rc = ffi::sqlite3_declare_vtab(db, sql.as_ptr());
1248            if rc == ffi::SQLITE_OK {
1249                let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1250                *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
1251                ffi::SQLITE_OK
1252            } else {
1253                let err = error_from_sqlite_code(rc, None);
1254                to_sqlite_error(&err, err_msg)
1255            }
1256        }
1257        Err(err) => to_sqlite_error(&err, err_msg),
1258    }
1259}
1260
1261unsafe extern "C" fn rust_connect<'vtab, T>(
1262    db: *mut ffi::sqlite3,
1263    aux: *mut c_void,
1264    argc: c_int,
1265    argv: *const *const c_char,
1266    pp_vtab: *mut *mut sqlite3_vtab,
1267    err_msg: *mut *mut c_char,
1268) -> c_int
1269where
1270    T: VTab<'vtab>,
1271{
1272    let mut conn = VTabConnection(db);
1273    let aux = aux.cast::<T::Aux>();
1274    let args = slice::from_raw_parts(argv, argc as usize);
1275    let vec = args
1276        .iter()
1277        .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
1278        .collect::<Vec<_>>();
1279    match T::connect(&mut conn, aux.as_ref(), vec[0], vec[1], vec[2], &vec[3..]) {
1280        Ok((sql, vtab)) => {
1281            let rc = ffi::sqlite3_declare_vtab(db, sql.as_ptr());
1282            if rc == ffi::SQLITE_OK {
1283                let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1284                *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
1285                ffi::SQLITE_OK
1286            } else {
1287                let err = error_from_sqlite_code(rc, None);
1288                to_sqlite_error(&err, err_msg)
1289            }
1290        }
1291        Err(err) => to_sqlite_error(&err, err_msg),
1292    }
1293}
1294
1295unsafe extern "C" fn rust_best_index<'vtab, T>(
1296    vtab: *mut sqlite3_vtab,
1297    info: *mut ffi::sqlite3_index_info,
1298) -> c_int
1299where
1300    T: VTab<'vtab>,
1301{
1302    let vt = vtab.cast::<T>();
1303    let mut idx_info = IndexInfo(info);
1304    match (*vt).best_index(&mut idx_info) {
1305        Ok(true) => ffi::SQLITE_OK,
1306        Ok(false) => ffi::SQLITE_CONSTRAINT,
1307        err => vtab_error(vtab, err),
1308    }
1309}
1310
1311unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1312where
1313    T: VTab<'vtab>,
1314{
1315    if vtab.is_null() {
1316        return ffi::SQLITE_OK;
1317    }
1318    let vtab = vtab.cast::<T>();
1319    drop(Box::from_raw(vtab));
1320    ffi::SQLITE_OK
1321}
1322
1323unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1324where
1325    T: CreateVTab<'vtab>,
1326{
1327    if vtab.is_null() {
1328        return ffi::SQLITE_OK;
1329    }
1330    let vt = vtab.cast::<T>();
1331    match (*vt).destroy() {
1332        Ok(_) => {
1333            drop(Box::from_raw(vt));
1334            ffi::SQLITE_OK
1335        }
1336        err => vtab_error(vtab, err),
1337    }
1338}
1339
1340unsafe extern "C" fn rust_open<'vtab, T>(
1341    vtab: *mut sqlite3_vtab,
1342    pp_cursor: *mut *mut sqlite3_vtab_cursor,
1343) -> c_int
1344where
1345    T: VTab<'vtab> + 'vtab,
1346{
1347    let vt = vtab.cast::<T>();
1348    match (*vt).open() {
1349        Ok(cursor) => {
1350            let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
1351            *pp_cursor = boxed_cursor.cast::<sqlite3_vtab_cursor>();
1352            ffi::SQLITE_OK
1353        }
1354        err => vtab_error(vtab, err),
1355    }
1356}
1357
1358unsafe extern "C" fn rust_close<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1359where
1360    C: VTabCursor,
1361{
1362    let cr = cursor.cast::<C>();
1363    drop(Box::from_raw(cr));
1364    ffi::SQLITE_OK
1365}
1366
1367unsafe extern "C" fn rust_filter<C>(
1368    cursor: *mut sqlite3_vtab_cursor,
1369    idx_num: c_int,
1370    idx_str: *const c_char,
1371    argc: c_int,
1372    argv: *mut *mut ffi::sqlite3_value,
1373) -> c_int
1374where
1375    C: VTabCursor,
1376{
1377    use std::str;
1378    let idx_name = if idx_str.is_null() {
1379        None
1380    } else {
1381        let c_slice = CStr::from_ptr(idx_str).to_bytes();
1382        Some(str::from_utf8_unchecked(c_slice))
1383    };
1384    let args = slice::from_raw_parts_mut(argv, argc as usize);
1385    let values = Values { args };
1386    let cr = cursor as *mut C;
1387    cursor_error(cursor, (*cr).filter(idx_num, idx_name, &Filters { values }))
1388}
1389
1390unsafe extern "C" fn rust_next<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1391where
1392    C: VTabCursor,
1393{
1394    let cr = cursor as *mut C;
1395    cursor_error(cursor, (*cr).next())
1396}
1397
1398unsafe extern "C" fn rust_eof<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1399where
1400    C: VTabCursor,
1401{
1402    let cr = cursor.cast::<C>();
1403    (*cr).eof() as c_int
1404}
1405
1406unsafe extern "C" fn rust_column<C>(
1407    cursor: *mut sqlite3_vtab_cursor,
1408    ctx: *mut ffi::sqlite3_context,
1409    i: c_int,
1410) -> c_int
1411where
1412    C: VTabCursor,
1413{
1414    let cr = cursor.cast::<C>();
1415    let mut ctxt = Context(ctx);
1416    result_error(ctx, (*cr).column(&mut ctxt, i))
1417}
1418
1419unsafe extern "C" fn rust_rowid<C>(
1420    cursor: *mut sqlite3_vtab_cursor,
1421    p_rowid: *mut ffi::sqlite3_int64,
1422) -> c_int
1423where
1424    C: VTabCursor,
1425{
1426    let cr = cursor.cast::<C>();
1427    match (*cr).rowid() {
1428        Ok(rowid) => {
1429            *p_rowid = rowid;
1430            ffi::SQLITE_OK
1431        }
1432        err => cursor_error(cursor, err),
1433    }
1434}
1435
1436unsafe extern "C" fn rust_update<'vtab, T>(
1437    vtab: *mut sqlite3_vtab,
1438    argc: c_int,
1439    argv: *mut *mut ffi::sqlite3_value,
1440    p_rowid: *mut ffi::sqlite3_int64,
1441) -> c_int
1442where
1443    T: UpdateVTab<'vtab> + 'vtab,
1444{
1445    assert!(argc >= 1);
1446    let args = slice::from_raw_parts_mut(argv, argc as usize);
1447    let vt = vtab.cast::<T>();
1448    let r = if args.len() == 1 {
1449        (*vt).delete(ValueRef::from_value(args[0]))
1450    } else if ffi::sqlite3_value_type(args[0]) == ffi::SQLITE_NULL {
1451        // TODO Make the distinction between argv[1] == NULL and argv[1] != NULL ?
1452        let values = Values { args };
1453        match (*vt).insert(&Inserts { values }) {
1454            Ok(rowid) => {
1455                *p_rowid = rowid;
1456                Ok(())
1457            }
1458            Err(e) => Err(e),
1459        }
1460    } else {
1461        let values = Values { args };
1462        (*vt).update(&Updates { values })
1463    };
1464    vtab_error(vtab, r)
1465}
1466
1467unsafe extern "C" fn rust_begin<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1468where
1469    T: TransactionVTab<'vtab>,
1470{
1471    let vt = vtab.cast::<T>();
1472    vtab_error(vtab, (*vt).begin())
1473}
1474unsafe extern "C" fn rust_sync<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1475where
1476    T: TransactionVTab<'vtab>,
1477{
1478    let vt = vtab.cast::<T>();
1479    vtab_error(vtab, (*vt).sync())
1480}
1481unsafe extern "C" fn rust_commit<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1482where
1483    T: TransactionVTab<'vtab>,
1484{
1485    let vt = vtab.cast::<T>();
1486    vtab_error(vtab, (*vt).commit())
1487}
1488unsafe extern "C" fn rust_rollback<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1489where
1490    T: TransactionVTab<'vtab>,
1491{
1492    let vt = vtab.cast::<T>();
1493    vtab_error(vtab, (*vt).rollback())
1494}
1495
1496/// Virtual table cursors can set an error message by assigning a string to
1497/// `zErrMsg`.
1498unsafe fn cursor_error<T>(cursor: *mut sqlite3_vtab_cursor, result: Result<T>) -> c_int {
1499    vtab_error((*cursor).pVtab, result)
1500}
1501
1502/// Virtual tables can set an error message by assigning a string to
1503/// `zErrMsg`.
1504unsafe fn vtab_error<T>(vtab: *mut sqlite3_vtab, result: Result<T>) -> c_int {
1505    match result {
1506        Ok(_) => ffi::SQLITE_OK,
1507        Err(Error::SqliteFailure(err, s)) => {
1508            if let Some(err_msg) = s {
1509                set_err_msg(vtab, &err_msg);
1510            }
1511            err.extended_code
1512        }
1513        Err(err) => {
1514            set_err_msg(vtab, &err.to_string());
1515            ffi::SQLITE_ERROR
1516        }
1517    }
1518}
1519
1520/// Virtual tables methods can set an error message by assigning a string to
1521/// `zErrMsg`.
1522#[cold]
1523unsafe fn set_err_msg(vtab: *mut sqlite3_vtab, err_msg: &str) {
1524    if !(*vtab).zErrMsg.is_null() {
1525        ffi::sqlite3_free((*vtab).zErrMsg.cast::<c_void>());
1526    }
1527    (*vtab).zErrMsg = alloc(err_msg);
1528}
1529
1530/// To raise an error, the `column` method should use this method to set the
1531/// error message and return the error code.
1532#[cold]
1533unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
1534    match result {
1535        Ok(_) => ffi::SQLITE_OK,
1536        Err(Error::SqliteFailure(err, s)) => {
1537            match err.extended_code {
1538                ffi::SQLITE_TOOBIG => {
1539                    ffi::sqlite3_result_error_toobig(ctx);
1540                }
1541                ffi::SQLITE_NOMEM => {
1542                    ffi::sqlite3_result_error_nomem(ctx);
1543                }
1544                code => {
1545                    ffi::sqlite3_result_error_code(ctx, code);
1546                    if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
1547                        ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1548                    }
1549                }
1550            }
1551            err.extended_code
1552        }
1553        Err(err) => {
1554            ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_ERROR);
1555            if let Ok(cstr) = str_to_cstring(&err.to_string()) {
1556                ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1557            }
1558            ffi::SQLITE_ERROR
1559        }
1560    }
1561}
1562
1563#[cfg(feature = "array")]
1564pub mod array;
1565#[cfg(feature = "csvtab")]
1566pub mod csvtab;
1567#[cfg(feature = "series")]
1568pub mod series; // SQLite >= 3.9.0
1569#[cfg(all(test, feature = "modern_sqlite", not(miri)))]
1570mod vtablog;
1571
1572#[cfg(test)]
1573mod test {
1574    use std::borrow::Cow;
1575
1576    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1577    use wasm_bindgen_test::wasm_bindgen_test as test;
1578
1579    #[test]
1580    fn test_dequote() {
1581        assert_eq!("", super::dequote(""));
1582        assert_eq!("'", super::dequote("'"));
1583        assert_eq!("\"", super::dequote("\""));
1584
1585        assert_eq!("'\"", super::dequote("'\""));
1586
1587        assert_eq!("", super::dequote("''"));
1588        assert_eq!("", super::dequote("\"\""));
1589        assert_eq!("", super::dequote("``"));
1590        assert_eq!("", super::dequote("[]"));
1591
1592        assert_eq!("x", super::dequote("'x'"));
1593        assert_eq!("x", super::dequote("\"x\""));
1594        assert_eq!("x", super::dequote("x"));
1595        assert_eq!("x", super::dequote("`x`"));
1596        assert_eq!("x", super::dequote("[x]"));
1597
1598        assert_eq!("x'", super::dequote("'x'''"));
1599        assert_eq!("x`", super::dequote("`x```"));
1600
1601        assert_eq!("x'", super::dequote("'x''"));
1602        assert_eq!("x`", super::dequote("`x``"));
1603    }
1604    #[test]
1605    fn test_parse_boolean() {
1606        assert_eq!(None, super::parse_boolean(""));
1607        assert_eq!(Some(true), super::parse_boolean("1"));
1608        assert_eq!(Some(true), super::parse_boolean("yes"));
1609        assert_eq!(Some(true), super::parse_boolean("on"));
1610        assert_eq!(Some(true), super::parse_boolean("true"));
1611        assert_eq!(Some(false), super::parse_boolean("0"));
1612        assert_eq!(Some(false), super::parse_boolean("no"));
1613        assert_eq!(Some(false), super::parse_boolean("off"));
1614        assert_eq!(Some(false), super::parse_boolean("false"));
1615    }
1616    #[test]
1617    fn test_parse_parameters() {
1618        assert_eq!(
1619            Ok(("key", Cow::Borrowed("value"))),
1620            super::parameter(b"key='value'")
1621        );
1622        assert_eq!(
1623            Ok(("key", Cow::Borrowed("foo=bar"))),
1624            super::parameter(b"key='foo=bar'")
1625        );
1626    }
1627}