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