1use std::borrow::Cow::{self, Borrowed, Owned};
13use std::marker::PhantomData;
14use std::marker::Sync;
15use std::os::raw::{c_char, c_int, c_void};
16use std::ptr;
17use std::slice;
18
19use crate::context::set_result;
20use crate::error::error_from_sqlite_code;
21use crate::ffi;
22pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor};
23use crate::types::{FromSql, FromSqlError, ToSql, ValueRef};
24use crate::{str_to_cstring, Connection, Error, InnerConnection, Result};
25
26pub enum VTabKind {
62 Default,
64 Eponymous,
68 EponymousOnly,
75}
76
77#[repr(transparent)]
81pub struct Module<'vtab, T: VTab<'vtab>> {
82 base: ffi::sqlite3_module,
83 phantom: PhantomData<&'vtab T>,
84}
85
86unsafe impl<'vtab, T: VTab<'vtab>> Send for Module<'vtab, T> {}
87unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {}
88
89union ModuleZeroHack {
90 bytes: [u8; std::mem::size_of::<ffi::sqlite3_module>()],
91 module: ffi::sqlite3_module,
92}
93
94const ZERO_MODULE: ffi::sqlite3_module = unsafe {
98 ModuleZeroHack {
99 bytes: [0_u8; std::mem::size_of::<ffi::sqlite3_module>()],
100 }
101 .module
102};
103
104macro_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 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>), 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#[must_use]
144pub 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#[must_use]
162pub 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 module!('vtab, T, T::Cursor, Some(rust_connect::<T>), Some(rust_disconnect::<T>), None)
169 }
170 _ => {
171 module!('vtab, T, T::Cursor, Some(rust_create::<T>), Some(rust_destroy::<T>), None)
174 }
175 }
176}
177
178#[must_use]
182pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> {
183 module!('vtab, T, T::Cursor, None, None, None)
185}
186
187#[repr(i32)]
189#[non_exhaustive]
190#[cfg(feature = "modern_sqlite")] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
192pub enum VTabConfig {
193 ConstraintSupport = 1,
195 Innocuous = 2,
197 DirectOnly = 3,
199}
200
201pub struct VTabConnection(*mut ffi::sqlite3);
203
204impl VTabConnection {
205 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
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 pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
228 self.0
229 }
230}
231
232pub unsafe trait VTab<'vtab>: Sized {
250 type Aux;
252 type Cursor: VTabCursor;
254
255 fn connect(
259 db: &mut VTabConnection,
260 aux: Option<&Self::Aux>,
261 args: &[&[u8]],
262 ) -> Result<(String, Self)>;
263
264 fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
267
268 fn open(&'vtab mut self) -> Result<Self::Cursor>;
271}
272
273pub trait CreateVTab<'vtab>: VTab<'vtab> {
277 const KIND: VTabKind;
281 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 fn destroy(&self) -> Result<()> {
302 Ok(())
303 }
304}
305
306pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
310 fn delete(&mut self, arg: ValueRef<'_>) -> Result<()>;
312 fn insert(&mut self, args: &Values<'_>) -> Result<i64>;
318 fn update(&mut self, args: &Values<'_>) -> Result<()>;
321}
322
323#[derive(Debug, Eq, PartialEq)]
326#[allow(non_snake_case, non_camel_case_types, missing_docs)]
327#[allow(clippy::upper_case_acronyms)]
328pub 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, SQLITE_INDEX_CONSTRAINT_GLOB, SQLITE_INDEX_CONSTRAINT_REGEXP, SQLITE_INDEX_CONSTRAINT_NE, SQLITE_INDEX_CONSTRAINT_ISNOT, SQLITE_INDEX_CONSTRAINT_ISNOTNULL, SQLITE_INDEX_CONSTRAINT_ISNULL, SQLITE_INDEX_CONSTRAINT_IS, SQLITE_INDEX_CONSTRAINT_LIMIT, SQLITE_INDEX_CONSTRAINT_OFFSET, SQLITE_INDEX_CONSTRAINT_FUNCTION(u8), }
347
348impl From<u8> for IndexConstraintOp {
349 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")] bitflags::bitflags! {
374 #[repr(C)]
377 pub struct IndexFlags: ::std::os::raw::c_int {
378 const NONE = 0;
380 const SQLITE_INDEX_SCAN_UNIQUE = ffi::SQLITE_INDEX_SCAN_UNIQUE;
382 }
383}
384
385#[derive(Debug)]
390pub struct IndexInfo(*mut ffi::sqlite3_index_info);
391
392impl IndexInfo {
393 #[inline]
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 #[inline]
408 #[must_use]
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 #[inline]
419 #[must_use]
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 #[inline]
430 #[must_use]
431 pub fn num_of_order_by(&self) -> usize {
432 unsafe { (*self.0).nOrderBy as usize }
433 }
434
435 #[inline]
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 #[inline]
446 pub fn set_idx_num(&mut self, idx_num: c_int) {
447 unsafe {
448 (*self.0).idxNum = idx_num;
449 }
450 }
451
452 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 #[inline]
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 #[inline]
470 pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
471 unsafe {
472 (*self.0).estimatedCost = estimated_ost;
473 }
474 }
475
476 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
479 #[inline]
480 pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
481 unsafe {
482 (*self.0).estimatedRows = estimated_rows;
483 }
484 }
485
486 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
489 #[inline]
490 pub fn set_idx_flags(&mut self, flags: IndexFlags) {
491 unsafe { (*self.0).idxFlags = flags.bits() };
492 }
493
494 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
497 #[inline]
498 pub fn col_used(&self) -> u64 {
499 unsafe { (*self.0).colUsed }
500 }
501
502 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
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 }
541
542pub 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
550impl<'a> Iterator for IndexConstraintAndUsageIter<'a> {
551 type Item = (IndexConstraint<'a>, IndexConstraintUsage<'a>);
552
553 #[inline]
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]
561 fn size_hint(&self) -> (usize, Option<usize>) {
562 self.iter.size_hint()
563 }
564}
565
566pub struct IndexConstraintIter<'a> {
568 iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
569}
570
571impl<'a> Iterator for IndexConstraintIter<'a> {
572 type Item = IndexConstraint<'a>;
573
574 #[inline]
575 fn next(&mut self) -> Option<IndexConstraint<'a>> {
576 self.iter.next().map(IndexConstraint)
577 }
578
579 #[inline]
580 fn size_hint(&self) -> (usize, Option<usize>) {
581 self.iter.size_hint()
582 }
583}
584
585pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
587
588impl IndexConstraint<'_> {
589 #[inline]
591 #[must_use]
592 pub fn column(&self) -> c_int {
593 self.0.iColumn
594 }
595
596 #[inline]
598 #[must_use]
599 pub fn operator(&self) -> IndexConstraintOp {
600 IndexConstraintOp::from(self.0.op)
601 }
602
603 #[inline]
605 #[must_use]
606 pub fn is_usable(&self) -> bool {
607 self.0.usable != 0
608 }
609}
610
611pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
614
615impl IndexConstraintUsage<'_> {
616 #[inline]
619 pub fn set_argv_index(&mut self, argv_index: c_int) {
620 self.0.argvIndex = argv_index;
621 }
622
623 #[inline]
625 pub fn set_omit(&mut self, omit: bool) {
626 self.0.omit = if omit { 1 } else { 0 };
627 }
628}
629
630pub struct OrderByIter<'a> {
632 iter: slice::Iter<'a, ffi::sqlite3_index_info_sqlite3_index_orderby>,
633}
634
635impl<'a> Iterator for OrderByIter<'a> {
636 type Item = OrderBy<'a>;
637
638 #[inline]
639 fn next(&mut self) -> Option<OrderBy<'a>> {
640 self.iter.next().map(OrderBy)
641 }
642
643 #[inline]
644 fn size_hint(&self) -> (usize, Option<usize>) {
645 self.iter.size_hint()
646 }
647}
648
649pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
651
652impl OrderBy<'_> {
653 #[inline]
655 #[must_use]
656 pub fn column(&self) -> c_int {
657 self.0.iColumn
658 }
659
660 #[inline]
662 #[must_use]
663 pub fn is_order_by_desc(&self) -> bool {
664 self.0.desc != 0
665 }
666}
667
668pub unsafe trait VTabCursor: Sized {
684 fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>;
687 fn next(&mut self) -> Result<()>;
690 fn eof(&self) -> bool;
694 fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
699 fn rowid(&self) -> Result<i64>;
702}
703
704pub struct Context(*mut ffi::sqlite3_context);
707
708impl Context {
709 #[inline]
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 }
719
720pub struct Values<'a> {
723 args: &'a [*mut ffi::sqlite3_value],
724}
725
726impl Values<'_> {
727 #[inline]
729 #[must_use]
730 pub fn len(&self) -> usize {
731 self.args.len()
732 }
733
734 #[inline]
736 #[must_use]
737 pub fn is_empty(&self) -> bool {
738 self.args.is_empty()
739 }
740
741 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 #[cfg(feature = "array")]
760 #[cfg_attr(docsrs, doc(cfg(feature = "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); array
773 })
774 }
775 }
776
777 #[inline]
779 #[must_use]
780 pub fn iter(&self) -> ValueIter<'_> {
781 ValueIter {
782 iter: self.args.iter(),
783 }
784 }
785 }
787
788impl<'a> IntoIterator for &'a Values<'a> {
789 type IntoIter = ValueIter<'a>;
790 type Item = ValueRef<'a>;
791
792 #[inline]
793 fn into_iter(self) -> ValueIter<'a> {
794 self.iter()
795 }
796}
797
798pub struct ValueIter<'a> {
800 iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
801}
802
803impl<'a> Iterator for ValueIter<'a> {
804 type Item = ValueRef<'a>;
805
806 #[inline]
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]
814 fn size_hint(&self) -> (usize, Option<usize>) {
815 self.iter.size_hint()
816 }
817}
818
819impl Connection {
820 #[inline]
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
835impl InnerConnection {
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#[must_use]
880pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
881 if identifier.contains('"') {
882 Owned(identifier.replace('"', "\"\""))
884 } else {
885 Borrowed(identifier)
886 }
887}
888#[must_use]
890pub 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], _ => s,
898 },
899 _ => s,
900 }
901}
902#[must_use]
908pub 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
926pub 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
940unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
942 drop(Box::from_raw(p.cast::<T>()));
943}
944
945unsafe 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
953where
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()) .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
997unsafe 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
1005where
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()) .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
1049unsafe extern "C" fn rust_best_index<'vtab, T>(
1050 vtab: *mut ffi::sqlite3_vtab,
1051 info: *mut ffi::sqlite3_index_info,
1052) -> c_int
1053where
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
1073unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
1074where
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
1085unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
1086where
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
1111unsafe 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
1115where
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
1138unsafe extern "C" fn rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1139where
1140 C: VTabCursor,
1141{
1142 let cr = cursor.cast::<C>();
1143 drop(Box::from_raw(cr));
1144 ffi::SQLITE_OK
1145}
1146
1147unsafe 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
1154where
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
1171unsafe extern "C" fn rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1172where
1173 C: VTabCursor,
1174{
1175 let cr = cursor as *mut C;
1176 cursor_error(cursor, (*cr).next())
1177}
1178
1179unsafe extern "C" fn rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1180where
1181 C: VTabCursor,
1182{
1183 let cr = cursor.cast::<C>();
1184 (*cr).eof() as c_int
1185}
1186
1187unsafe 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
1192where
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
1200unsafe extern "C" fn rust_rowid<C>(
1201 cursor: *mut ffi::sqlite3_vtab_cursor,
1202 p_rowid: *mut ffi::sqlite3_int64,
1203) -> c_int
1204where
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
1217unsafe 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
1223where
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 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#[cold]
1263unsafe 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#[cold]
1282unsafe 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#[cold]
1292unsafe 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
1322fn 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")))]
1330pub mod array;
1331#[cfg(feature = "csvtab")]
1332#[cfg_attr(docsrs, doc(cfg(feature = "csvtab")))]
1333pub mod csvtab;
1334#[cfg(feature = "series")]
1335#[cfg_attr(docsrs, doc(cfg(feature = "series")))]
1336pub mod series; #[cfg(test)]
1338mod vtablog;
1339
1340#[cfg(test)]
1341mod test {
1342 #[test]
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]
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}