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