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