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