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