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