rusqlite/vtab/
mod.rs

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