1 //! `feature = "vtab"` Create virtual tables.
2 //!
3 //! Follow these steps to create your own virtual table:
4 //! 1. Write implemenation of `VTab` and `VTabCursor` traits.
5 //! 2. Create an instance of the `Module` structure specialized for `VTab` impl.
6 //! 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 /// `feature = "vtab"` Virtual table module
61 ///
62 /// (See [SQLite doc](https://sqlite.org/c3ref/module.html))
63 #[repr(transparent)]
64 pub struct Module<'vtab, T: VTab<'vtab>> {
65 base: ffi::sqlite3_module,
66 phantom: PhantomData<&'vtab T>,
67 }
68
69 unsafe impl<'vtab, T: VTab<'vtab>> Send for Module<'vtab, T> {}
70 unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {}
71
72 union ModuleZeroHack {
73 bytes: [u8; std::mem::size_of::<ffi::sqlite3_module>()],
74 module: ffi::sqlite3_module,
75 }
76
77 // Used as a trailing initializer for sqlite3_module -- this way we avoid having
78 // the build fail if buildtime_bindgen is on. This is safe, as bindgen-generated
79 // structs are allowed to be zeroed.
80 const ZERO_MODULE: ffi::sqlite3_module = unsafe {
81 ModuleZeroHack {
82 bytes: [0u8; std::mem::size_of::<ffi::sqlite3_module>()],
83 }
84 .module
85 };
86
87 /// `feature = "vtab"` Create a read-only virtual table implementation.
88 ///
89 /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T>90 pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> {
91 // The xConnect and xCreate methods do the same thing, but they must be
92 // different so that the virtual table is not an eponymous virtual table.
93 &Module {
94 base: ffi::sqlite3_module {
95 // We don't use V3
96 iVersion: 2, // We don't use V2 or V3 features in read_only_module types
97 xCreate: Some(rust_create::<T>),
98 xConnect: Some(rust_connect::<T>),
99 xBestIndex: Some(rust_best_index::<T>),
100 xDisconnect: Some(rust_disconnect::<T>),
101 xDestroy: Some(rust_destroy::<T>),
102 xOpen: Some(rust_open::<T>),
103 xClose: Some(rust_close::<T::Cursor>),
104 xFilter: Some(rust_filter::<T::Cursor>),
105 xNext: Some(rust_next::<T::Cursor>),
106 xEof: Some(rust_eof::<T::Cursor>),
107 xColumn: Some(rust_column::<T::Cursor>),
108 xRowid: Some(rust_rowid::<T::Cursor>),
109 xUpdate: None,
110 xBegin: None,
111 xSync: None,
112 xCommit: None,
113 xRollback: None,
114 xFindFunction: None,
115 xRename: None,
116 xSavepoint: None,
117 xRelease: None,
118 xRollbackTo: None,
119 ..ZERO_MODULE
120 },
121 phantom: PhantomData::<&'vtab T>,
122 }
123 }
124
125 /// `feature = "vtab"` Create an eponymous only virtual table implementation.
126 ///
127 /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T>128 pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> {
129 // A virtual table is eponymous if its xCreate method is the exact same function
130 // as the xConnect method For eponymous-only virtual tables, the xCreate
131 // method is NULL
132 &Module {
133 base: ffi::sqlite3_module {
134 // We don't use V3
135 iVersion: 2,
136 xCreate: None,
137 xConnect: Some(rust_connect::<T>),
138 xBestIndex: Some(rust_best_index::<T>),
139 xDisconnect: Some(rust_disconnect::<T>),
140 xDestroy: None,
141 xOpen: Some(rust_open::<T>),
142 xClose: Some(rust_close::<T::Cursor>),
143 xFilter: Some(rust_filter::<T::Cursor>),
144 xNext: Some(rust_next::<T::Cursor>),
145 xEof: Some(rust_eof::<T::Cursor>),
146 xColumn: Some(rust_column::<T::Cursor>),
147 xRowid: Some(rust_rowid::<T::Cursor>),
148 xUpdate: None,
149 xBegin: None,
150 xSync: None,
151 xCommit: None,
152 xRollback: None,
153 xFindFunction: None,
154 xRename: None,
155 xSavepoint: None,
156 xRelease: None,
157 xRollbackTo: None,
158 ..ZERO_MODULE
159 },
160 phantom: PhantomData::<&'vtab T>,
161 }
162 }
163
164 /// `feature = "vtab"`
165 pub struct VTabConnection(*mut ffi::sqlite3);
166
167 impl VTabConnection {
168 // TODO sqlite3_vtab_config (http://sqlite.org/c3ref/vtab_config.html)
169
170 // TODO sqlite3_vtab_on_conflict (http://sqlite.org/c3ref/vtab_on_conflict.html)
171
172 /// Get access to the underlying SQLite database connection handle.
173 ///
174 /// # Warning
175 ///
176 /// You should not need to use this function. If you do need to, please
177 /// [open an issue on the rusqlite repository](https://github.com/rusqlite/rusqlite/issues) and describe
178 /// your use case.
179 ///
180 /// # Safety
181 ///
182 /// This function is unsafe because it gives you raw access
183 /// to the SQLite connection, and what you do with it could impact the
184 /// safety of this `Connection`.
handle(&mut self) -> *mut ffi::sqlite3185 pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
186 self.0
187 }
188 }
189
190 /// `feature = "vtab"` Virtual table instance trait.
191 ///
192 /// # Safety
193 ///
194 /// The first item in a struct implementing VTab must be
195 /// `rusqlite::sqlite3_vtab`, and the struct must be `#[repr(C)]`.
196 ///
197 /// ```rust,ignore
198 /// #[repr(C)]
199 /// struct MyTab {
200 /// /// Base class. Must be first
201 /// base: ffi::sqlite3_vtab,
202 /// /* Virtual table implementations will typically add additional fields */
203 /// }
204 /// ```
205 ///
206 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
207 pub unsafe trait VTab<'vtab>: Sized {
208 /// Client data passed to `Connection::create_module`.
209 type Aux;
210 /// Specific cursor implementation
211 type Cursor: VTabCursor;
212
213 /// Establish a new connection to an existing virtual table.
214 ///
215 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xconnect_method))
connect( db: &mut VTabConnection, aux: Option<&Self::Aux>, args: &[&[u8]], ) -> Result<(String, Self)>216 fn connect(
217 db: &mut VTabConnection,
218 aux: Option<&Self::Aux>,
219 args: &[&[u8]],
220 ) -> Result<(String, Self)>;
221
222 /// Determine the best way to access the virtual table.
223 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xbestindex_method))
best_index(&self, info: &mut IndexInfo) -> Result<()>224 fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
225
226 /// Create a new cursor used for accessing a virtual table.
227 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xopen_method))
open(&'vtab self) -> Result<Self::Cursor>228 fn open(&'vtab self) -> Result<Self::Cursor>;
229 }
230
231 /// `feature = "vtab"` Non-eponymous virtual table instance trait.
232 ///
233 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html))
234 pub trait CreateVTab<'vtab>: VTab<'vtab> {
235 /// Create a new instance of a virtual table in response to a CREATE VIRTUAL
236 /// TABLE statement. The `db` parameter is a pointer to the SQLite
237 /// database connection that is executing the CREATE VIRTUAL TABLE
238 /// statement.
239 ///
240 /// Call `connect` by default.
241 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcreate_method))
create( db: &mut VTabConnection, aux: Option<&Self::Aux>, args: &[&[u8]], ) -> Result<(String, Self)>242 fn create(
243 db: &mut VTabConnection,
244 aux: Option<&Self::Aux>,
245 args: &[&[u8]],
246 ) -> Result<(String, Self)> {
247 Self::connect(db, aux, args)
248 }
249
250 /// Destroy the underlying table implementation. This method undoes the work
251 /// of `create`.
252 ///
253 /// Do nothing by default.
254 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xdestroy_method))
destroy(&self) -> Result<()>255 fn destroy(&self) -> Result<()> {
256 Ok(())
257 }
258 }
259
260 /// `feature = "vtab"` Index constraint operator.
261 /// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
262 #[derive(Debug, PartialEq)]
263 #[allow(non_snake_case, non_camel_case_types, missing_docs)]
264 #[non_exhaustive]
265 pub enum IndexConstraintOp {
266 SQLITE_INDEX_CONSTRAINT_EQ,
267 SQLITE_INDEX_CONSTRAINT_GT,
268 SQLITE_INDEX_CONSTRAINT_LE,
269 SQLITE_INDEX_CONSTRAINT_LT,
270 SQLITE_INDEX_CONSTRAINT_GE,
271 SQLITE_INDEX_CONSTRAINT_MATCH,
272 SQLITE_INDEX_CONSTRAINT_LIKE, // 3.10.0
273 SQLITE_INDEX_CONSTRAINT_GLOB, // 3.10.0
274 SQLITE_INDEX_CONSTRAINT_REGEXP, // 3.10.0
275 SQLITE_INDEX_CONSTRAINT_NE, // 3.21.0
276 SQLITE_INDEX_CONSTRAINT_ISNOT, // 3.21.0
277 SQLITE_INDEX_CONSTRAINT_ISNOTNULL, // 3.21.0
278 SQLITE_INDEX_CONSTRAINT_ISNULL, // 3.21.0
279 SQLITE_INDEX_CONSTRAINT_IS, // 3.21.0
280 SQLITE_INDEX_CONSTRAINT_FUNCTION(u8), // 3.25.0
281 }
282
283 impl From<u8> for IndexConstraintOp {
from(code: u8) -> IndexConstraintOp284 fn from(code: u8) -> IndexConstraintOp {
285 match code {
286 2 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ,
287 4 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GT,
288 8 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LE,
289 16 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LT,
290 32 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GE,
291 64 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_MATCH,
292 65 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIKE,
293 66 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GLOB,
294 67 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_REGEXP,
295 68 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_NE,
296 69 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOT,
297 70 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
298 71 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNULL,
299 72 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_IS,
300 v => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
301 }
302 }
303 }
304
305 /// `feature = "vtab"` Pass information into and receive the reply from the
306 /// `VTab.best_index` method.
307 ///
308 /// (See [SQLite doc](http://sqlite.org/c3ref/index_info.html))
309 pub struct IndexInfo(*mut ffi::sqlite3_index_info);
310
311 impl IndexInfo {
312 /// Record WHERE clause constraints.
constraints(&self) -> IndexConstraintIter<'_>313 pub fn constraints(&self) -> IndexConstraintIter<'_> {
314 let constraints =
315 unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
316 IndexConstraintIter {
317 iter: constraints.iter(),
318 }
319 }
320
321 /// Information about the ORDER BY clause.
order_bys(&self) -> OrderByIter<'_>322 pub fn order_bys(&self) -> OrderByIter<'_> {
323 let order_bys =
324 unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
325 OrderByIter {
326 iter: order_bys.iter(),
327 }
328 }
329
330 /// Number of terms in the ORDER BY clause
num_of_order_by(&self) -> usize331 pub fn num_of_order_by(&self) -> usize {
332 unsafe { (*self.0).nOrderBy as usize }
333 }
334
335 /// Information about what parameters to pass to `VTabCursor.filter`.
constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_>336 pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
337 let constraint_usages = unsafe {
338 slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
339 };
340 IndexConstraintUsage(&mut constraint_usages[constraint_idx])
341 }
342
343 /// Number used to identify the index
set_idx_num(&mut self, idx_num: c_int)344 pub fn set_idx_num(&mut self, idx_num: c_int) {
345 unsafe {
346 (*self.0).idxNum = idx_num;
347 }
348 }
349
350 /// True if output is already ordered
set_order_by_consumed(&mut self, order_by_consumed: bool)351 pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
352 unsafe {
353 (*self.0).orderByConsumed = if order_by_consumed { 1 } else { 0 };
354 }
355 }
356
357 /// Estimated cost of using this index
set_estimated_cost(&mut self, estimated_ost: f64)358 pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
359 unsafe {
360 (*self.0).estimatedCost = estimated_ost;
361 }
362 }
363
364 /// Estimated number of rows returned.
365 #[cfg(feature = "modern_sqlite")] // SQLite >= 3.8.2
set_estimated_rows(&mut self, estimated_rows: i64)366 pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
367 unsafe {
368 (*self.0).estimatedRows = estimated_rows;
369 }
370 }
371
372 // TODO idxFlags
373 // TODO colUsed
374
375 // TODO sqlite3_vtab_collation (http://sqlite.org/c3ref/vtab_collation.html)
376 }
377
378 /// `feature = "vtab"`
379 pub struct IndexConstraintIter<'a> {
380 iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
381 }
382
383 impl<'a> Iterator for IndexConstraintIter<'a> {
384 type Item = IndexConstraint<'a>;
385
next(&mut self) -> Option<IndexConstraint<'a>>386 fn next(&mut self) -> Option<IndexConstraint<'a>> {
387 self.iter.next().map(|raw| IndexConstraint(raw))
388 }
389
size_hint(&self) -> (usize, Option<usize>)390 fn size_hint(&self) -> (usize, Option<usize>) {
391 self.iter.size_hint()
392 }
393 }
394
395 /// `feature = "vtab"` WHERE clause constraint.
396 pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
397
398 impl IndexConstraint<'_> {
399 /// Column constrained. -1 for ROWID
column(&self) -> c_int400 pub fn column(&self) -> c_int {
401 self.0.iColumn
402 }
403
404 /// Constraint operator
operator(&self) -> IndexConstraintOp405 pub fn operator(&self) -> IndexConstraintOp {
406 IndexConstraintOp::from(self.0.op)
407 }
408
409 /// True if this constraint is usable
is_usable(&self) -> bool410 pub fn is_usable(&self) -> bool {
411 self.0.usable != 0
412 }
413 }
414
415 /// `feature = "vtab"` Information about what parameters to pass to
416 /// `VTabCursor.filter`.
417 pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
418
419 impl IndexConstraintUsage<'_> {
420 /// if `argv_index` > 0, constraint is part of argv to `VTabCursor.filter`
set_argv_index(&mut self, argv_index: c_int)421 pub fn set_argv_index(&mut self, argv_index: c_int) {
422 self.0.argvIndex = argv_index;
423 }
424
425 /// if `omit`, do not code a test for this constraint
set_omit(&mut self, omit: bool)426 pub fn set_omit(&mut self, omit: bool) {
427 self.0.omit = if omit { 1 } else { 0 };
428 }
429 }
430
431 /// `feature = "vtab"`
432 pub struct OrderByIter<'a> {
433 iter: slice::Iter<'a, ffi::sqlite3_index_info_sqlite3_index_orderby>,
434 }
435
436 impl<'a> Iterator for OrderByIter<'a> {
437 type Item = OrderBy<'a>;
438
next(&mut self) -> Option<OrderBy<'a>>439 fn next(&mut self) -> Option<OrderBy<'a>> {
440 self.iter.next().map(|raw| OrderBy(raw))
441 }
442
size_hint(&self) -> (usize, Option<usize>)443 fn size_hint(&self) -> (usize, Option<usize>) {
444 self.iter.size_hint()
445 }
446 }
447
448 /// `feature = "vtab"` A column of the ORDER BY clause.
449 pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
450
451 impl OrderBy<'_> {
452 /// Column number
column(&self) -> c_int453 pub fn column(&self) -> c_int {
454 self.0.iColumn
455 }
456
457 /// True for DESC. False for ASC.
is_order_by_desc(&self) -> bool458 pub fn is_order_by_desc(&self) -> bool {
459 self.0.desc != 0
460 }
461 }
462
463 /// `feature = "vtab"` Virtual table cursor trait.
464 ///
465 /// Implementations must be like:
466 /// ```rust,ignore
467 /// #[repr(C)]
468 /// struct MyTabCursor {
469 /// /// Base class. Must be first
470 /// base: ffi::sqlite3_vtab_cursor,
471 /// /* Virtual table implementations will typically add additional fields */
472 /// }
473 /// ```
474 ///
475 /// (See [SQLite doc](https://sqlite.org/c3ref/vtab_cursor.html))
476 pub unsafe trait VTabCursor: Sized {
477 /// Begin a search of a virtual table.
478 /// (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<()>479 fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>;
480 /// Advance cursor to the next row of a result set initiated by `filter`.
481 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xnext_method))
next(&mut self) -> Result<()>482 fn next(&mut self) -> Result<()>;
483 /// Must return `false` if the cursor currently points to a valid row of
484 /// data, or `true` otherwise.
485 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xeof_method))
eof(&self) -> bool486 fn eof(&self) -> bool;
487 /// Find the value for the `i`-th column of the current row.
488 /// `i` is zero-based so the first column is numbered 0.
489 /// May return its result back to SQLite using one of the specified `ctx`.
490 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xcolumn_method))
column(&self, ctx: &mut Context, i: c_int) -> Result<()>491 fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
492 /// Return the rowid of row that the cursor is currently pointing at.
493 /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xrowid_method))
rowid(&self) -> Result<i64>494 fn rowid(&self) -> Result<i64>;
495 }
496
497 /// `feature = "vtab"` Context is used by `VTabCursor.column` to specify the
498 /// cell value.
499 pub struct Context(*mut ffi::sqlite3_context);
500
501 impl Context {
502 /// Set current cell value
set_result<T: ToSql>(&mut self, value: &T) -> Result<()>503 pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
504 let t = value.to_sql()?;
505 unsafe { set_result(self.0, &t) };
506 Ok(())
507 }
508
509 // TODO sqlite3_vtab_nochange (http://sqlite.org/c3ref/vtab_nochange.html)
510 }
511
512 /// `feature = "vtab"` Wrapper to `VTabCursor.filter` arguments, the values
513 /// requested by `VTab.best_index`.
514 pub struct Values<'a> {
515 args: &'a [*mut ffi::sqlite3_value],
516 }
517
518 impl Values<'_> {
519 /// Returns the number of values.
len(&self) -> usize520 pub fn len(&self) -> usize {
521 self.args.len()
522 }
523
524 /// Returns `true` if there is no value.
is_empty(&self) -> bool525 pub fn is_empty(&self) -> bool {
526 self.args.is_empty()
527 }
528
529 /// Returns value at `idx`
get<T: FromSql>(&self, idx: usize) -> Result<T>530 pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
531 let arg = self.args[idx];
532 let value = unsafe { ValueRef::from_value(arg) };
533 FromSql::column_result(value).map_err(|err| match err {
534 FromSqlError::InvalidType => Error::InvalidFilterParameterType(idx, value.data_type()),
535 FromSqlError::Other(err) => {
536 Error::FromSqlConversionFailure(idx, value.data_type(), err)
537 }
538 FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
539 #[cfg(feature = "i128_blob")]
540 FromSqlError::InvalidI128Size(_) => {
541 Error::InvalidColumnType(idx, idx.to_string(), value.data_type())
542 }
543 #[cfg(feature = "uuid")]
544 FromSqlError::InvalidUuidSize(_) => {
545 Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
546 }
547 })
548 }
549
550 // `sqlite3_value_type` returns `SQLITE_NULL` for pointer.
551 // So it seems not possible to enhance `ValueRef::from_value`.
552 #[cfg(feature = "array")]
get_array(&self, idx: usize) -> Result<Option<array::Array>>553 fn get_array(&self, idx: usize) -> Result<Option<array::Array>> {
554 use crate::types::Value;
555 let arg = self.args[idx];
556 let ptr = unsafe { ffi::sqlite3_value_pointer(arg, array::ARRAY_TYPE) };
557 if ptr.is_null() {
558 Ok(None)
559 } else {
560 Ok(Some(unsafe {
561 let rc = array::Array::from_raw(ptr as *const Vec<Value>);
562 let array = rc.clone();
563 array::Array::into_raw(rc); // don't consume it
564 array
565 }))
566 }
567 }
568
569 /// Turns `Values` into an iterator.
iter(&self) -> ValueIter<'_>570 pub fn iter(&self) -> ValueIter<'_> {
571 ValueIter {
572 iter: self.args.iter(),
573 }
574 }
575 }
576
577 impl<'a> IntoIterator for &'a Values<'a> {
578 type IntoIter = ValueIter<'a>;
579 type Item = ValueRef<'a>;
580
into_iter(self) -> ValueIter<'a>581 fn into_iter(self) -> ValueIter<'a> {
582 self.iter()
583 }
584 }
585
586 /// `Values` iterator.
587 pub struct ValueIter<'a> {
588 iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
589 }
590
591 impl<'a> Iterator for ValueIter<'a> {
592 type Item = ValueRef<'a>;
593
next(&mut self) -> Option<ValueRef<'a>>594 fn next(&mut self) -> Option<ValueRef<'a>> {
595 self.iter
596 .next()
597 .map(|&raw| unsafe { ValueRef::from_value(raw) })
598 }
599
size_hint(&self) -> (usize, Option<usize>)600 fn size_hint(&self) -> (usize, Option<usize>) {
601 self.iter.size_hint()
602 }
603 }
604
605 impl Connection {
606 /// `feature = "vtab"` Register a virtual table implementation.
607 ///
608 /// Step 3 of [Creating New Virtual Table
609 /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
create_module<'vtab, T: VTab<'vtab>>( &self, module_name: &str, module: &'static Module<'vtab, T>, aux: Option<T::Aux>, ) -> Result<()>610 pub fn create_module<'vtab, T: VTab<'vtab>>(
611 &self,
612 module_name: &str,
613 module: &'static Module<'vtab, T>,
614 aux: Option<T::Aux>,
615 ) -> Result<()> {
616 self.db.borrow_mut().create_module(module_name, module, aux)
617 }
618 }
619
620 impl InnerConnection {
create_module<'vtab, T: VTab<'vtab>>( &mut self, module_name: &str, module: &'static Module<'vtab, T>, aux: Option<T::Aux>, ) -> Result<()>621 fn create_module<'vtab, T: VTab<'vtab>>(
622 &mut self,
623 module_name: &str,
624 module: &'static Module<'vtab, T>,
625 aux: Option<T::Aux>,
626 ) -> Result<()> {
627 let c_name = str_to_cstring(module_name)?;
628 let r = match aux {
629 Some(aux) => {
630 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
631 unsafe {
632 ffi::sqlite3_create_module_v2(
633 self.db(),
634 c_name.as_ptr(),
635 &module.base,
636 boxed_aux as *mut c_void,
637 Some(free_boxed_value::<T::Aux>),
638 )
639 }
640 }
641 None => unsafe {
642 ffi::sqlite3_create_module_v2(
643 self.db(),
644 c_name.as_ptr(),
645 &module.base,
646 ptr::null_mut(),
647 None,
648 )
649 },
650 };
651 self.decode_result(r)
652 }
653 }
654
655 /// `feature = "vtab"` Escape double-quote (`"`) character occurences by
656 /// doubling them (`""`).
escape_double_quote(identifier: &str) -> Cow<'_, str>657 pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
658 if identifier.contains('"') {
659 // escape quote by doubling them
660 Owned(identifier.replace("\"", "\"\""))
661 } else {
662 Borrowed(identifier)
663 }
664 }
665 /// `feature = "vtab"` Dequote string
dequote(s: &str) -> &str666 pub fn dequote(s: &str) -> &str {
667 if s.len() < 2 {
668 return s;
669 }
670 match s.bytes().next() {
671 Some(b) if b == b'"' || b == b'\'' => match s.bytes().rev().next() {
672 Some(e) if e == b => &s[1..s.len() - 1],
673 _ => s,
674 },
675 _ => s,
676 }
677 }
678 /// `feature = "vtab"` The boolean can be one of:
679 /// ```text
680 /// 1 yes true on
681 /// 0 no false off
682 /// ```
parse_boolean(s: &str) -> Option<bool>683 pub fn parse_boolean(s: &str) -> Option<bool> {
684 if s.eq_ignore_ascii_case("yes")
685 || s.eq_ignore_ascii_case("on")
686 || s.eq_ignore_ascii_case("true")
687 || s.eq("1")
688 {
689 Some(true)
690 } else if s.eq_ignore_ascii_case("no")
691 || s.eq_ignore_ascii_case("off")
692 || s.eq_ignore_ascii_case("false")
693 || s.eq("0")
694 {
695 Some(false)
696 } else {
697 None
698 }
699 }
700
701 // FIXME copy/paste from function.rs
free_boxed_value<T>(p: *mut c_void)702 unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
703 let _: Box<T> = Box::from_raw(p as *mut T);
704 }
705
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>,706 unsafe extern "C" fn rust_create<'vtab, T>(
707 db: *mut ffi::sqlite3,
708 aux: *mut c_void,
709 argc: c_int,
710 argv: *const *const c_char,
711 pp_vtab: *mut *mut ffi::sqlite3_vtab,
712 err_msg: *mut *mut c_char,
713 ) -> c_int
714 where
715 T: CreateVTab<'vtab>,
716 {
717 use std::ffi::CStr;
718
719 let mut conn = VTabConnection(db);
720 let aux = aux as *mut T::Aux;
721 let args = slice::from_raw_parts(argv, argc as usize);
722 let vec = args
723 .iter()
724 .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
725 .collect::<Vec<_>>();
726 match T::create(&mut conn, aux.as_ref(), &vec[..]) {
727 Ok((sql, vtab)) => match ::std::ffi::CString::new(sql) {
728 Ok(c_sql) => {
729 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
730 if rc == ffi::SQLITE_OK {
731 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
732 *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
733 ffi::SQLITE_OK
734 } else {
735 let err = error_from_sqlite_code(rc, None);
736 *err_msg = alloc(&err.to_string());
737 rc
738 }
739 }
740 Err(err) => {
741 *err_msg = alloc(&err.to_string());
742 ffi::SQLITE_ERROR
743 }
744 },
745 Err(Error::SqliteFailure(err, s)) => {
746 if let Some(s) = s {
747 *err_msg = alloc(&s);
748 }
749 err.extended_code
750 }
751 Err(err) => {
752 *err_msg = alloc(&err.to_string());
753 ffi::SQLITE_ERROR
754 }
755 }
756 }
757
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>,758 unsafe extern "C" fn rust_connect<'vtab, T>(
759 db: *mut ffi::sqlite3,
760 aux: *mut c_void,
761 argc: c_int,
762 argv: *const *const c_char,
763 pp_vtab: *mut *mut ffi::sqlite3_vtab,
764 err_msg: *mut *mut c_char,
765 ) -> c_int
766 where
767 T: VTab<'vtab>,
768 {
769 use std::ffi::CStr;
770
771 let mut conn = VTabConnection(db);
772 let aux = aux as *mut T::Aux;
773 let args = slice::from_raw_parts(argv, argc as usize);
774 let vec = args
775 .iter()
776 .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
777 .collect::<Vec<_>>();
778 match T::connect(&mut conn, aux.as_ref(), &vec[..]) {
779 Ok((sql, vtab)) => match ::std::ffi::CString::new(sql) {
780 Ok(c_sql) => {
781 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
782 if rc == ffi::SQLITE_OK {
783 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
784 *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
785 ffi::SQLITE_OK
786 } else {
787 let err = error_from_sqlite_code(rc, None);
788 *err_msg = alloc(&err.to_string());
789 rc
790 }
791 }
792 Err(err) => {
793 *err_msg = alloc(&err.to_string());
794 ffi::SQLITE_ERROR
795 }
796 },
797 Err(Error::SqliteFailure(err, s)) => {
798 if let Some(s) = s {
799 *err_msg = alloc(&s);
800 }
801 err.extended_code
802 }
803 Err(err) => {
804 *err_msg = alloc(&err.to_string());
805 ffi::SQLITE_ERROR
806 }
807 }
808 }
809
rust_best_index<'vtab, T>( vtab: *mut ffi::sqlite3_vtab, info: *mut ffi::sqlite3_index_info, ) -> c_int where T: VTab<'vtab>,810 unsafe extern "C" fn rust_best_index<'vtab, T>(
811 vtab: *mut ffi::sqlite3_vtab,
812 info: *mut ffi::sqlite3_index_info,
813 ) -> c_int
814 where
815 T: VTab<'vtab>,
816 {
817 let vt = vtab as *mut T;
818 let mut idx_info = IndexInfo(info);
819 match (*vt).best_index(&mut idx_info) {
820 Ok(_) => ffi::SQLITE_OK,
821 Err(Error::SqliteFailure(err, s)) => {
822 if let Some(err_msg) = s {
823 set_err_msg(vtab, &err_msg);
824 }
825 err.extended_code
826 }
827 Err(err) => {
828 set_err_msg(vtab, &err.to_string());
829 ffi::SQLITE_ERROR
830 }
831 }
832 }
833
rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where T: VTab<'vtab>,834 unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
835 where
836 T: VTab<'vtab>,
837 {
838 if vtab.is_null() {
839 return ffi::SQLITE_OK;
840 }
841 let vtab = vtab as *mut T;
842 let _: Box<T> = Box::from_raw(vtab);
843 ffi::SQLITE_OK
844 }
845
rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where T: CreateVTab<'vtab>,846 unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
847 where
848 T: CreateVTab<'vtab>,
849 {
850 if vtab.is_null() {
851 return ffi::SQLITE_OK;
852 }
853 let vt = vtab as *mut T;
854 match (*vt).destroy() {
855 Ok(_) => {
856 let _: Box<T> = Box::from_raw(vt);
857 ffi::SQLITE_OK
858 }
859 Err(Error::SqliteFailure(err, s)) => {
860 if let Some(err_msg) = s {
861 set_err_msg(vtab, &err_msg);
862 }
863 err.extended_code
864 }
865 Err(err) => {
866 set_err_msg(vtab, &err.to_string());
867 ffi::SQLITE_ERROR
868 }
869 }
870 }
871
rust_open<'vtab, T: 'vtab>( vtab: *mut ffi::sqlite3_vtab, pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor, ) -> c_int where T: VTab<'vtab>,872 unsafe extern "C" fn rust_open<'vtab, T: 'vtab>(
873 vtab: *mut ffi::sqlite3_vtab,
874 pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor,
875 ) -> c_int
876 where
877 T: VTab<'vtab>,
878 {
879 let vt = vtab as *mut T;
880 match (*vt).open() {
881 Ok(cursor) => {
882 let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
883 *pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor;
884 ffi::SQLITE_OK
885 }
886 Err(Error::SqliteFailure(err, s)) => {
887 if let Some(err_msg) = s {
888 set_err_msg(vtab, &err_msg);
889 }
890 err.extended_code
891 }
892 Err(err) => {
893 set_err_msg(vtab, &err.to_string());
894 ffi::SQLITE_ERROR
895 }
896 }
897 }
898
rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,899 unsafe extern "C" fn rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
900 where
901 C: VTabCursor,
902 {
903 let cr = cursor as *mut C;
904 let _: Box<C> = Box::from_raw(cr);
905 ffi::SQLITE_OK
906 }
907
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,908 unsafe extern "C" fn rust_filter<C>(
909 cursor: *mut ffi::sqlite3_vtab_cursor,
910 idx_num: c_int,
911 idx_str: *const c_char,
912 argc: c_int,
913 argv: *mut *mut ffi::sqlite3_value,
914 ) -> c_int
915 where
916 C: VTabCursor,
917 {
918 use std::ffi::CStr;
919 use std::str;
920 let idx_name = if idx_str.is_null() {
921 None
922 } else {
923 let c_slice = CStr::from_ptr(idx_str).to_bytes();
924 Some(str::from_utf8_unchecked(c_slice))
925 };
926 let args = slice::from_raw_parts_mut(argv, argc as usize);
927 let values = Values { args };
928 let cr = cursor as *mut C;
929 cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values))
930 }
931
rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,932 unsafe extern "C" fn rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
933 where
934 C: VTabCursor,
935 {
936 let cr = cursor as *mut C;
937 cursor_error(cursor, (*cr).next())
938 }
939
rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int where C: VTabCursor,940 unsafe extern "C" fn rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
941 where
942 C: VTabCursor,
943 {
944 let cr = cursor as *mut C;
945 (*cr).eof() as c_int
946 }
947
rust_column<C>( cursor: *mut ffi::sqlite3_vtab_cursor, ctx: *mut ffi::sqlite3_context, i: c_int, ) -> c_int where C: VTabCursor,948 unsafe extern "C" fn rust_column<C>(
949 cursor: *mut ffi::sqlite3_vtab_cursor,
950 ctx: *mut ffi::sqlite3_context,
951 i: c_int,
952 ) -> c_int
953 where
954 C: VTabCursor,
955 {
956 let cr = cursor as *mut C;
957 let mut ctxt = Context(ctx);
958 result_error(ctx, (*cr).column(&mut ctxt, i))
959 }
960
rust_rowid<C>( cursor: *mut ffi::sqlite3_vtab_cursor, p_rowid: *mut ffi::sqlite3_int64, ) -> c_int where C: VTabCursor,961 unsafe extern "C" fn rust_rowid<C>(
962 cursor: *mut ffi::sqlite3_vtab_cursor,
963 p_rowid: *mut ffi::sqlite3_int64,
964 ) -> c_int
965 where
966 C: VTabCursor,
967 {
968 let cr = cursor as *mut C;
969 match (*cr).rowid() {
970 Ok(rowid) => {
971 *p_rowid = rowid;
972 ffi::SQLITE_OK
973 }
974 err => cursor_error(cursor, err),
975 }
976 }
977
978 /// Virtual table cursors can set an error message by assigning a string to
979 /// `zErrMsg`.
cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int980 unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int {
981 match result {
982 Ok(_) => ffi::SQLITE_OK,
983 Err(Error::SqliteFailure(err, s)) => {
984 if let Some(err_msg) = s {
985 set_err_msg((*cursor).pVtab, &err_msg);
986 }
987 err.extended_code
988 }
989 Err(err) => {
990 set_err_msg((*cursor).pVtab, &err.to_string());
991 ffi::SQLITE_ERROR
992 }
993 }
994 }
995
996 /// Virtual tables methods can set an error message by assigning a string to
997 /// `zErrMsg`.
set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str)998 unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
999 if !(*vtab).zErrMsg.is_null() {
1000 ffi::sqlite3_free((*vtab).zErrMsg as *mut c_void);
1001 }
1002 (*vtab).zErrMsg = alloc(err_msg);
1003 }
1004
1005 /// To raise an error, the `column` method should use this method to set the
1006 /// error message and return the error code.
result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int1007 unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
1008 match result {
1009 Ok(_) => ffi::SQLITE_OK,
1010 Err(Error::SqliteFailure(err, s)) => {
1011 match err.extended_code {
1012 ffi::SQLITE_TOOBIG => {
1013 ffi::sqlite3_result_error_toobig(ctx);
1014 }
1015 ffi::SQLITE_NOMEM => {
1016 ffi::sqlite3_result_error_nomem(ctx);
1017 }
1018 code => {
1019 ffi::sqlite3_result_error_code(ctx, code);
1020 if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
1021 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1022 }
1023 }
1024 };
1025 err.extended_code
1026 }
1027 Err(err) => {
1028 ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_ERROR);
1029 if let Ok(cstr) = str_to_cstring(&err.to_string()) {
1030 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1031 }
1032 ffi::SQLITE_ERROR
1033 }
1034 }
1035 }
1036
1037 // Space to hold this string must be obtained
1038 // from an SQLite memory allocation function
alloc(s: &str) -> *mut c_char1039 fn alloc(s: &str) -> *mut c_char {
1040 crate::util::SqliteMallocString::from_str(s).into_raw()
1041 }
1042
1043 #[cfg(feature = "array")]
1044 pub mod array;
1045 #[cfg(feature = "csvtab")]
1046 pub mod csvtab;
1047 #[cfg(feature = "series")]
1048 pub mod series; // SQLite >= 3.9.0
1049
1050 #[cfg(test)]
1051 mod test {
1052 #[test]
test_dequote()1053 fn test_dequote() {
1054 assert_eq!("", super::dequote(""));
1055 assert_eq!("'", super::dequote("'"));
1056 assert_eq!("\"", super::dequote("\""));
1057 assert_eq!("'\"", super::dequote("'\""));
1058 assert_eq!("", super::dequote("''"));
1059 assert_eq!("", super::dequote("\"\""));
1060 assert_eq!("x", super::dequote("'x'"));
1061 assert_eq!("x", super::dequote("\"x\""));
1062 assert_eq!("x", super::dequote("x"));
1063 }
1064 #[test]
test_parse_boolean()1065 fn test_parse_boolean() {
1066 assert_eq!(None, super::parse_boolean(""));
1067 assert_eq!(Some(true), super::parse_boolean("1"));
1068 assert_eq!(Some(true), super::parse_boolean("yes"));
1069 assert_eq!(Some(true), super::parse_boolean("on"));
1070 assert_eq!(Some(true), super::parse_boolean("true"));
1071 assert_eq!(Some(false), super::parse_boolean("0"));
1072 assert_eq!(Some(false), super::parse_boolean("no"));
1073 assert_eq!(Some(false), super::parse_boolean("off"));
1074 assert_eq!(Some(false), super::parse_boolean("false"));
1075 }
1076 }
1077