1use std::borrow::Cow::{self, Borrowed, Owned};
13use std::ffi::{c_char, c_int, c_void, CStr};
14use std::marker::PhantomData;
15use std::ops::Deref;
16use std::ptr;
17use std::slice;
18
19use crate::ffi::sqlite3_free;
20
21use crate::context::set_result;
22use crate::error::{check, error_from_sqlite_code, to_sqlite_error};
23use crate::ffi;
24pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor};
25use crate::types::{FromSql, FromSqlError, ToSql, ValueRef};
26use crate::util::{alloc, free_boxed_value};
27use crate::{str_to_cstring, Connection, Error, InnerConnection, Name, Result};
28
29pub enum VTabKind {
65 Default,
67 Eponymous,
71 EponymousOnly,
78}
79
80#[repr(transparent)]
84pub struct Module<'vtab, T: VTab<'vtab>> {
85 base: ffi::sqlite3_module,
86 phantom: PhantomData<&'vtab T>,
87}
88
89union ModuleZeroHack {
90 bytes: [u8; 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; size_of::<ffi::sqlite3_module>()],
100 }
101 .module
102};
103
104macro_rules! module {
105 ($lt:lifetime, $vt:ty, $ct:ty, $xcreate:expr, $xdestroy:expr, $xupdate:expr,
106 $xbegin:expr, $xsync:expr, $xcommit:expr, $xrollback:expr) => {
107 &Module {
108 base: ffi::sqlite3_module {
109 iVersion: 1,
111 xCreate: $xcreate,
112 xConnect: Some(rust_connect::<$vt>),
113 xBestIndex: Some(rust_best_index::<$vt>),
114 xDisconnect: Some(rust_disconnect::<$vt>),
115 xDestroy: $xdestroy,
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: $xupdate,
124 xBegin: $xbegin,
125 xSync: $xsync,
126 xCommit: $xcommit,
127 xRollback: $xrollback,
128 xFindFunction: None,
129 xRename: None,
130 ..ZERO_MODULE
131 },
132 phantom: PhantomData::<&$lt $vt>,
133 }
134 };
135}
136
137#[must_use]
141pub fn update_module<'vtab, T: UpdateVTab<'vtab>>() -> &'static Module<'vtab, T> {
142 match T::KIND {
143 VTabKind::EponymousOnly => {
144 module!('vtab, T, T::Cursor, None, None, Some(rust_update::<T>), None, None, None, None)
145 }
146 VTabKind::Eponymous => {
147 module!('vtab, T, T::Cursor, Some(rust_connect::<T>), Some(rust_disconnect::<T>), Some(rust_update::<T>), None, None, None, None)
148 }
149 _ => {
150 module!('vtab, T, T::Cursor, Some(rust_create::<T>), Some(rust_destroy::<T>), Some(rust_update::<T>), None, None, None, None)
151 }
152 }
153}
154
155#[must_use]
159pub fn update_module_with_tx<'vtab, T: TransactionVTab<'vtab>>() -> &'static Module<'vtab, T> {
160 match T::KIND {
161 VTabKind::EponymousOnly => {
162 module!('vtab, T, T::Cursor, None, None, Some(rust_update::<T>), Some(rust_begin::<T>), Some(rust_sync::<T>), Some(rust_commit::<T>), Some(rust_rollback::<T>))
163 }
164 VTabKind::Eponymous => {
165 module!('vtab, T, T::Cursor, Some(rust_connect::<T>), Some(rust_disconnect::<T>), Some(rust_update::<T>), Some(rust_begin::<T>), Some(rust_sync::<T>), Some(rust_commit::<T>), Some(rust_rollback::<T>))
166 }
167 _ => {
168 module!('vtab, T, T::Cursor, Some(rust_create::<T>), Some(rust_destroy::<T>), Some(rust_update::<T>), Some(rust_begin::<T>), Some(rust_sync::<T>), Some(rust_commit::<T>), Some(rust_rollback::<T>))
169 }
170 }
171}
172
173#[must_use]
177pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> {
178 match T::KIND {
179 VTabKind::EponymousOnly => eponymous_only_module(),
180 VTabKind::Eponymous => {
181 module!('vtab, T, T::Cursor, Some(rust_connect::<T>), Some(rust_disconnect::<T>), None, None, None, None, None)
184 }
185 _ => {
186 module!('vtab, T, T::Cursor, Some(rust_create::<T>), Some(rust_destroy::<T>), None, None, None, None, None)
189 }
190 }
191}
192
193#[must_use]
197pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> {
198 module!('vtab, T, T::Cursor, None, None, None, None, None, None, None)
200}
201
202#[repr(i32)]
204#[non_exhaustive]
205#[derive(Debug, Clone, Copy, Eq, PartialEq)]
206pub enum VTabConfig {
207 ConstraintSupport = 1,
209 Innocuous = 2,
211 DirectOnly = 3,
213 UsesAllSchemas = 4,
215}
216
217pub struct VTabConnection(*mut ffi::sqlite3);
219
220impl VTabConnection {
221 pub fn config(&mut self, config: VTabConfig) -> Result<()> {
223 check(unsafe { ffi::sqlite3_vtab_config(self.0, config as c_int) })
224 }
225
226 pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
240 self.0
241 }
242}
243
244pub unsafe trait VTab<'vtab>: Sized {
262 type Aux: Send + Sync + 'static;
264 type Cursor: VTabCursor;
266
267 fn connect(
271 db: &mut VTabConnection,
272 aux: Option<&Self::Aux>,
273 args: &[&[u8]],
274 ) -> Result<(String, Self)>;
275
276 fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
279
280 fn open(&'vtab mut self) -> Result<Self::Cursor>;
283}
284
285pub trait CreateVTab<'vtab>: VTab<'vtab> {
289 const KIND: VTabKind;
293 fn create(
301 db: &mut VTabConnection,
302 aux: Option<&Self::Aux>,
303 args: &[&[u8]],
304 ) -> Result<(String, Self)> {
305 Self::connect(db, aux, args)
306 }
307
308 fn destroy(&self) -> Result<()> {
314 Ok(())
315 }
316}
317
318pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
322 fn delete(&mut self, arg: ValueRef<'_>) -> Result<()>;
324 fn insert(&mut self, args: &Inserts<'_>) -> Result<i64>;
330 fn update(&mut self, args: &Updates<'_>) -> Result<()>;
333}
334
335pub trait TransactionVTab<'vtab>: UpdateVTab<'vtab> {
339 fn begin(&mut self) -> Result<()> {
341 Ok(())
342 }
343 fn sync(&mut self) -> Result<()> {
345 Ok(())
346 }
347 fn commit(&mut self) -> Result<()> {
349 Ok(())
350 }
351 fn rollback(&mut self) -> Result<()> {
353 Ok(())
354 }
355}
356
357#[derive(Debug, Eq, PartialEq)]
360#[allow(missing_docs)]
361#[expect(non_camel_case_types)]
362pub enum IndexConstraintOp {
363 SQLITE_INDEX_CONSTRAINT_EQ,
364 SQLITE_INDEX_CONSTRAINT_GT,
365 SQLITE_INDEX_CONSTRAINT_LE,
366 SQLITE_INDEX_CONSTRAINT_LT,
367 SQLITE_INDEX_CONSTRAINT_GE,
368 SQLITE_INDEX_CONSTRAINT_MATCH,
369 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), }
381
382impl From<u8> for IndexConstraintOp {
383 fn from(code: u8) -> Self {
384 match code {
385 2 => Self::SQLITE_INDEX_CONSTRAINT_EQ,
386 4 => Self::SQLITE_INDEX_CONSTRAINT_GT,
387 8 => Self::SQLITE_INDEX_CONSTRAINT_LE,
388 16 => Self::SQLITE_INDEX_CONSTRAINT_LT,
389 32 => Self::SQLITE_INDEX_CONSTRAINT_GE,
390 64 => Self::SQLITE_INDEX_CONSTRAINT_MATCH,
391 65 => Self::SQLITE_INDEX_CONSTRAINT_LIKE,
392 66 => Self::SQLITE_INDEX_CONSTRAINT_GLOB,
393 67 => Self::SQLITE_INDEX_CONSTRAINT_REGEXP,
394 68 => Self::SQLITE_INDEX_CONSTRAINT_NE,
395 69 => Self::SQLITE_INDEX_CONSTRAINT_ISNOT,
396 70 => Self::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
397 71 => Self::SQLITE_INDEX_CONSTRAINT_ISNULL,
398 72 => Self::SQLITE_INDEX_CONSTRAINT_IS,
399 73 => Self::SQLITE_INDEX_CONSTRAINT_LIMIT,
400 74 => Self::SQLITE_INDEX_CONSTRAINT_OFFSET,
401 v => Self::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
402 }
403 }
404}
405
406bitflags::bitflags! {
407 #[repr(C)]
410 #[derive(Copy, Clone, Debug)]
411 pub struct IndexFlags: c_int {
412 const NONE = 0;
414 const SQLITE_INDEX_SCAN_UNIQUE = ffi::SQLITE_INDEX_SCAN_UNIQUE;
416 const SQLITE_INDEX_SCAN_HEX = 0x0000_0002; }
419}
420
421#[derive(Debug)]
426pub struct IndexInfo(*mut ffi::sqlite3_index_info);
427
428impl IndexInfo {
429 #[inline]
431 pub fn constraints_and_usages(&mut self) -> IndexConstraintAndUsageIter<'_> {
432 let constraints =
433 unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
434 let constraint_usages = unsafe {
435 slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
436 };
437 IndexConstraintAndUsageIter {
438 iter: constraints.iter().zip(constraint_usages.iter_mut()),
439 }
440 }
441
442 #[inline]
444 #[must_use]
445 pub fn constraints(&self) -> IndexConstraintIter<'_> {
446 let constraints =
447 unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
448 IndexConstraintIter {
449 iter: constraints.iter(),
450 }
451 }
452
453 #[inline]
455 #[must_use]
456 pub fn order_bys(&self) -> OrderByIter<'_> {
457 let order_bys =
458 unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
459 OrderByIter {
460 iter: order_bys.iter(),
461 }
462 }
463
464 #[inline]
466 #[must_use]
467 pub fn num_of_order_by(&self) -> usize {
468 unsafe { (*self.0).nOrderBy as usize }
469 }
470
471 #[inline]
473 pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
474 let constraint_usages = unsafe {
475 slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
476 };
477 IndexConstraintUsage(&mut constraint_usages[constraint_idx])
478 }
479
480 #[inline]
482 pub fn set_idx_num(&mut self, idx_num: c_int) {
483 unsafe {
484 (*self.0).idxNum = idx_num;
485 }
486 }
487
488 pub fn set_idx_str(&mut self, idx_str: &str) {
490 unsafe {
491 if (*self.0).needToFreeIdxStr == 1 {
492 sqlite3_free((*self.0).idxStr as _);
493 }
494 (*self.0).idxStr = alloc(idx_str);
495 (*self.0).needToFreeIdxStr = 1;
496 }
497 }
498 pub fn set_idx_cstr(&mut self, idx_str: &'static CStr) {
500 unsafe {
501 if (*self.0).needToFreeIdxStr == 1 {
502 sqlite3_free((*self.0).idxStr as _);
503 }
504 (*self.0).idxStr = idx_str.as_ptr() as _;
505 (*self.0).needToFreeIdxStr = 0;
506 }
507 }
508
509 #[inline]
511 pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
512 unsafe {
513 (*self.0).orderByConsumed = order_by_consumed as c_int;
514 }
515 }
516
517 #[inline]
519 pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
520 unsafe {
521 (*self.0).estimatedCost = estimated_ost;
522 }
523 }
524
525 #[inline]
527 pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
528 unsafe {
529 (*self.0).estimatedRows = estimated_rows;
530 }
531 }
532
533 #[inline]
535 pub fn set_idx_flags(&mut self, flags: IndexFlags) {
536 unsafe { (*self.0).idxFlags = flags.bits() };
537 }
538
539 #[inline]
541 pub fn col_used(&self) -> u64 {
542 unsafe { (*self.0).colUsed }
543 }
544
545 pub fn collation(&self, constraint_idx: usize) -> Result<&str> {
547 let idx = constraint_idx as c_int;
548 let collation = unsafe { ffi::sqlite3_vtab_collation(self.0, idx) };
549 if collation.is_null() {
550 return Err(err!(ffi::SQLITE_MISUSE, "{constraint_idx} is out of range"));
551 }
552 Ok(unsafe { CStr::from_ptr(collation) }.to_str()?)
553 }
554
555 #[must_use]
557 #[cfg(feature = "modern_sqlite")] pub fn distinct(&self) -> DistinctMode {
559 match unsafe { ffi::sqlite3_vtab_distinct(self.0) } {
560 0 => DistinctMode::Ordered,
561 1 => DistinctMode::Grouped,
562 2 => DistinctMode::Distinct,
563 3 => DistinctMode::DistinctOrdered,
564 _ => DistinctMode::Ordered,
565 }
566 }
567
568 #[cfg(feature = "modern_sqlite")] pub fn rhs_value(&self, constraint_idx: usize) -> Result<Option<ValueRef<'_>>> {
571 let idx = constraint_idx as c_int;
572 let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
573 let rc = unsafe { ffi::sqlite3_vtab_rhs_value(self.0, idx, &mut p_value) };
574 if rc == ffi::SQLITE_NOTFOUND {
575 return Ok(None);
576 }
577 check(rc)?;
578 assert!(!p_value.is_null());
579 Ok(Some(unsafe { ValueRef::from_value(p_value) }))
580 }
581
582 #[cfg(feature = "modern_sqlite")] pub fn is_in_constraint(&self, constraint_idx: usize) -> Result<bool> {
585 self.check_constraint_index(constraint_idx)?;
586 let idx = constraint_idx as c_int;
587 Ok(unsafe { ffi::sqlite3_vtab_in(self.0, idx, -1) != 0 })
588 }
589 #[cfg(feature = "modern_sqlite")] pub fn set_in_constraint(&mut self, constraint_idx: usize, filter_all: bool) -> Result<bool> {
592 self.check_constraint_index(constraint_idx)?;
593 let idx = constraint_idx as c_int;
594 Ok(unsafe { ffi::sqlite3_vtab_in(self.0, idx, filter_all as c_int) != 0 })
595 }
596
597 #[cfg(feature = "modern_sqlite")] fn check_constraint_index(&self, idx: usize) -> Result<()> {
599 if idx >= unsafe { (*self.0).nConstraint } as usize {
600 return Err(err!(ffi::SQLITE_MISUSE, "{idx} is out of range"));
601 }
602 Ok(())
603 }
604}
605
606#[non_exhaustive]
608#[derive(Debug, Eq, PartialEq)]
609pub enum DistinctMode {
610 Ordered,
612 Grouped,
614 Distinct,
616 DistinctOrdered,
618}
619
620pub struct IndexConstraintAndUsageIter<'a> {
622 iter: std::iter::Zip<
623 slice::Iter<'a, ffi::sqlite3_index_constraint>,
624 slice::IterMut<'a, ffi::sqlite3_index_constraint_usage>,
625 >,
626}
627
628impl<'a> Iterator for IndexConstraintAndUsageIter<'a> {
629 type Item = (IndexConstraint<'a>, IndexConstraintUsage<'a>);
630
631 #[inline]
632 fn next(&mut self) -> Option<(IndexConstraint<'a>, IndexConstraintUsage<'a>)> {
633 self.iter
634 .next()
635 .map(|raw| (IndexConstraint(raw.0), IndexConstraintUsage(raw.1)))
636 }
637
638 #[inline]
639 fn size_hint(&self) -> (usize, Option<usize>) {
640 self.iter.size_hint()
641 }
642}
643
644pub struct IndexConstraintIter<'a> {
646 iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
647}
648
649impl<'a> Iterator for IndexConstraintIter<'a> {
650 type Item = IndexConstraint<'a>;
651
652 #[inline]
653 fn next(&mut self) -> Option<IndexConstraint<'a>> {
654 self.iter.next().map(IndexConstraint)
655 }
656
657 #[inline]
658 fn size_hint(&self) -> (usize, Option<usize>) {
659 self.iter.size_hint()
660 }
661}
662
663pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
665
666impl IndexConstraint<'_> {
667 #[inline]
669 #[must_use]
670 pub fn column(&self) -> c_int {
671 self.0.iColumn
672 }
673
674 #[inline]
676 #[must_use]
677 pub fn operator(&self) -> IndexConstraintOp {
678 IndexConstraintOp::from(self.0.op)
679 }
680
681 #[inline]
683 #[must_use]
684 pub fn is_usable(&self) -> bool {
685 self.0.usable != 0
686 }
687}
688
689pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
692
693impl IndexConstraintUsage<'_> {
694 #[inline]
697 pub fn set_argv_index(&mut self, argv_index: c_int) {
698 self.0.argvIndex = argv_index;
699 }
700
701 #[inline]
703 pub fn set_omit(&mut self, omit: bool) {
704 self.0.omit = omit as std::ffi::c_uchar;
705 }
706}
707
708pub struct OrderByIter<'a> {
710 iter: slice::Iter<'a, ffi::sqlite3_index_orderby>,
711}
712
713impl<'a> Iterator for OrderByIter<'a> {
714 type Item = OrderBy<'a>;
715
716 #[inline]
717 fn next(&mut self) -> Option<OrderBy<'a>> {
718 self.iter.next().map(OrderBy)
719 }
720
721 #[inline]
722 fn size_hint(&self) -> (usize, Option<usize>) {
723 self.iter.size_hint()
724 }
725}
726
727pub struct OrderBy<'a>(&'a ffi::sqlite3_index_orderby);
729
730impl OrderBy<'_> {
731 #[inline]
733 #[must_use]
734 pub fn column(&self) -> c_int {
735 self.0.iColumn
736 }
737
738 #[inline]
740 #[must_use]
741 pub fn is_order_by_desc(&self) -> bool {
742 self.0.desc != 0
743 }
744}
745
746pub unsafe trait VTabCursor: Sized {
762 fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Filters<'_>) -> Result<()>;
765 fn next(&mut self) -> Result<()>;
768 fn eof(&self) -> bool;
772 fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
777 fn rowid(&self) -> Result<i64>;
780}
781
782pub struct Context(*mut ffi::sqlite3_context);
785
786impl Context {
787 #[inline]
789 pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
790 let t = value.to_sql()?;
791 unsafe { set_result(self.0, &[], &t) };
792 Ok(())
793 }
794
795 #[inline]
797 #[must_use]
798 pub fn no_change(&self) -> bool {
799 unsafe { ffi::sqlite3_vtab_nochange(self.0) != 0 }
800 }
801
802 pub unsafe fn get_connection(&self) -> Result<ConnectionRef<'_>> {
808 let handle = ffi::sqlite3_context_db_handle(self.0);
809 Ok(ConnectionRef {
810 conn: Connection::from_handle(handle)?,
811 phantom: PhantomData,
812 })
813 }
814}
815
816pub struct ConnectionRef<'ctx> {
818 conn: Connection,
821 phantom: PhantomData<&'ctx Context>,
822}
823
824impl Deref for ConnectionRef<'_> {
825 type Target = Connection;
826
827 #[inline]
828 fn deref(&self) -> &Connection {
829 &self.conn
830 }
831}
832
833pub struct Filters<'a> {
836 values: Values<'a>,
837}
838impl<'a> Deref for Filters<'a> {
839 type Target = Values<'a>;
840
841 fn deref(&self) -> &Self::Target {
842 &self.values
843 }
844}
845#[cfg(feature = "modern_sqlite")] impl<'a> Filters<'a> {
847 pub fn in_values(&self, idx: usize) -> Result<InValues<'_>> {
849 let list = self.args[idx];
850 Ok(InValues {
851 list,
852 phantom: PhantomData,
853 first: true,
854 })
855 }
856}
857
858#[cfg(feature = "modern_sqlite")] pub struct InValues<'a> {
861 list: *mut ffi::sqlite3_value,
862 phantom: PhantomData<Filters<'a>>,
863 first: bool,
864}
865#[cfg(feature = "modern_sqlite")] impl<'a> fallible_iterator::FallibleIterator for InValues<'a> {
867 type Error = Error;
868 type Item = ValueRef<'a>;
869
870 fn next(&mut self) -> Result<Option<Self::Item>> {
871 let mut val: *mut ffi::sqlite3_value = ptr::null_mut();
872 let rc = unsafe {
873 if self.first {
874 self.first = false;
875 ffi::sqlite3_vtab_in_first(self.list, &mut val)
876 } else {
877 ffi::sqlite3_vtab_in_next(self.list, &mut val)
878 }
879 };
880 match rc {
881 ffi::SQLITE_OK => Ok(Some(unsafe { ValueRef::from_value(val) })),
882 ffi::SQLITE_DONE => Ok(None),
883 _ => Err(error_from_sqlite_code(rc, None)),
884 }
885 }
886}
887
888pub struct Values<'a> {
890 args: &'a [*mut ffi::sqlite3_value],
891}
892
893impl Values<'_> {
894 #[inline]
896 #[must_use]
897 pub fn len(&self) -> usize {
898 self.args.len()
899 }
900
901 #[inline]
903 #[must_use]
904 pub fn is_empty(&self) -> bool {
905 self.args.is_empty()
906 }
907
908 pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
910 let arg = self.args[idx];
911 let value = unsafe { ValueRef::from_value(arg) };
912 FromSql::column_result(value).map_err(|err| match err {
913 FromSqlError::InvalidType => Error::InvalidFilterParameterType(idx, value.data_type()),
914 FromSqlError::Other(err) => {
915 Error::FromSqlConversionFailure(idx, value.data_type(), err)
916 }
917 FromSqlError::InvalidBlobSize { .. } => {
918 Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
919 }
920 FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
921 FromSqlError::Utf8Error(err) => Error::Utf8Error(idx, err),
922 })
923 }
924
925 #[cfg(feature = "pointer")]
931 pub unsafe fn get_pointer<'a, T: 'static>(
932 &self,
933 idx: usize,
934 ptr_type: &'static CStr,
935 ) -> Option<&'a T> {
936 let arg = self.args[idx];
937 debug_assert_eq!(unsafe { ffi::sqlite3_value_type(arg) }, ffi::SQLITE_NULL);
938 unsafe {
939 ffi::sqlite3_value_pointer(arg, ptr_type.as_ptr())
940 .cast::<T>()
941 .as_ref()
942 }
943 }
944
945 #[inline]
947 #[must_use]
948 pub fn iter(&self) -> ValueIter<'_> {
949 ValueIter {
950 iter: self.args.iter(),
951 }
952 }
953}
954
955impl<'a> IntoIterator for &'a Values<'a> {
956 type IntoIter = ValueIter<'a>;
957 type Item = ValueRef<'a>;
958
959 #[inline]
960 fn into_iter(self) -> ValueIter<'a> {
961 self.iter()
962 }
963}
964
965pub struct ValueIter<'a> {
967 iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
968}
969
970impl<'a> Iterator for ValueIter<'a> {
971 type Item = ValueRef<'a>;
972
973 #[inline]
974 fn next(&mut self) -> Option<ValueRef<'a>> {
975 self.iter
976 .next()
977 .map(|&raw| unsafe { ValueRef::from_value(raw) })
978 }
979
980 #[inline]
981 fn size_hint(&self) -> (usize, Option<usize>) {
982 self.iter.size_hint()
983 }
984}
985
986pub struct Inserts<'a> {
988 values: Values<'a>,
989}
990impl<'a> Deref for Inserts<'a> {
991 type Target = Values<'a>;
992
993 fn deref(&self) -> &Self::Target {
994 &self.values
995 }
996}
997impl Inserts<'_> {
998 #[must_use]
1003 pub unsafe fn on_conflict(&self, db: *mut ffi::sqlite3) -> ConflictMode {
1004 ConflictMode::from(unsafe { ffi::sqlite3_vtab_on_conflict(db) })
1005 }
1006}
1007
1008pub struct Updates<'a> {
1010 values: Values<'a>,
1011}
1012impl<'a> Deref for Updates<'a> {
1013 type Target = Values<'a>;
1014
1015 fn deref(&self) -> &Self::Target {
1016 &self.values
1017 }
1018}
1019impl Updates<'_> {
1020 #[inline]
1024 #[must_use]
1025 pub fn no_change(&self, idx: usize) -> bool {
1026 unsafe { ffi::sqlite3_value_nochange(self.values.args[idx]) != 0 }
1027 }
1028
1029 #[must_use]
1034 pub unsafe fn on_conflict(&self, db: *mut ffi::sqlite3) -> ConflictMode {
1035 ConflictMode::from(unsafe { ffi::sqlite3_vtab_on_conflict(db) })
1036 }
1037}
1038
1039#[non_exhaustive]
1041#[derive(Debug, Eq, PartialEq)]
1042pub enum ConflictMode {
1043 Rollback,
1045 Ignore,
1047 Fail,
1049 Abort,
1051 Replace,
1053}
1054impl From<c_int> for ConflictMode {
1055 fn from(value: c_int) -> Self {
1056 match value {
1057 ffi::SQLITE_ROLLBACK => ConflictMode::Rollback,
1058 ffi::SQLITE_IGNORE => ConflictMode::Ignore,
1059 ffi::SQLITE_FAIL => ConflictMode::Fail,
1060 ffi::SQLITE_ABORT => ConflictMode::Abort,
1061 ffi::SQLITE_REPLACE => ConflictMode::Replace,
1062 _ => unreachable!("sqlite3_vtab_on_conflict returned invalid value"),
1063 }
1064 }
1065}
1066
1067impl Connection {
1068 #[inline]
1073 pub fn create_module<'vtab, T: VTab<'vtab>, M: Name>(
1074 &self,
1075 module_name: M,
1076 module: &'static Module<'vtab, T>,
1077 aux: Option<T::Aux>,
1078 ) -> Result<()> {
1079 self.db.borrow_mut().create_module(module_name, module, aux)
1080 }
1081}
1082
1083impl InnerConnection {
1084 fn create_module<'vtab, T: VTab<'vtab>, M: Name>(
1085 &mut self,
1086 module_name: M,
1087 module: &'static Module<'vtab, T>,
1088 aux: Option<T::Aux>,
1089 ) -> Result<()> {
1090 use crate::version;
1091 if version::version_number() < 3_009_000 && module.base.xCreate.is_none() {
1092 return Err(Error::ModuleError(format!(
1093 "Eponymous-only virtual table not supported by SQLite version {}",
1094 version::version()
1095 )));
1096 }
1097 let c_name = module_name.as_cstr()?;
1098 let r = match aux {
1099 Some(aux) => {
1100 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
1101 unsafe {
1102 ffi::sqlite3_create_module_v2(
1103 self.db(),
1104 c_name.as_ptr(),
1105 &module.base,
1106 boxed_aux.cast::<c_void>(),
1107 Some(free_boxed_value::<T::Aux>),
1108 )
1109 }
1110 }
1111 None => unsafe {
1112 ffi::sqlite3_create_module_v2(
1113 self.db(),
1114 c_name.as_ptr(),
1115 &module.base,
1116 ptr::null_mut(),
1117 None,
1118 )
1119 },
1120 };
1121 self.decode_result(r)
1122 }
1123}
1124
1125#[must_use]
1128pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
1129 if identifier.contains('"') {
1130 Owned(identifier.replace('"', "\"\""))
1132 } else {
1133 Borrowed(identifier)
1134 }
1135}
1136#[must_use]
1138pub fn dequote(s: &str) -> &str {
1139 if s.len() < 2 {
1140 return s;
1141 }
1142 match s.bytes().next() {
1143 Some(b) if b == b'"' || b == b'\'' => match s.bytes().next_back() {
1144 Some(e) if e == b => &s[1..s.len() - 1], _ => s,
1146 },
1147 _ => s,
1148 }
1149}
1150#[must_use]
1156pub fn parse_boolean(s: &str) -> Option<bool> {
1157 if s.eq_ignore_ascii_case("yes")
1158 || s.eq_ignore_ascii_case("on")
1159 || s.eq_ignore_ascii_case("true")
1160 || s.eq("1")
1161 {
1162 Some(true)
1163 } else if s.eq_ignore_ascii_case("no")
1164 || s.eq_ignore_ascii_case("off")
1165 || s.eq_ignore_ascii_case("false")
1166 || s.eq("0")
1167 {
1168 Some(false)
1169 } else {
1170 None
1171 }
1172}
1173
1174pub fn parameter(c_slice: &[u8]) -> Result<(&str, &str)> {
1176 let arg = std::str::from_utf8(c_slice)?.trim();
1177 match arg.split_once('=') {
1178 Some((key, value)) => {
1179 let param = key.trim();
1180 let value = dequote(value.trim());
1181 Ok((param, value))
1182 }
1183 _ => Err(Error::ModuleError(format!("illegal argument: '{arg}'"))),
1184 }
1185}
1186
1187unsafe extern "C" fn rust_create<'vtab, T>(
1188 db: *mut ffi::sqlite3,
1189 aux: *mut c_void,
1190 argc: c_int,
1191 argv: *const *const c_char,
1192 pp_vtab: *mut *mut sqlite3_vtab,
1193 err_msg: *mut *mut c_char,
1194) -> c_int
1195where
1196 T: CreateVTab<'vtab>,
1197{
1198 let mut conn = VTabConnection(db);
1199 let aux = aux.cast::<T::Aux>();
1200 let args = slice::from_raw_parts(argv, argc as usize);
1201 let vec = args
1202 .iter()
1203 .map(|&cs| CStr::from_ptr(cs).to_bytes()) .collect::<Vec<_>>();
1205 match T::create(&mut conn, aux.as_ref(), &vec[..]) {
1206 Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
1207 Ok(c_sql) => {
1208 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
1209 if rc == ffi::SQLITE_OK {
1210 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1211 *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
1212 ffi::SQLITE_OK
1213 } else {
1214 let err = error_from_sqlite_code(rc, None);
1215 to_sqlite_error(&err, err_msg)
1216 }
1217 }
1218 Err(err) => {
1219 *err_msg = alloc(&err.to_string());
1220 ffi::SQLITE_ERROR
1221 }
1222 },
1223 Err(err) => to_sqlite_error(&err, err_msg),
1224 }
1225}
1226
1227unsafe extern "C" fn rust_connect<'vtab, T>(
1228 db: *mut ffi::sqlite3,
1229 aux: *mut c_void,
1230 argc: c_int,
1231 argv: *const *const c_char,
1232 pp_vtab: *mut *mut sqlite3_vtab,
1233 err_msg: *mut *mut c_char,
1234) -> c_int
1235where
1236 T: VTab<'vtab>,
1237{
1238 let mut conn = VTabConnection(db);
1239 let aux = aux.cast::<T::Aux>();
1240 let args = slice::from_raw_parts(argv, argc as usize);
1241 let vec = args
1242 .iter()
1243 .map(|&cs| CStr::from_ptr(cs).to_bytes()) .collect::<Vec<_>>();
1245 match T::connect(&mut conn, aux.as_ref(), &vec[..]) {
1246 Ok((sql, vtab)) => match std::ffi::CString::new(sql) {
1247 Ok(c_sql) => {
1248 let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
1249 if rc == ffi::SQLITE_OK {
1250 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1251 *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
1252 ffi::SQLITE_OK
1253 } else {
1254 let err = error_from_sqlite_code(rc, None);
1255 to_sqlite_error(&err, err_msg)
1256 }
1257 }
1258 Err(err) => {
1259 *err_msg = alloc(&err.to_string());
1260 ffi::SQLITE_ERROR
1261 }
1262 },
1263 Err(err) => to_sqlite_error(&err, err_msg),
1264 }
1265}
1266
1267unsafe extern "C" fn rust_best_index<'vtab, T>(
1268 vtab: *mut sqlite3_vtab,
1269 info: *mut ffi::sqlite3_index_info,
1270) -> c_int
1271where
1272 T: VTab<'vtab>,
1273{
1274 let vt = vtab.cast::<T>();
1275 let mut idx_info = IndexInfo(info);
1276 vtab_error(vtab, (*vt).best_index(&mut idx_info))
1277}
1278
1279unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1280where
1281 T: VTab<'vtab>,
1282{
1283 if vtab.is_null() {
1284 return ffi::SQLITE_OK;
1285 }
1286 let vtab = vtab.cast::<T>();
1287 drop(Box::from_raw(vtab));
1288 ffi::SQLITE_OK
1289}
1290
1291unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1292where
1293 T: CreateVTab<'vtab>,
1294{
1295 if vtab.is_null() {
1296 return ffi::SQLITE_OK;
1297 }
1298 let vt = vtab.cast::<T>();
1299 match (*vt).destroy() {
1300 Ok(_) => {
1301 drop(Box::from_raw(vt));
1302 ffi::SQLITE_OK
1303 }
1304 err => vtab_error(vtab, err),
1305 }
1306}
1307
1308unsafe extern "C" fn rust_open<'vtab, T>(
1309 vtab: *mut sqlite3_vtab,
1310 pp_cursor: *mut *mut sqlite3_vtab_cursor,
1311) -> c_int
1312where
1313 T: VTab<'vtab> + 'vtab,
1314{
1315 let vt = vtab.cast::<T>();
1316 match (*vt).open() {
1317 Ok(cursor) => {
1318 let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
1319 *pp_cursor = boxed_cursor.cast::<sqlite3_vtab_cursor>();
1320 ffi::SQLITE_OK
1321 }
1322 err => vtab_error(vtab, err),
1323 }
1324}
1325
1326unsafe extern "C" fn rust_close<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1327where
1328 C: VTabCursor,
1329{
1330 let cr = cursor.cast::<C>();
1331 drop(Box::from_raw(cr));
1332 ffi::SQLITE_OK
1333}
1334
1335unsafe extern "C" fn rust_filter<C>(
1336 cursor: *mut sqlite3_vtab_cursor,
1337 idx_num: c_int,
1338 idx_str: *const c_char,
1339 argc: c_int,
1340 argv: *mut *mut ffi::sqlite3_value,
1341) -> c_int
1342where
1343 C: VTabCursor,
1344{
1345 use std::str;
1346 let idx_name = if idx_str.is_null() {
1347 None
1348 } else {
1349 let c_slice = CStr::from_ptr(idx_str).to_bytes();
1350 Some(str::from_utf8_unchecked(c_slice))
1351 };
1352 let args = slice::from_raw_parts_mut(argv, argc as usize);
1353 let values = Values { args };
1354 let cr = cursor as *mut C;
1355 cursor_error(cursor, (*cr).filter(idx_num, idx_name, &Filters { values }))
1356}
1357
1358unsafe extern "C" fn rust_next<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1359where
1360 C: VTabCursor,
1361{
1362 let cr = cursor as *mut C;
1363 cursor_error(cursor, (*cr).next())
1364}
1365
1366unsafe extern "C" fn rust_eof<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1367where
1368 C: VTabCursor,
1369{
1370 let cr = cursor.cast::<C>();
1371 (*cr).eof() as c_int
1372}
1373
1374unsafe extern "C" fn rust_column<C>(
1375 cursor: *mut sqlite3_vtab_cursor,
1376 ctx: *mut ffi::sqlite3_context,
1377 i: c_int,
1378) -> c_int
1379where
1380 C: VTabCursor,
1381{
1382 let cr = cursor.cast::<C>();
1383 let mut ctxt = Context(ctx);
1384 result_error(ctx, (*cr).column(&mut ctxt, i))
1385}
1386
1387unsafe extern "C" fn rust_rowid<C>(
1388 cursor: *mut sqlite3_vtab_cursor,
1389 p_rowid: *mut ffi::sqlite3_int64,
1390) -> c_int
1391where
1392 C: VTabCursor,
1393{
1394 let cr = cursor.cast::<C>();
1395 match (*cr).rowid() {
1396 Ok(rowid) => {
1397 *p_rowid = rowid;
1398 ffi::SQLITE_OK
1399 }
1400 err => cursor_error(cursor, err),
1401 }
1402}
1403
1404unsafe extern "C" fn rust_update<'vtab, T>(
1405 vtab: *mut sqlite3_vtab,
1406 argc: c_int,
1407 argv: *mut *mut ffi::sqlite3_value,
1408 p_rowid: *mut ffi::sqlite3_int64,
1409) -> c_int
1410where
1411 T: UpdateVTab<'vtab> + 'vtab,
1412{
1413 assert!(argc >= 1);
1414 let args = slice::from_raw_parts_mut(argv, argc as usize);
1415 let vt = vtab.cast::<T>();
1416 let r = if args.len() == 1 {
1417 (*vt).delete(ValueRef::from_value(args[0]))
1418 } else if ffi::sqlite3_value_type(args[0]) == ffi::SQLITE_NULL {
1419 let values = Values { args };
1421 match (*vt).insert(&Inserts { values }) {
1422 Ok(rowid) => {
1423 *p_rowid = rowid;
1424 Ok(())
1425 }
1426 Err(e) => Err(e),
1427 }
1428 } else {
1429 let values = Values { args };
1430 (*vt).update(&Updates { values })
1431 };
1432 vtab_error(vtab, r)
1433}
1434
1435unsafe extern "C" fn rust_begin<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1436where
1437 T: TransactionVTab<'vtab>,
1438{
1439 let vt = vtab.cast::<T>();
1440 vtab_error(vtab, (*vt).begin())
1441}
1442unsafe extern "C" fn rust_sync<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1443where
1444 T: TransactionVTab<'vtab>,
1445{
1446 let vt = vtab.cast::<T>();
1447 vtab_error(vtab, (*vt).sync())
1448}
1449unsafe extern "C" fn rust_commit<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1450where
1451 T: TransactionVTab<'vtab>,
1452{
1453 let vt = vtab.cast::<T>();
1454 vtab_error(vtab, (*vt).commit())
1455}
1456unsafe extern "C" fn rust_rollback<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1457where
1458 T: TransactionVTab<'vtab>,
1459{
1460 let vt = vtab.cast::<T>();
1461 vtab_error(vtab, (*vt).rollback())
1462}
1463
1464unsafe fn cursor_error<T>(cursor: *mut sqlite3_vtab_cursor, result: Result<T>) -> c_int {
1467 vtab_error((*cursor).pVtab, result)
1468}
1469
1470unsafe fn vtab_error<T>(vtab: *mut sqlite3_vtab, result: Result<T>) -> c_int {
1473 match result {
1474 Ok(_) => ffi::SQLITE_OK,
1475 Err(Error::SqliteFailure(err, s)) => {
1476 if let Some(err_msg) = s {
1477 set_err_msg(vtab, &err_msg);
1478 }
1479 err.extended_code
1480 }
1481 Err(err) => {
1482 set_err_msg(vtab, &err.to_string());
1483 ffi::SQLITE_ERROR
1484 }
1485 }
1486}
1487
1488#[cold]
1491unsafe fn set_err_msg(vtab: *mut sqlite3_vtab, err_msg: &str) {
1492 if !(*vtab).zErrMsg.is_null() {
1493 ffi::sqlite3_free((*vtab).zErrMsg.cast::<c_void>());
1494 }
1495 (*vtab).zErrMsg = alloc(err_msg);
1496}
1497
1498#[cold]
1501unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
1502 match result {
1503 Ok(_) => ffi::SQLITE_OK,
1504 Err(Error::SqliteFailure(err, s)) => {
1505 match err.extended_code {
1506 ffi::SQLITE_TOOBIG => {
1507 ffi::sqlite3_result_error_toobig(ctx);
1508 }
1509 ffi::SQLITE_NOMEM => {
1510 ffi::sqlite3_result_error_nomem(ctx);
1511 }
1512 code => {
1513 ffi::sqlite3_result_error_code(ctx, code);
1514 if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
1515 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1516 }
1517 }
1518 };
1519 err.extended_code
1520 }
1521 Err(err) => {
1522 ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_ERROR);
1523 if let Ok(cstr) = str_to_cstring(&err.to_string()) {
1524 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1525 }
1526 ffi::SQLITE_ERROR
1527 }
1528 }
1529}
1530
1531#[cfg(feature = "array")]
1532pub mod array;
1533#[cfg(feature = "csvtab")]
1534pub mod csvtab;
1535#[cfg(feature = "series")]
1536pub mod series; #[cfg(all(test, feature = "modern_sqlite"))]
1538mod vtablog;
1539
1540#[cfg(test)]
1541mod test {
1542 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1543 use wasm_bindgen_test::wasm_bindgen_test as test;
1544
1545 #[test]
1546 fn test_dequote() {
1547 assert_eq!("", super::dequote(""));
1548 assert_eq!("'", super::dequote("'"));
1549 assert_eq!("\"", super::dequote("\""));
1550 assert_eq!("'\"", super::dequote("'\""));
1551 assert_eq!("", super::dequote("''"));
1552 assert_eq!("", super::dequote("\"\""));
1553 assert_eq!("x", super::dequote("'x'"));
1554 assert_eq!("x", super::dequote("\"x\""));
1555 assert_eq!("x", super::dequote("x"));
1556 }
1557 #[test]
1558 fn test_parse_boolean() {
1559 assert_eq!(None, super::parse_boolean(""));
1560 assert_eq!(Some(true), super::parse_boolean("1"));
1561 assert_eq!(Some(true), super::parse_boolean("yes"));
1562 assert_eq!(Some(true), super::parse_boolean("on"));
1563 assert_eq!(Some(true), super::parse_boolean("true"));
1564 assert_eq!(Some(false), super::parse_boolean("0"));
1565 assert_eq!(Some(false), super::parse_boolean("no"));
1566 assert_eq!(Some(false), super::parse_boolean("off"));
1567 assert_eq!(Some(false), super::parse_boolean("false"));
1568 }
1569 #[test]
1570 fn test_parse_parameters() {
1571 assert_eq!(Ok(("key", "value")), super::parameter(b"key='value'"));
1572 assert_eq!(Ok(("key", "foo=bar")), super::parameter(b"key='foo=bar'"));
1573 }
1574}