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#[derive(Debug, Clone, Copy, Eq, PartialEq)]
191pub enum VTabConfig {
192 ConstraintSupport = 1,
194 Innocuous = 2,
196 DirectOnly = 3,
198}
199
200pub struct VTabConnection(*mut ffi::sqlite3);
202
203impl VTabConnection {
204 pub fn config(&mut self, config: VTabConfig) -> Result<()> {
206 crate::error::check(unsafe { ffi::sqlite3_vtab_config(self.0, config as c_int) })
207 }
208
209 pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
225 self.0
226 }
227}
228
229pub unsafe trait VTab<'vtab>: Sized {
247 type Aux;
249 type Cursor: VTabCursor;
251
252 fn connect(
256 db: &mut VTabConnection,
257 aux: Option<&Self::Aux>,
258 args: &[&[u8]],
259 ) -> Result<(String, Self)>;
260
261 fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
264
265 fn open(&'vtab mut self) -> Result<Self::Cursor>;
268}
269
270pub trait CreateVTab<'vtab>: VTab<'vtab> {
274 const KIND: VTabKind;
278 fn create(
286 db: &mut VTabConnection,
287 aux: Option<&Self::Aux>,
288 args: &[&[u8]],
289 ) -> Result<(String, Self)> {
290 Self::connect(db, aux, args)
291 }
292
293 fn destroy(&self) -> Result<()> {
299 Ok(())
300 }
301}
302
303pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
307 fn delete(&mut self, arg: ValueRef<'_>) -> Result<()>;
309 fn insert(&mut self, args: &Values<'_>) -> Result<i64>;
315 fn update(&mut self, args: &Values<'_>) -> Result<()>;
318}
319
320#[derive(Debug, Eq, PartialEq)]
323#[allow(non_snake_case, non_camel_case_types, missing_docs)]
324#[allow(clippy::upper_case_acronyms)]
325pub enum IndexConstraintOp {
326 SQLITE_INDEX_CONSTRAINT_EQ,
327 SQLITE_INDEX_CONSTRAINT_GT,
328 SQLITE_INDEX_CONSTRAINT_LE,
329 SQLITE_INDEX_CONSTRAINT_LT,
330 SQLITE_INDEX_CONSTRAINT_GE,
331 SQLITE_INDEX_CONSTRAINT_MATCH,
332 SQLITE_INDEX_CONSTRAINT_LIKE, 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), }
344
345impl From<u8> for IndexConstraintOp {
346 fn from(code: u8) -> IndexConstraintOp {
347 match code {
348 2 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ,
349 4 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GT,
350 8 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LE,
351 16 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LT,
352 32 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GE,
353 64 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_MATCH,
354 65 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIKE,
355 66 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_GLOB,
356 67 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_REGEXP,
357 68 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_NE,
358 69 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOT,
359 70 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
360 71 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_ISNULL,
361 72 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_IS,
362 73 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_LIMIT,
363 74 => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_OFFSET,
364 v => IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
365 }
366 }
367}
368
369bitflags::bitflags! {
370 #[repr(C)]
373 pub struct IndexFlags: ::std::os::raw::c_int {
374 const NONE = 0;
376 const SQLITE_INDEX_SCAN_UNIQUE = ffi::SQLITE_INDEX_SCAN_UNIQUE;
378 }
379}
380
381#[derive(Debug)]
386pub struct IndexInfo(*mut ffi::sqlite3_index_info);
387
388impl IndexInfo {
389 #[inline]
391 pub fn constraints_and_usages(&mut self) -> IndexConstraintAndUsageIter<'_> {
392 let constraints =
393 unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
394 let constraint_usages = unsafe {
395 slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
396 };
397 IndexConstraintAndUsageIter {
398 iter: constraints.iter().zip(constraint_usages.iter_mut()),
399 }
400 }
401
402 #[inline]
404 #[must_use]
405 pub fn constraints(&self) -> IndexConstraintIter<'_> {
406 let constraints =
407 unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
408 IndexConstraintIter {
409 iter: constraints.iter(),
410 }
411 }
412
413 #[inline]
415 #[must_use]
416 pub fn order_bys(&self) -> OrderByIter<'_> {
417 let order_bys =
418 unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
419 OrderByIter {
420 iter: order_bys.iter(),
421 }
422 }
423
424 #[inline]
426 #[must_use]
427 pub fn num_of_order_by(&self) -> usize {
428 unsafe { (*self.0).nOrderBy as usize }
429 }
430
431 #[inline]
433 pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
434 let constraint_usages = unsafe {
435 slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
436 };
437 IndexConstraintUsage(&mut constraint_usages[constraint_idx])
438 }
439
440 #[inline]
442 pub fn set_idx_num(&mut self, idx_num: c_int) {
443 unsafe {
444 (*self.0).idxNum = idx_num;
445 }
446 }
447
448 pub fn set_idx_str(&mut self, idx_str: &str) {
450 unsafe {
451 (*self.0).idxStr = alloc(idx_str);
452 (*self.0).needToFreeIdxStr = 1;
453 }
454 }
455
456 #[inline]
458 pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
459 unsafe {
460 (*self.0).orderByConsumed = order_by_consumed as c_int;
461 }
462 }
463
464 #[inline]
466 pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
467 unsafe {
468 (*self.0).estimatedCost = estimated_ost;
469 }
470 }
471
472 #[inline]
474 pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
475 unsafe {
476 (*self.0).estimatedRows = estimated_rows;
477 }
478 }
479
480 #[inline]
482 pub fn set_idx_flags(&mut self, flags: IndexFlags) {
483 unsafe { (*self.0).idxFlags = flags.bits() };
484 }
485
486 #[inline]
488 pub fn col_used(&self) -> u64 {
489 unsafe { (*self.0).colUsed }
490 }
491
492 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
495 pub fn collation(&self, constraint_idx: usize) -> Result<&str> {
496 use std::ffi::CStr;
497 let idx = constraint_idx as c_int;
498 let collation = unsafe { ffi::sqlite3_vtab_collation(self.0, idx) };
499 if collation.is_null() {
500 return Err(Error::SqliteFailure(
501 ffi::Error::new(ffi::SQLITE_MISUSE),
502 Some(format!("{constraint_idx} is out of range")),
503 ));
504 }
505 Ok(unsafe { CStr::from_ptr(collation) }.to_str()?)
506 }
507
508 }
531
532pub struct IndexConstraintAndUsageIter<'a> {
534 iter: std::iter::Zip<
535 slice::Iter<'a, ffi::sqlite3_index_constraint>,
536 slice::IterMut<'a, ffi::sqlite3_index_constraint_usage>,
537 >,
538}
539
540impl<'a> Iterator for IndexConstraintAndUsageIter<'a> {
541 type Item = (IndexConstraint<'a>, IndexConstraintUsage<'a>);
542
543 #[inline]
544 fn next(&mut self) -> Option<(IndexConstraint<'a>, IndexConstraintUsage<'a>)> {
545 self.iter
546 .next()
547 .map(|raw| (IndexConstraint(raw.0), IndexConstraintUsage(raw.1)))
548 }
549
550 #[inline]
551 fn size_hint(&self) -> (usize, Option<usize>) {
552 self.iter.size_hint()
553 }
554}
555
556pub struct IndexConstraintIter<'a> {
558 iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
559}
560
561impl<'a> Iterator for IndexConstraintIter<'a> {
562 type Item = IndexConstraint<'a>;
563
564 #[inline]
565 fn next(&mut self) -> Option<IndexConstraint<'a>> {
566 self.iter.next().map(IndexConstraint)
567 }
568
569 #[inline]
570 fn size_hint(&self) -> (usize, Option<usize>) {
571 self.iter.size_hint()
572 }
573}
574
575pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
577
578impl IndexConstraint<'_> {
579 #[inline]
581 #[must_use]
582 pub fn column(&self) -> c_int {
583 self.0.iColumn
584 }
585
586 #[inline]
588 #[must_use]
589 pub fn operator(&self) -> IndexConstraintOp {
590 IndexConstraintOp::from(self.0.op)
591 }
592
593 #[inline]
595 #[must_use]
596 pub fn is_usable(&self) -> bool {
597 self.0.usable != 0
598 }
599}
600
601pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
604
605impl IndexConstraintUsage<'_> {
606 #[inline]
609 pub fn set_argv_index(&mut self, argv_index: c_int) {
610 self.0.argvIndex = argv_index;
611 }
612
613 #[inline]
615 pub fn set_omit(&mut self, omit: bool) {
616 self.0.omit = omit as std::os::raw::c_uchar;
617 }
618}
619
620pub struct OrderByIter<'a> {
622 iter: slice::Iter<'a, ffi::sqlite3_index_orderby>,
623}
624
625impl<'a> Iterator for OrderByIter<'a> {
626 type Item = OrderBy<'a>;
627
628 #[inline]
629 fn next(&mut self) -> Option<OrderBy<'a>> {
630 self.iter.next().map(OrderBy)
631 }
632
633 #[inline]
634 fn size_hint(&self) -> (usize, Option<usize>) {
635 self.iter.size_hint()
636 }
637}
638
639pub struct OrderBy<'a>(&'a ffi::sqlite3_index_orderby);
641
642impl OrderBy<'_> {
643 #[inline]
645 #[must_use]
646 pub fn column(&self) -> c_int {
647 self.0.iColumn
648 }
649
650 #[inline]
652 #[must_use]
653 pub fn is_order_by_desc(&self) -> bool {
654 self.0.desc != 0
655 }
656}
657
658pub unsafe trait VTabCursor: Sized {
674 fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Values<'_>) -> Result<()>;
677 fn next(&mut self) -> Result<()>;
680 fn eof(&self) -> bool;
684 fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
689 fn rowid(&self) -> Result<i64>;
692}
693
694pub struct Context(*mut ffi::sqlite3_context);
697
698impl Context {
699 #[inline]
701 pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
702 let t = value.to_sql()?;
703 unsafe { set_result(self.0, &t) };
704 Ok(())
705 }
706
707 }
709
710pub struct Values<'a> {
713 args: &'a [*mut ffi::sqlite3_value],
714}
715
716impl Values<'_> {
717 #[inline]
719 #[must_use]
720 pub fn len(&self) -> usize {
721 self.args.len()
722 }
723
724 #[inline]
726 #[must_use]
727 pub fn is_empty(&self) -> bool {
728 self.args.is_empty()
729 }
730
731 pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
733 let arg = self.args[idx];
734 let value = unsafe { ValueRef::from_value(arg) };
735 FromSql::column_result(value).map_err(|err| match err {
736 FromSqlError::InvalidType => Error::InvalidFilterParameterType(idx, value.data_type()),
737 FromSqlError::Other(err) => {
738 Error::FromSqlConversionFailure(idx, value.data_type(), err)
739 }
740 FromSqlError::InvalidBlobSize { .. } => {
741 Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
742 }
743 FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
744 })
745 }
746
747 #[cfg(feature = "array")]
750 #[cfg_attr(docsrs, doc(cfg(feature = "array")))]
751 fn get_array(&self, idx: usize) -> Option<array::Array> {
752 use crate::types::Value;
753 let arg = self.args[idx];
754 let ptr = unsafe { ffi::sqlite3_value_pointer(arg, array::ARRAY_TYPE) };
755 if ptr.is_null() {
756 None
757 } else {
758 Some(unsafe {
759 let rc = array::Array::from_raw(ptr as *const Vec<Value>);
760 let array = rc.clone();
761 let _ = array::Array::into_raw(rc); array
763 })
764 }
765 }
766
767 #[inline]
769 #[must_use]
770 pub fn iter(&self) -> ValueIter<'_> {
771 ValueIter {
772 iter: self.args.iter(),
773 }
774 }
775 }
777
778impl<'a> IntoIterator for &'a Values<'a> {
779 type IntoIter = ValueIter<'a>;
780 type Item = ValueRef<'a>;
781
782 #[inline]
783 fn into_iter(self) -> ValueIter<'a> {
784 self.iter()
785 }
786}
787
788pub struct ValueIter<'a> {
790 iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
791}
792
793impl<'a> Iterator for ValueIter<'a> {
794 type Item = ValueRef<'a>;
795
796 #[inline]
797 fn next(&mut self) -> Option<ValueRef<'a>> {
798 self.iter
799 .next()
800 .map(|&raw| unsafe { ValueRef::from_value(raw) })
801 }
802
803 #[inline]
804 fn size_hint(&self) -> (usize, Option<usize>) {
805 self.iter.size_hint()
806 }
807}
808
809impl Connection {
810 #[inline]
815 pub fn create_module<'vtab, T: VTab<'vtab>>(
816 &self,
817 module_name: &str,
818 module: &'static Module<'vtab, T>,
819 aux: Option<T::Aux>,
820 ) -> Result<()> {
821 self.db.borrow_mut().create_module(module_name, module, aux)
822 }
823}
824
825impl InnerConnection {
826 fn create_module<'vtab, T: VTab<'vtab>>(
827 &mut self,
828 module_name: &str,
829 module: &'static Module<'vtab, T>,
830 aux: Option<T::Aux>,
831 ) -> Result<()> {
832 use crate::version;
833 if version::version_number() < 3_009_000 && module.base.xCreate.is_none() {
834 return Err(Error::ModuleError(format!(
835 "Eponymous-only virtual table not supported by SQLite version {}",
836 version::version()
837 )));
838 }
839 let c_name = str_to_cstring(module_name)?;
840 let r = match aux {
841 Some(aux) => {
842 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
843 unsafe {
844 ffi::sqlite3_create_module_v2(
845 self.db(),
846 c_name.as_ptr(),
847 &module.base,
848 boxed_aux.cast::<c_void>(),
849 Some(free_boxed_value::<T::Aux>),
850 )
851 }
852 }
853 None => unsafe {
854 ffi::sqlite3_create_module_v2(
855 self.db(),
856 c_name.as_ptr(),
857 &module.base,
858 ptr::null_mut(),
859 None,
860 )
861 },
862 };
863 self.decode_result(r)
864 }
865}
866
867#[must_use]
870pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
871 if identifier.contains('"') {
872 Owned(identifier.replace('"', "\"\""))
874 } else {
875 Borrowed(identifier)
876 }
877}
878#[must_use]
880pub fn dequote(s: &str) -> &str {
881 if s.len() < 2 {
882 return s;
883 }
884 match s.bytes().next() {
885 Some(b) if b == b'"' || b == b'\'' => match s.bytes().rev().next() {
886 Some(e) if e == b => &s[1..s.len() - 1], _ => s,
888 },
889 _ => s,
890 }
891}
892#[must_use]
898pub fn parse_boolean(s: &str) -> Option<bool> {
899 if s.eq_ignore_ascii_case("yes")
900 || s.eq_ignore_ascii_case("on")
901 || s.eq_ignore_ascii_case("true")
902 || s.eq("1")
903 {
904 Some(true)
905 } else if s.eq_ignore_ascii_case("no")
906 || s.eq_ignore_ascii_case("off")
907 || s.eq_ignore_ascii_case("false")
908 || s.eq("0")
909 {
910 Some(false)
911 } else {
912 None
913 }
914}
915
916pub fn parameter(c_slice: &[u8]) -> Result<(&str, &str)> {
918 let arg = std::str::from_utf8(c_slice)?.trim();
919 let mut split = arg.split('=');
920 if let Some(key) = split.next() {
921 if let Some(value) = split.next() {
922 let param = key.trim();
923 let value = dequote(value);
924 return Ok((param, value));
925 }
926 }
927 Err(Error::ModuleError(format!("illegal argument: '{arg}'")))
928}
929
930unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
932 drop(Box::from_raw(p.cast::<T>()));
933}
934
935unsafe extern "C" fn rust_create<'vtab, T>(
936 db: *mut ffi::sqlite3,
937 aux: *mut c_void,
938 argc: c_int,
939 argv: *const *const c_char,
940 pp_vtab: *mut *mut ffi::sqlite3_vtab,
941 err_msg: *mut *mut c_char,
942) -> c_int
943where
944 T: CreateVTab<'vtab>,
945{
946 use std::ffi::CStr;
947
948 let mut conn = VTabConnection(db);
949 let aux = aux.cast::<T::Aux>();
950 let args = slice::from_raw_parts(argv, argc as usize);
951 let vec = args
952 .iter()
953 .map(|&cs| CStr::from_ptr(cs).to_bytes()) .collect::<Vec<_>>();
955 match T::create(&mut conn, aux.as_ref(), &vec[..]) {
956 Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
957 Ok(c_sql) => {
958 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
959 if rc == ffi::SQLITE_OK {
960 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
961 *pp_vtab = boxed_vtab.cast::<ffi::sqlite3_vtab>();
962 ffi::SQLITE_OK
963 } else {
964 let err = error_from_sqlite_code(rc, None);
965 *err_msg = alloc(&err.to_string());
966 rc
967 }
968 }
969 Err(err) => {
970 *err_msg = alloc(&err.to_string());
971 ffi::SQLITE_ERROR
972 }
973 },
974 Err(Error::SqliteFailure(err, s)) => {
975 if let Some(s) = s {
976 *err_msg = alloc(&s);
977 }
978 err.extended_code
979 }
980 Err(err) => {
981 *err_msg = alloc(&err.to_string());
982 ffi::SQLITE_ERROR
983 }
984 }
985}
986
987unsafe extern "C" fn rust_connect<'vtab, T>(
988 db: *mut ffi::sqlite3,
989 aux: *mut c_void,
990 argc: c_int,
991 argv: *const *const c_char,
992 pp_vtab: *mut *mut ffi::sqlite3_vtab,
993 err_msg: *mut *mut c_char,
994) -> c_int
995where
996 T: VTab<'vtab>,
997{
998 use std::ffi::CStr;
999
1000 let mut conn = VTabConnection(db);
1001 let aux = aux.cast::<T::Aux>();
1002 let args = slice::from_raw_parts(argv, argc as usize);
1003 let vec = args
1004 .iter()
1005 .map(|&cs| CStr::from_ptr(cs).to_bytes()) .collect::<Vec<_>>();
1007 match T::connect(&mut conn, aux.as_ref(), &vec[..]) {
1008 Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
1009 Ok(c_sql) => {
1010 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
1011 if rc == ffi::SQLITE_OK {
1012 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1013 *pp_vtab = boxed_vtab.cast::<ffi::sqlite3_vtab>();
1014 ffi::SQLITE_OK
1015 } else {
1016 let err = error_from_sqlite_code(rc, None);
1017 *err_msg = alloc(&err.to_string());
1018 rc
1019 }
1020 }
1021 Err(err) => {
1022 *err_msg = alloc(&err.to_string());
1023 ffi::SQLITE_ERROR
1024 }
1025 },
1026 Err(Error::SqliteFailure(err, s)) => {
1027 if let Some(s) = s {
1028 *err_msg = alloc(&s);
1029 }
1030 err.extended_code
1031 }
1032 Err(err) => {
1033 *err_msg = alloc(&err.to_string());
1034 ffi::SQLITE_ERROR
1035 }
1036 }
1037}
1038
1039unsafe extern "C" fn rust_best_index<'vtab, T>(
1040 vtab: *mut ffi::sqlite3_vtab,
1041 info: *mut ffi::sqlite3_index_info,
1042) -> c_int
1043where
1044 T: VTab<'vtab>,
1045{
1046 let vt = vtab.cast::<T>();
1047 let mut idx_info = IndexInfo(info);
1048 match (*vt).best_index(&mut idx_info) {
1049 Ok(_) => ffi::SQLITE_OK,
1050 Err(Error::SqliteFailure(err, s)) => {
1051 if let Some(err_msg) = s {
1052 set_err_msg(vtab, &err_msg);
1053 }
1054 err.extended_code
1055 }
1056 Err(err) => {
1057 set_err_msg(vtab, &err.to_string());
1058 ffi::SQLITE_ERROR
1059 }
1060 }
1061}
1062
1063unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
1064where
1065 T: VTab<'vtab>,
1066{
1067 if vtab.is_null() {
1068 return ffi::SQLITE_OK;
1069 }
1070 let vtab = vtab.cast::<T>();
1071 drop(Box::from_raw(vtab));
1072 ffi::SQLITE_OK
1073}
1074
1075unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int
1076where
1077 T: CreateVTab<'vtab>,
1078{
1079 if vtab.is_null() {
1080 return ffi::SQLITE_OK;
1081 }
1082 let vt = vtab.cast::<T>();
1083 match (*vt).destroy() {
1084 Ok(_) => {
1085 drop(Box::from_raw(vt));
1086 ffi::SQLITE_OK
1087 }
1088 Err(Error::SqliteFailure(err, s)) => {
1089 if let Some(err_msg) = s {
1090 set_err_msg(vtab, &err_msg);
1091 }
1092 err.extended_code
1093 }
1094 Err(err) => {
1095 set_err_msg(vtab, &err.to_string());
1096 ffi::SQLITE_ERROR
1097 }
1098 }
1099}
1100
1101unsafe extern "C" fn rust_open<'vtab, T: 'vtab>(
1102 vtab: *mut ffi::sqlite3_vtab,
1103 pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor,
1104) -> c_int
1105where
1106 T: VTab<'vtab>,
1107{
1108 let vt = vtab.cast::<T>();
1109 match (*vt).open() {
1110 Ok(cursor) => {
1111 let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
1112 *pp_cursor = boxed_cursor.cast::<ffi::sqlite3_vtab_cursor>();
1113 ffi::SQLITE_OK
1114 }
1115 Err(Error::SqliteFailure(err, s)) => {
1116 if let Some(err_msg) = s {
1117 set_err_msg(vtab, &err_msg);
1118 }
1119 err.extended_code
1120 }
1121 Err(err) => {
1122 set_err_msg(vtab, &err.to_string());
1123 ffi::SQLITE_ERROR
1124 }
1125 }
1126}
1127
1128unsafe extern "C" fn rust_close<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1129where
1130 C: VTabCursor,
1131{
1132 let cr = cursor.cast::<C>();
1133 drop(Box::from_raw(cr));
1134 ffi::SQLITE_OK
1135}
1136
1137unsafe extern "C" fn rust_filter<C>(
1138 cursor: *mut ffi::sqlite3_vtab_cursor,
1139 idx_num: c_int,
1140 idx_str: *const c_char,
1141 argc: c_int,
1142 argv: *mut *mut ffi::sqlite3_value,
1143) -> c_int
1144where
1145 C: VTabCursor,
1146{
1147 use std::ffi::CStr;
1148 use std::str;
1149 let idx_name = if idx_str.is_null() {
1150 None
1151 } else {
1152 let c_slice = CStr::from_ptr(idx_str).to_bytes();
1153 Some(str::from_utf8_unchecked(c_slice))
1154 };
1155 let args = slice::from_raw_parts_mut(argv, argc as usize);
1156 let values = Values { args };
1157 let cr = cursor as *mut C;
1158 cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values))
1159}
1160
1161unsafe extern "C" fn rust_next<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1162where
1163 C: VTabCursor,
1164{
1165 let cr = cursor as *mut C;
1166 cursor_error(cursor, (*cr).next())
1167}
1168
1169unsafe extern "C" fn rust_eof<C>(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int
1170where
1171 C: VTabCursor,
1172{
1173 let cr = cursor.cast::<C>();
1174 (*cr).eof() as c_int
1175}
1176
1177unsafe extern "C" fn rust_column<C>(
1178 cursor: *mut ffi::sqlite3_vtab_cursor,
1179 ctx: *mut ffi::sqlite3_context,
1180 i: c_int,
1181) -> c_int
1182where
1183 C: VTabCursor,
1184{
1185 let cr = cursor.cast::<C>();
1186 let mut ctxt = Context(ctx);
1187 result_error(ctx, (*cr).column(&mut ctxt, i))
1188}
1189
1190unsafe extern "C" fn rust_rowid<C>(
1191 cursor: *mut ffi::sqlite3_vtab_cursor,
1192 p_rowid: *mut ffi::sqlite3_int64,
1193) -> c_int
1194where
1195 C: VTabCursor,
1196{
1197 let cr = cursor.cast::<C>();
1198 match (*cr).rowid() {
1199 Ok(rowid) => {
1200 *p_rowid = rowid;
1201 ffi::SQLITE_OK
1202 }
1203 err => cursor_error(cursor, err),
1204 }
1205}
1206
1207unsafe extern "C" fn rust_update<'vtab, T: 'vtab>(
1208 vtab: *mut ffi::sqlite3_vtab,
1209 argc: c_int,
1210 argv: *mut *mut ffi::sqlite3_value,
1211 p_rowid: *mut ffi::sqlite3_int64,
1212) -> c_int
1213where
1214 T: UpdateVTab<'vtab>,
1215{
1216 assert!(argc >= 1);
1217 let args = slice::from_raw_parts_mut(argv, argc as usize);
1218 let vt = vtab.cast::<T>();
1219 let r = if args.len() == 1 {
1220 (*vt).delete(ValueRef::from_value(args[0]))
1221 } else if ffi::sqlite3_value_type(args[0]) == ffi::SQLITE_NULL {
1222 let values = Values { args };
1224 match (*vt).insert(&values) {
1225 Ok(rowid) => {
1226 *p_rowid = rowid;
1227 Ok(())
1228 }
1229 Err(e) => Err(e),
1230 }
1231 } else {
1232 let values = Values { args };
1233 (*vt).update(&values)
1234 };
1235 match r {
1236 Ok(_) => ffi::SQLITE_OK,
1237 Err(Error::SqliteFailure(err, s)) => {
1238 if let Some(err_msg) = s {
1239 set_err_msg(vtab, &err_msg);
1240 }
1241 err.extended_code
1242 }
1243 Err(err) => {
1244 set_err_msg(vtab, &err.to_string());
1245 ffi::SQLITE_ERROR
1246 }
1247 }
1248}
1249
1250#[cold]
1253unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int {
1254 match result {
1255 Ok(_) => ffi::SQLITE_OK,
1256 Err(Error::SqliteFailure(err, s)) => {
1257 if let Some(err_msg) = s {
1258 set_err_msg((*cursor).pVtab, &err_msg);
1259 }
1260 err.extended_code
1261 }
1262 Err(err) => {
1263 set_err_msg((*cursor).pVtab, &err.to_string());
1264 ffi::SQLITE_ERROR
1265 }
1266 }
1267}
1268
1269#[cold]
1272unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
1273 if !(*vtab).zErrMsg.is_null() {
1274 ffi::sqlite3_free((*vtab).zErrMsg.cast::<c_void>());
1275 }
1276 (*vtab).zErrMsg = alloc(err_msg);
1277}
1278
1279#[cold]
1282unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
1283 match result {
1284 Ok(_) => ffi::SQLITE_OK,
1285 Err(Error::SqliteFailure(err, s)) => {
1286 match err.extended_code {
1287 ffi::SQLITE_TOOBIG => {
1288 ffi::sqlite3_result_error_toobig(ctx);
1289 }
1290 ffi::SQLITE_NOMEM => {
1291 ffi::sqlite3_result_error_nomem(ctx);
1292 }
1293 code => {
1294 ffi::sqlite3_result_error_code(ctx, code);
1295 if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
1296 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1297 }
1298 }
1299 };
1300 err.extended_code
1301 }
1302 Err(err) => {
1303 ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_ERROR);
1304 if let Ok(cstr) = str_to_cstring(&err.to_string()) {
1305 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1306 }
1307 ffi::SQLITE_ERROR
1308 }
1309 }
1310}
1311
1312fn alloc(s: &str) -> *mut c_char {
1315 crate::util::SqliteMallocString::from_str(s).into_raw()
1316}
1317
1318#[cfg(feature = "array")]
1319#[cfg_attr(docsrs, doc(cfg(feature = "array")))]
1320pub mod array;
1321#[cfg(feature = "csvtab")]
1322#[cfg_attr(docsrs, doc(cfg(feature = "csvtab")))]
1323pub mod csvtab;
1324#[cfg(feature = "series")]
1325#[cfg_attr(docsrs, doc(cfg(feature = "series")))]
1326pub mod series; #[cfg(all(test, feature = "modern_sqlite"))]
1328mod vtablog;
1329
1330#[cfg(test)]
1331mod test {
1332 #[test]
1333 fn test_dequote() {
1334 assert_eq!("", super::dequote(""));
1335 assert_eq!("'", super::dequote("'"));
1336 assert_eq!("\"", super::dequote("\""));
1337 assert_eq!("'\"", super::dequote("'\""));
1338 assert_eq!("", super::dequote("''"));
1339 assert_eq!("", super::dequote("\"\""));
1340 assert_eq!("x", super::dequote("'x'"));
1341 assert_eq!("x", super::dequote("\"x\""));
1342 assert_eq!("x", super::dequote("x"));
1343 }
1344 #[test]
1345 fn test_parse_boolean() {
1346 assert_eq!(None, super::parse_boolean(""));
1347 assert_eq!(Some(true), super::parse_boolean("1"));
1348 assert_eq!(Some(true), super::parse_boolean("yes"));
1349 assert_eq!(Some(true), super::parse_boolean("on"));
1350 assert_eq!(Some(true), super::parse_boolean("true"));
1351 assert_eq!(Some(false), super::parse_boolean("0"));
1352 assert_eq!(Some(false), super::parse_boolean("no"));
1353 assert_eq!(Some(false), super::parse_boolean("off"));
1354 assert_eq!(Some(false), super::parse_boolean("false"));
1355 }
1356}