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