1use std::borrow::Cow::{self, Borrowed, Owned};
13use std::ffi::{CStr, c_char, c_int, c_uint, c_void};
14use std::marker::PhantomData;
15use std::ops::Deref;
16use std::ptr;
17use std::slice;
18
19use crate::ffi::{sqlite3_context, sqlite3_free, sqlite3_value};
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, from_raw_parts, from_raw_parts_mut};
27use crate::{Connection, Error, InnerConnection, Name, Result, str_to_cstring};
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
104impl<'vtab, T: VTab<'vtab>> Module<'vtab, T> {
105 #[must_use]
109 pub const fn eponymous_only_module() -> Self {
110 Module {
112 base: ffi::sqlite3_module {
113 iVersion: 1,
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 ..ZERO_MODULE
135 },
136 phantom: PhantomData::<&'vtab T>,
137 }
138 }
139
140 #[must_use]
144 pub const fn read_only_module() -> Self
145 where
146 T: CreateVTab<'vtab>,
147 {
148 let mut module = Self::eponymous_only_module();
149 match T::KIND {
150 VTabKind::EponymousOnly => module,
151 VTabKind::Eponymous => {
152 module.base.xCreate = module.base.xConnect;
155 module.base.xDestroy = module.base.xDisconnect;
156 module
157 }
158 _ => {
159 module.base.xCreate = Some(rust_create::<T>);
162 module.base.xDestroy = Some(rust_destroy::<T>);
163 module
164 }
165 }
166 }
167
168 #[must_use]
172 pub const fn update_module() -> Self
173 where
174 T: UpdateVTab<'vtab>,
175 {
176 let mut module = Self::read_only_module();
177 module.base.xUpdate = Some(rust_update::<T>);
178 module
179 }
180
181 #[must_use]
185 pub const fn update_module_with_tx() -> Self
186 where
187 T: TransactionVTab<'vtab>,
188 {
189 let mut module = Self::update_module();
190 module.base.xBegin = Some(rust_begin::<T>);
191 module.base.xSync = Some(rust_sync::<T>);
192 module.base.xCommit = Some(rust_commit::<T>);
193 module.base.xRollback = Some(rust_rollback::<T>);
194 module
195 }
196
197 #[must_use]
199 pub const fn without_rowid(mut self) -> Self {
200 self.base.xRowid = None;
201 self
202 }
203
204 #[must_use]
206 pub const fn without_sync(mut self) -> Self
207 where
208 T: TransactionVTab<'vtab>,
209 {
210 self.base.xSync = None;
211 self
212 }
213}
214
215#[repr(i32)]
217#[non_exhaustive]
218#[derive(Debug, Clone, Copy, Eq, PartialEq)]
219pub enum VTabConfig {
220 ConstraintSupport = 1,
222 Innocuous = 2,
224 DirectOnly = 3,
226 UsesAllSchemas = 4,
228}
229
230pub struct VTabConnection(*mut ffi::sqlite3);
232
233impl VTabConnection {
234 pub fn config(&mut self, config: VTabConfig) -> Result<()> {
236 check(unsafe { ffi::sqlite3_vtab_config(self.0, config as c_int) })
237 }
238
239 pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
253 self.0
254 }
255}
256
257pub unsafe trait VTab<'vtab>: Sized {
275 type Aux: Send + Sync + 'static;
277 type Cursor: VTabCursor;
279
280 fn connect(
284 db: &mut VTabConnection,
285 aux: Option<&Self::Aux>,
286 module_name: &[u8],
287 database_name: &[u8],
288 table_name: &[u8],
289 args: &[&[u8]],
290 ) -> Result<(Cow<'static, CStr>, Self)>;
291
292 fn best_index(&self, info: &mut IndexInfo) -> Result<bool>;
296
297 fn open(&'vtab mut self) -> Result<Self::Cursor>;
300}
301
302pub trait CreateVTab<'vtab>: VTab<'vtab> {
306 const KIND: VTabKind;
310 fn create(
318 db: &mut VTabConnection,
319 aux: Option<&Self::Aux>,
320 module_name: &[u8],
321 database_name: &[u8],
322 table_name: &[u8],
323 args: &[&[u8]],
324 ) -> Result<(Cow<'static, CStr>, Self)> {
325 Self::connect(db, aux, module_name, database_name, table_name, args)
326 }
327
328 fn destroy(&self) -> Result<()> {
334 Ok(())
335 }
336}
337
338pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
342 fn delete(&mut self, arg: ValueRef<'_>) -> Result<()>;
344 fn insert(&mut self, args: &Inserts<'_>) -> Result<i64>;
350 fn update(&mut self, args: &Updates<'_>) -> Result<()>;
353}
354
355pub trait TransactionVTab<'vtab>: UpdateVTab<'vtab> {
359 fn begin(&mut self) -> Result<()> {
361 Ok(())
362 }
363 fn sync(&mut self) -> Result<()> {
365 Ok(())
366 }
367 fn commit(&mut self) -> Result<()> {
369 Ok(())
370 }
371 fn rollback(&mut self) -> Result<()> {
373 Ok(())
374 }
375}
376
377#[derive(Debug, Eq, PartialEq)]
380#[allow(missing_docs)]
381#[expect(non_camel_case_types)]
382pub enum IndexConstraintOp {
383 SQLITE_INDEX_CONSTRAINT_EQ,
384 SQLITE_INDEX_CONSTRAINT_GT,
385 SQLITE_INDEX_CONSTRAINT_LE,
386 SQLITE_INDEX_CONSTRAINT_LT,
387 SQLITE_INDEX_CONSTRAINT_GE,
388 SQLITE_INDEX_CONSTRAINT_MATCH,
389 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), }
401
402impl From<u8> for IndexConstraintOp {
403 fn from(code: u8) -> Self {
404 match code {
405 2 => Self::SQLITE_INDEX_CONSTRAINT_EQ,
406 4 => Self::SQLITE_INDEX_CONSTRAINT_GT,
407 8 => Self::SQLITE_INDEX_CONSTRAINT_LE,
408 16 => Self::SQLITE_INDEX_CONSTRAINT_LT,
409 32 => Self::SQLITE_INDEX_CONSTRAINT_GE,
410 64 => Self::SQLITE_INDEX_CONSTRAINT_MATCH,
411 65 => Self::SQLITE_INDEX_CONSTRAINT_LIKE,
412 66 => Self::SQLITE_INDEX_CONSTRAINT_GLOB,
413 67 => Self::SQLITE_INDEX_CONSTRAINT_REGEXP,
414 68 => Self::SQLITE_INDEX_CONSTRAINT_NE,
415 69 => Self::SQLITE_INDEX_CONSTRAINT_ISNOT,
416 70 => Self::SQLITE_INDEX_CONSTRAINT_ISNOTNULL,
417 71 => Self::SQLITE_INDEX_CONSTRAINT_ISNULL,
418 72 => Self::SQLITE_INDEX_CONSTRAINT_IS,
419 73 => Self::SQLITE_INDEX_CONSTRAINT_LIMIT,
420 74 => Self::SQLITE_INDEX_CONSTRAINT_OFFSET,
421 v => Self::SQLITE_INDEX_CONSTRAINT_FUNCTION(v),
422 }
423 }
424}
425
426bitflags::bitflags! {
427 #[repr(C)]
430 #[derive(Copy, Clone, Debug)]
431 pub struct IndexFlags: c_int {
432 const NONE = 0;
434 const SQLITE_INDEX_SCAN_UNIQUE = ffi::SQLITE_INDEX_SCAN_UNIQUE;
436 const SQLITE_INDEX_SCAN_HEX = 0x0000_0002; }
439}
440
441#[derive(Debug)]
446pub struct IndexInfo(*mut ffi::sqlite3_index_info);
447
448impl IndexInfo {
449 #[inline]
451 pub fn constraints_and_usages(&mut self) -> IndexConstraintAndUsageIter<'_> {
452 let constraints = unsafe { from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint) };
453 let constraint_usages =
454 unsafe { from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint) };
455 IndexConstraintAndUsageIter {
456 iter: constraints.iter().zip(constraint_usages.iter_mut()),
457 }
458 }
459
460 #[inline]
462 #[must_use]
463 pub fn constraints(&self) -> IndexConstraintIter<'_> {
464 let constraints = unsafe { from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint) };
465 IndexConstraintIter {
466 iter: constraints.iter(),
467 }
468 }
469
470 #[inline]
472 #[must_use]
473 pub fn order_bys(&self) -> OrderByIter<'_> {
474 let order_bys = unsafe { from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy) };
475 OrderByIter {
476 iter: order_bys.iter(),
477 }
478 }
479
480 #[inline]
482 #[must_use]
483 pub fn num_of_order_by(&self) -> usize {
484 unsafe { (*self.0).nOrderBy as usize }
485 }
486
487 #[inline]
489 pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
490 let constraint_usages =
491 unsafe { from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint) };
492 IndexConstraintUsage(&mut constraint_usages[constraint_idx])
493 }
494
495 #[inline]
497 pub fn set_idx_num(&mut self, idx_num: c_int) {
498 unsafe {
499 (*self.0).idxNum = idx_num;
500 }
501 }
502
503 pub fn set_idx_str(&mut self, idx_str: &str) {
505 unsafe {
506 if (*self.0).needToFreeIdxStr == 1 {
507 sqlite3_free((*self.0).idxStr.cast());
508 }
509 (*self.0).idxStr = alloc(idx_str);
510 (*self.0).needToFreeIdxStr = 1;
511 }
512 }
513
514 pub fn set_idx_cstr(&mut self, idx_str: &'static CStr) {
516 unsafe {
517 if (*self.0).needToFreeIdxStr == 1 {
518 sqlite3_free((*self.0).idxStr.cast());
519 }
520 (*self.0).idxStr = idx_str.as_ptr().cast_mut();
521 (*self.0).needToFreeIdxStr = 0;
522 }
523 }
524
525 #[inline]
527 pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
528 unsafe {
529 (*self.0).orderByConsumed = c_int::from(order_by_consumed);
530 }
531 }
532
533 #[inline]
535 pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
536 unsafe {
537 (*self.0).estimatedCost = estimated_ost;
538 }
539 }
540
541 #[inline]
543 pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
544 unsafe {
545 (*self.0).estimatedRows = estimated_rows;
546 }
547 }
548
549 #[inline]
551 pub fn set_idx_flags(&mut self, flags: IndexFlags) {
552 unsafe { (*self.0).idxFlags = flags.bits() };
553 }
554
555 #[inline]
557 #[must_use]
558 pub fn col_used(&self) -> u64 {
559 unsafe { (*self.0).colUsed }
560 }
561
562 pub fn collation(&self, constraint_idx: usize) -> Result<&str> {
564 let idx = constraint_idx as c_int;
565 let collation = unsafe { ffi::sqlite3_vtab_collation(self.0, idx) };
566 if collation.is_null() {
567 return Err(err!(ffi::SQLITE_MISUSE, "{constraint_idx} is out of range"));
568 }
569 Ok(unsafe { CStr::from_ptr(collation) }.to_str()?)
570 }
571
572 #[must_use]
574 pub fn distinct(&self) -> DistinctMode {
575 match unsafe { ffi::sqlite3_vtab_distinct(self.0) } {
576 0 => DistinctMode::Ordered,
577 1 => DistinctMode::Grouped,
578 2 => DistinctMode::Distinct,
579 3 => DistinctMode::DistinctOrdered,
580 _ => DistinctMode::Ordered,
581 }
582 }
583
584 pub fn rhs_value(&self, constraint_idx: usize) -> Result<Option<ValueRef<'_>>> {
586 let idx = constraint_idx as c_int;
587 let mut p_value: *mut sqlite3_value = ptr::null_mut();
588 let rc = unsafe { ffi::sqlite3_vtab_rhs_value(self.0, idx, &raw mut p_value) };
589 if rc == ffi::SQLITE_NOTFOUND {
590 return Ok(None);
591 }
592 check(rc)?;
593 assert!(!p_value.is_null());
594 Ok(Some(unsafe { ValueRef::from_value(p_value) }))
595 }
596
597 pub fn is_in_constraint(&self, constraint_idx: usize) -> Result<bool> {
599 self.check_constraint_index(constraint_idx)?;
600 let idx = constraint_idx as c_int;
601 Ok(unsafe { ffi::sqlite3_vtab_in(self.0, idx, -1) != 0 })
602 }
603
604 pub fn set_in_constraint(&mut self, constraint_idx: usize, filter_all: bool) -> Result<bool> {
606 self.check_constraint_index(constraint_idx)?;
607 let idx = constraint_idx as c_int;
608 Ok(unsafe { ffi::sqlite3_vtab_in(self.0, idx, c_int::from(filter_all)) != 0 })
609 }
610
611 fn check_constraint_index(&self, idx: usize) -> Result<()> {
612 if idx >= unsafe { (*self.0).nConstraint } as usize {
613 return Err(err!(ffi::SQLITE_MISUSE, "{idx} is out of range"));
614 }
615 Ok(())
616 }
617}
618
619#[non_exhaustive]
621#[derive(Debug, Eq, PartialEq)]
622pub enum DistinctMode {
623 Ordered,
625 Grouped,
627 Distinct,
629 DistinctOrdered,
631}
632
633pub struct IndexConstraintAndUsageIter<'a> {
635 iter: std::iter::Zip<
636 slice::Iter<'a, ffi::sqlite3_index_constraint>,
637 slice::IterMut<'a, ffi::sqlite3_index_constraint_usage>,
638 >,
639}
640
641impl<'a> Iterator for IndexConstraintAndUsageIter<'a> {
642 type Item = (IndexConstraint<'a>, IndexConstraintUsage<'a>);
643
644 #[inline]
645 fn next(&mut self) -> Option<(IndexConstraint<'a>, IndexConstraintUsage<'a>)> {
646 self.iter
647 .next()
648 .map(|raw| (IndexConstraint(raw.0), IndexConstraintUsage(raw.1)))
649 }
650
651 #[inline]
652 fn size_hint(&self) -> (usize, Option<usize>) {
653 self.iter.size_hint()
654 }
655}
656
657pub struct IndexConstraintIter<'a> {
659 iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
660}
661
662impl<'a> Iterator for IndexConstraintIter<'a> {
663 type Item = IndexConstraint<'a>;
664
665 #[inline]
666 fn next(&mut self) -> Option<IndexConstraint<'a>> {
667 self.iter.next().map(IndexConstraint)
668 }
669
670 #[inline]
671 fn size_hint(&self) -> (usize, Option<usize>) {
672 self.iter.size_hint()
673 }
674}
675
676pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
678
679impl IndexConstraint<'_> {
680 #[inline]
682 #[must_use]
683 pub fn column(&self) -> c_int {
684 self.0.iColumn
685 }
686
687 #[inline]
689 #[must_use]
690 pub fn operator(&self) -> IndexConstraintOp {
691 IndexConstraintOp::from(self.0.op)
692 }
693
694 #[inline]
696 #[must_use]
697 pub fn is_usable(&self) -> bool {
698 self.0.usable != 0
699 }
700}
701
702pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage);
705
706impl IndexConstraintUsage<'_> {
707 #[inline]
710 pub fn set_argv_index(&mut self, argv_index: c_int) {
711 self.0.argvIndex = argv_index;
712 }
713
714 #[inline]
716 pub fn set_omit(&mut self, omit: bool) {
717 self.0.omit = std::ffi::c_uchar::from(omit);
718 }
719}
720
721pub struct OrderByIter<'a> {
723 iter: slice::Iter<'a, ffi::sqlite3_index_orderby>,
724}
725
726impl<'a> Iterator for OrderByIter<'a> {
727 type Item = OrderBy<'a>;
728
729 #[inline]
730 fn next(&mut self) -> Option<OrderBy<'a>> {
731 self.iter.next().map(OrderBy)
732 }
733
734 #[inline]
735 fn size_hint(&self) -> (usize, Option<usize>) {
736 self.iter.size_hint()
737 }
738}
739
740pub struct OrderBy<'a>(&'a ffi::sqlite3_index_orderby);
742
743impl OrderBy<'_> {
744 #[inline]
746 #[must_use]
747 pub fn column(&self) -> c_int {
748 self.0.iColumn
749 }
750
751 #[inline]
753 #[must_use]
754 pub fn is_order_by_desc(&self) -> bool {
755 self.0.desc != 0
756 }
757}
758
759pub unsafe trait VTabCursor: Sized {
775 fn filter(&mut self, idx_num: c_int, idx_str: Option<&str>, args: &Filters<'_>) -> Result<()>;
778 fn next(&mut self) -> Result<()>;
781 fn eof(&self) -> bool;
785 fn column(&self, ctx: &mut Context, i: c_int) -> Result<()>;
790 fn rowid(&self) -> Result<i64>;
793}
794
795pub struct Context(*mut sqlite3_context);
798
799impl Context {
800 #[inline]
802 pub fn set_result<T: ToSql>(&mut self, value: T) -> Result<()> {
803 let t = value.to_sql()?;
804 unsafe { set_result(self.0, &[], t) }
805 }
806
807 #[inline]
809 #[must_use]
810 pub fn no_change(&self) -> bool {
811 unsafe { ffi::sqlite3_vtab_nochange(self.0) != 0 }
812 }
813
814 pub unsafe fn get_connection(&self) -> Result<ConnectionRef<'_>> {
820 Ok(ConnectionRef {
821 conn: unsafe {
822 let handle = ffi::sqlite3_context_db_handle(self.0);
823 Connection::from_handle(handle)?
824 },
825 phantom: PhantomData,
826 })
827 }
828}
829
830pub struct ConnectionRef<'ctx> {
832 conn: Connection,
835 phantom: PhantomData<&'ctx Context>,
836}
837
838impl Deref for ConnectionRef<'_> {
839 type Target = Connection;
840
841 #[inline]
842 fn deref(&self) -> &Connection {
843 &self.conn
844 }
845}
846
847pub struct Filters<'a> {
850 values: Values<'a>,
851}
852impl<'a> Deref for Filters<'a> {
853 type Target = Values<'a>;
854
855 fn deref(&self) -> &Self::Target {
856 &self.values
857 }
858}
859impl Filters<'_> {
860 pub fn in_values(&self, idx: usize) -> Result<InValues<'_>> {
862 let list = self.args[idx];
863 Ok(InValues {
864 list,
865 phantom: PhantomData,
866 first: true,
867 })
868 }
869}
870
871pub struct InValues<'a> {
873 list: *mut sqlite3_value,
874 phantom: PhantomData<Filters<'a>>,
875 first: bool,
876}
877impl<'a> fallible_iterator::FallibleIterator for InValues<'a> {
878 type Error = Error;
879 type Item = ValueRef<'a>;
880
881 fn next(&mut self) -> Result<Option<Self::Item>> {
882 let mut val: *mut sqlite3_value = ptr::null_mut();
883 let rc = unsafe {
884 if self.first {
885 self.first = false;
886 ffi::sqlite3_vtab_in_first(self.list, &raw mut val)
887 } else {
888 ffi::sqlite3_vtab_in_next(self.list, &raw mut val)
889 }
890 };
891 match rc {
892 ffi::SQLITE_OK => Ok(Some(unsafe { ValueRef::from_value(val) })),
893 ffi::SQLITE_DONE => Ok(None),
894 _ => Err(error_from_sqlite_code(rc, None)),
895 }
896 }
897}
898
899pub struct Values<'a> {
901 args: &'a [*mut sqlite3_value],
902}
903
904impl Values<'_> {
905 #[inline]
907 #[must_use]
908 pub fn len(&self) -> usize {
909 self.args.len()
910 }
911
912 #[inline]
914 #[must_use]
915 pub fn is_empty(&self) -> bool {
916 self.args.is_empty()
917 }
918
919 pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
921 let arg = self.args[idx];
922 let value = unsafe { ValueRef::from_value(arg) };
923 FromSql::column_result(value).map_err(|err| match err {
924 FromSqlError::InvalidType => Error::InvalidFilterParameterType(idx, value.data_type()),
925 FromSqlError::Other(err) => {
926 Error::FromSqlConversionFailure(idx, value.data_type(), err)
927 }
928 FromSqlError::InvalidBlobSize { .. } => {
929 Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
930 }
931 FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
932 FromSqlError::Utf8Error(err) => Error::Utf8Error(idx, err),
933 })
934 }
935
936 #[inline]
943 #[must_use]
944 pub fn get_subtype(&self, idx: usize) -> c_uint {
945 let arg = self.args[idx];
946 unsafe { ffi::sqlite3_value_subtype(arg) }
947 }
948
949 #[cfg(feature = "pointer")]
955 #[must_use]
956 pub unsafe fn get_pointer<'a, T: 'static>(
957 &self,
958 idx: usize,
959 ptr_type: &'static CStr,
960 ) -> Option<&'a T> {
961 let arg = self.args[idx];
962 debug_assert_eq!(unsafe { ffi::sqlite3_value_type(arg) }, ffi::SQLITE_NULL);
963 unsafe {
964 ffi::sqlite3_value_pointer(arg, ptr_type.as_ptr())
965 .cast::<T>()
966 .as_ref()
967 }
968 }
969
970 #[inline]
972 #[must_use]
973 pub fn iter(&self) -> ValueIter<'_> {
974 ValueIter {
975 iter: self.args.iter(),
976 }
977 }
978}
979
980impl<'a> IntoIterator for &'a Values<'a> {
981 type IntoIter = ValueIter<'a>;
982 type Item = ValueRef<'a>;
983
984 #[inline]
985 fn into_iter(self) -> ValueIter<'a> {
986 self.iter()
987 }
988}
989
990pub struct ValueIter<'a> {
992 iter: slice::Iter<'a, *mut sqlite3_value>,
993}
994
995impl<'a> Iterator for ValueIter<'a> {
996 type Item = ValueRef<'a>;
997
998 #[inline]
999 fn next(&mut self) -> Option<ValueRef<'a>> {
1000 self.iter
1001 .next()
1002 .map(|&raw| unsafe { ValueRef::from_value(raw) })
1003 }
1004
1005 #[inline]
1006 fn size_hint(&self) -> (usize, Option<usize>) {
1007 self.iter.size_hint()
1008 }
1009}
1010
1011pub struct Inserts<'a> {
1013 values: Values<'a>,
1014}
1015impl<'a> Deref for Inserts<'a> {
1016 type Target = Values<'a>;
1017
1018 fn deref(&self) -> &Self::Target {
1019 &self.values
1020 }
1021}
1022impl Inserts<'_> {
1023 #[must_use]
1028 pub unsafe fn on_conflict(&self, db: *mut ffi::sqlite3) -> ConflictMode {
1029 ConflictMode::from(unsafe { ffi::sqlite3_vtab_on_conflict(db) })
1030 }
1031}
1032
1033pub struct Updates<'a> {
1035 values: Values<'a>,
1036}
1037impl<'a> Deref for Updates<'a> {
1038 type Target = Values<'a>;
1039
1040 fn deref(&self) -> &Self::Target {
1041 &self.values
1042 }
1043}
1044impl Updates<'_> {
1045 #[inline]
1049 #[must_use]
1050 pub fn no_change(&self, idx: usize) -> bool {
1051 unsafe { ffi::sqlite3_value_nochange(self.values.args[idx]) != 0 }
1052 }
1053
1054 #[must_use]
1059 pub unsafe fn on_conflict(&self, db: *mut ffi::sqlite3) -> ConflictMode {
1060 ConflictMode::from(unsafe { ffi::sqlite3_vtab_on_conflict(db) })
1061 }
1062}
1063
1064#[non_exhaustive]
1066#[derive(Debug, Eq, PartialEq)]
1067pub enum ConflictMode {
1068 Rollback,
1070 Ignore,
1072 Fail,
1074 Abort,
1076 Replace,
1078}
1079impl From<c_int> for ConflictMode {
1080 fn from(value: c_int) -> Self {
1081 match value {
1082 ffi::SQLITE_ROLLBACK => ConflictMode::Rollback,
1083 ffi::SQLITE_IGNORE => ConflictMode::Ignore,
1084 ffi::SQLITE_FAIL => ConflictMode::Fail,
1085 ffi::SQLITE_ABORT => ConflictMode::Abort,
1086 ffi::SQLITE_REPLACE => ConflictMode::Replace,
1087 _ => unreachable!("sqlite3_vtab_on_conflict returned invalid value"),
1088 }
1089 }
1090}
1091
1092impl Connection {
1093 #[inline]
1098 pub fn create_module<'vtab, T: VTab<'vtab>, M: Name>(
1099 &self,
1100 module_name: M,
1101 module: &'static Module<'vtab, T>,
1102 aux: Option<T::Aux>,
1103 ) -> Result<()> {
1104 self.db.borrow_mut().create_module(module_name, module, aux)
1105 }
1106}
1107
1108impl InnerConnection {
1109 fn create_module<'vtab, T: VTab<'vtab>, M: Name>(
1110 &mut self,
1111 module_name: M,
1112 module: &'static Module<'vtab, T>,
1113 aux: Option<T::Aux>,
1114 ) -> Result<()> {
1115 use crate::version;
1116 if version::version_number() < 3_009_000 && module.base.xCreate.is_none() {
1117 return Err(Error::ModuleError(format!(
1118 "Eponymous-only virtual table not supported by SQLite version {}",
1119 version::version()
1120 )));
1121 }
1122 let c_name = module_name.as_cstr()?;
1123 let r = match aux {
1124 Some(aux) => {
1125 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
1126 unsafe {
1127 ffi::sqlite3_create_module_v2(
1128 self.db(),
1129 c_name.as_ptr(),
1130 &raw const module.base,
1131 boxed_aux.cast::<c_void>(),
1132 Some(free_boxed_value::<T::Aux>),
1133 )
1134 }
1135 }
1136 None => unsafe {
1137 ffi::sqlite3_create_module_v2(
1138 self.db(),
1139 c_name.as_ptr(),
1140 &raw const module.base,
1141 ptr::null_mut(),
1142 None,
1143 )
1144 },
1145 };
1146 self.decode_result(r)
1147 }
1148}
1149
1150#[must_use]
1153pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
1154 if identifier.contains('"') {
1155 Owned(identifier.replace('"', "\"\""))
1157 } else {
1158 Borrowed(identifier)
1159 }
1160}
1161#[must_use]
1163pub fn dequote(mut s: &str) -> Cow<'_, str> {
1164 let mut chars = s.chars();
1165 let (Some(first), Some(last)) = (chars.next(), chars.next_back()) else {
1166 return Borrowed(s);
1167 };
1168 if (first == '"' || first == '\'' || first == '`' || first == '[')
1169 && (last == first || first == '[' && last == ']')
1170 {
1171 s = chars.as_str();
1172 if first != '[' && s.contains(first) {
1173 let mut owned = String::with_capacity(s.len());
1175 let mut escaped = false;
1176 for c in s.chars() {
1177 if c == first {
1178 if !escaped {
1179 escaped = true;
1180 continue;
1181 }
1182 escaped = false;
1183 } else if escaped {
1184 return Borrowed(s);
1186 }
1187 owned.push(c);
1188 }
1189 if !escaped {
1190 return Owned(owned);
1191 }
1192 }
1193 }
1194 Borrowed(s)
1195}
1196#[must_use]
1202pub fn parse_boolean(s: &str) -> Option<bool> {
1203 if s.eq_ignore_ascii_case("yes")
1204 || s.eq_ignore_ascii_case("on")
1205 || s.eq_ignore_ascii_case("true")
1206 || s.eq("1")
1207 {
1208 Some(true)
1209 } else if s.eq_ignore_ascii_case("no")
1210 || s.eq_ignore_ascii_case("off")
1211 || s.eq_ignore_ascii_case("false")
1212 || s.eq("0")
1213 {
1214 Some(false)
1215 } else {
1216 None
1217 }
1218}
1219
1220pub fn parameter(c_slice: &[u8]) -> Result<(&str, Cow<'_, str>)> {
1222 let arg = std::str::from_utf8(c_slice)?.trim();
1223 match arg.split_once('=') {
1224 Some((key, value)) => {
1225 let param = key.trim();
1226 let value = dequote(value.trim());
1227 Ok((param, value))
1228 }
1229 _ => Err(Error::ModuleError(format!("illegal argument: '{arg}'"))),
1230 }
1231}
1232
1233unsafe extern "C" fn rust_create<'vtab, T>(
1234 db: *mut ffi::sqlite3,
1235 aux: *mut c_void,
1236 argc: c_int,
1237 argv: *const *const c_char,
1238 pp_vtab: *mut *mut sqlite3_vtab,
1239 err_msg: *mut *mut c_char,
1240) -> c_int
1241where
1242 T: CreateVTab<'vtab>,
1243{
1244 let mut conn = VTabConnection(db);
1245 let aux = aux.cast::<T::Aux>();
1246 unsafe {
1247 let args = from_raw_parts(argv, argc);
1248 let vec = args
1249 .iter()
1250 .map(|&cs| CStr::from_ptr(cs).to_bytes()) .collect::<Vec<_>>();
1252 match T::create(&mut conn, aux.as_ref(), vec[0], vec[1], vec[2], &vec[3..]) {
1253 Ok((sql, vtab)) => {
1254 let rc = ffi::sqlite3_declare_vtab(db, sql.as_ptr());
1255 if rc == ffi::SQLITE_OK {
1256 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1257 *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
1258 ffi::SQLITE_OK
1259 } else {
1260 let err = error_from_sqlite_code(rc, None);
1261 to_sqlite_error(&err, err_msg)
1262 }
1263 }
1264 Err(err) => to_sqlite_error(&err, err_msg),
1265 }
1266 }
1267}
1268
1269unsafe extern "C" fn rust_connect<'vtab, T>(
1270 db: *mut ffi::sqlite3,
1271 aux: *mut c_void,
1272 argc: c_int,
1273 argv: *const *const c_char,
1274 pp_vtab: *mut *mut sqlite3_vtab,
1275 err_msg: *mut *mut c_char,
1276) -> c_int
1277where
1278 T: VTab<'vtab>,
1279{
1280 let mut conn = VTabConnection(db);
1281 let aux = aux.cast::<T::Aux>();
1282 unsafe {
1283 let args = from_raw_parts(argv, argc);
1284 let vec = args
1285 .iter()
1286 .map(|&cs| CStr::from_ptr(cs).to_bytes()) .collect::<Vec<_>>();
1288 match T::connect(&mut conn, aux.as_ref(), vec[0], vec[1], vec[2], &vec[3..]) {
1289 Ok((sql, vtab)) => {
1290 let rc = ffi::sqlite3_declare_vtab(db, sql.as_ptr());
1291 if rc == ffi::SQLITE_OK {
1292 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
1293 *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
1294 ffi::SQLITE_OK
1295 } else {
1296 let err = error_from_sqlite_code(rc, None);
1297 to_sqlite_error(&err, err_msg)
1298 }
1299 }
1300 Err(err) => to_sqlite_error(&err, err_msg),
1301 }
1302 }
1303}
1304
1305unsafe extern "C" fn rust_best_index<'vtab, T>(
1306 vtab: *mut sqlite3_vtab,
1307 info: *mut ffi::sqlite3_index_info,
1308) -> c_int
1309where
1310 T: VTab<'vtab>,
1311{
1312 let vt = vtab.cast::<T>();
1313 let mut idx_info = IndexInfo(info);
1314 unsafe {
1315 match (*vt).best_index(&mut idx_info) {
1316 Ok(true) => ffi::SQLITE_OK,
1317 Ok(false) => ffi::SQLITE_CONSTRAINT,
1318 err => vtab_error(vtab, err),
1319 }
1320 }
1321}
1322
1323unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1324where
1325 T: VTab<'vtab>,
1326{
1327 if vtab.is_null() {
1328 return ffi::SQLITE_OK;
1329 }
1330 let vtab = vtab.cast::<T>();
1331 drop(unsafe { Box::from_raw(vtab) });
1332 ffi::SQLITE_OK
1333}
1334
1335unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1336where
1337 T: CreateVTab<'vtab>,
1338{
1339 if vtab.is_null() {
1340 return ffi::SQLITE_OK;
1341 }
1342 let vt = vtab.cast::<T>();
1343 unsafe {
1344 match (*vt).destroy() {
1345 Ok(()) => {
1346 drop(Box::from_raw(vt));
1347 ffi::SQLITE_OK
1348 }
1349 err => vtab_error(vtab, err),
1350 }
1351 }
1352}
1353
1354unsafe extern "C" fn rust_open<'vtab, T>(
1355 vtab: *mut sqlite3_vtab,
1356 pp_cursor: *mut *mut sqlite3_vtab_cursor,
1357) -> c_int
1358where
1359 T: VTab<'vtab> + 'vtab,
1360{
1361 let vt = vtab.cast::<T>();
1362 unsafe {
1363 match (*vt).open() {
1364 Ok(cursor) => {
1365 let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
1366 *pp_cursor = boxed_cursor.cast::<sqlite3_vtab_cursor>();
1367 ffi::SQLITE_OK
1368 }
1369 err => vtab_error(vtab, err),
1370 }
1371 }
1372}
1373
1374unsafe extern "C" fn rust_close<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1375where
1376 C: VTabCursor,
1377{
1378 let cr = cursor.cast::<C>();
1379 drop(unsafe { Box::from_raw(cr) });
1380 ffi::SQLITE_OK
1381}
1382
1383unsafe extern "C" fn rust_filter<C>(
1384 cursor: *mut sqlite3_vtab_cursor,
1385 idx_num: c_int,
1386 idx_str: *const c_char,
1387 argc: c_int,
1388 argv: *mut *mut sqlite3_value,
1389) -> c_int
1390where
1391 C: VTabCursor,
1392{
1393 use std::str;
1394 unsafe {
1395 let idx_name = if idx_str.is_null() {
1396 None
1397 } else {
1398 let c_slice = CStr::from_ptr(idx_str).to_bytes();
1399 Some(str::from_utf8_unchecked(c_slice))
1400 };
1401 let args = from_raw_parts_mut(argv, argc);
1402 let values = Values { args };
1403 let cr = cursor.cast::<C>();
1404 cursor_error(cursor, (*cr).filter(idx_num, idx_name, &Filters { values }))
1405 }
1406}
1407
1408unsafe extern "C" fn rust_next<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1409where
1410 C: VTabCursor,
1411{
1412 let cr = cursor.cast::<C>();
1413 unsafe { cursor_error(cursor, (*cr).next()) }
1414}
1415
1416unsafe extern "C" fn rust_eof<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1417where
1418 C: VTabCursor,
1419{
1420 let cr = cursor.cast::<C>();
1421 unsafe { c_int::from((*cr).eof()) }
1422}
1423
1424unsafe extern "C" fn rust_column<C>(
1425 cursor: *mut sqlite3_vtab_cursor,
1426 ctx: *mut sqlite3_context,
1427 i: c_int,
1428) -> c_int
1429where
1430 C: VTabCursor,
1431{
1432 let cr = cursor.cast::<C>();
1433 let mut ctxt = Context(ctx);
1434 unsafe { result_error(ctx, (*cr).column(&mut ctxt, i)) }
1435}
1436
1437unsafe extern "C" fn rust_rowid<C>(
1438 cursor: *mut sqlite3_vtab_cursor,
1439 p_rowid: *mut ffi::sqlite3_int64,
1440) -> c_int
1441where
1442 C: VTabCursor,
1443{
1444 let cr = cursor.cast::<C>();
1445 unsafe {
1446 match (*cr).rowid() {
1447 Ok(rowid) => {
1448 *p_rowid = rowid;
1449 ffi::SQLITE_OK
1450 }
1451 err => cursor_error(cursor, err),
1452 }
1453 }
1454}
1455
1456unsafe extern "C" fn rust_update<'vtab, T>(
1457 vtab: *mut sqlite3_vtab,
1458 argc: c_int,
1459 argv: *mut *mut sqlite3_value,
1460 p_rowid: *mut ffi::sqlite3_int64,
1461) -> c_int
1462where
1463 T: UpdateVTab<'vtab> + 'vtab,
1464{
1465 assert!(argc >= 1);
1466 let vt = vtab.cast::<T>();
1467 unsafe {
1468 let args = from_raw_parts_mut(argv, argc);
1469 let r = if args.len() == 1 {
1470 (*vt).delete(ValueRef::from_value(args[0]))
1471 } else if ffi::sqlite3_value_type(args[0]) == ffi::SQLITE_NULL {
1472 let values = Values { args };
1474 match (*vt).insert(&Inserts { values }) {
1475 Ok(rowid) => {
1476 *p_rowid = rowid;
1477 Ok(())
1478 }
1479 Err(e) => Err(e),
1480 }
1481 } else {
1482 let values = Values { args };
1483 (*vt).update(&Updates { values })
1484 };
1485 vtab_error(vtab, r)
1486 }
1487}
1488
1489unsafe extern "C" fn rust_begin<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1490where
1491 T: TransactionVTab<'vtab>,
1492{
1493 let vt = vtab.cast::<T>();
1494 unsafe { vtab_error(vtab, (*vt).begin()) }
1495}
1496unsafe extern "C" fn rust_sync<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1497where
1498 T: TransactionVTab<'vtab>,
1499{
1500 let vt = vtab.cast::<T>();
1501 unsafe { vtab_error(vtab, (*vt).sync()) }
1502}
1503unsafe extern "C" fn rust_commit<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1504where
1505 T: TransactionVTab<'vtab>,
1506{
1507 let vt = vtab.cast::<T>();
1508 unsafe { vtab_error(vtab, (*vt).commit()) }
1509}
1510unsafe extern "C" fn rust_rollback<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
1511where
1512 T: TransactionVTab<'vtab>,
1513{
1514 let vt = vtab.cast::<T>();
1515 unsafe { vtab_error(vtab, (*vt).rollback()) }
1516}
1517
1518unsafe fn cursor_error<T>(cursor: *mut sqlite3_vtab_cursor, result: Result<T>) -> c_int {
1521 unsafe { vtab_error((*cursor).pVtab, result) }
1522}
1523
1524unsafe fn vtab_error<T>(vtab: *mut sqlite3_vtab, result: Result<T>) -> c_int {
1527 unsafe {
1528 match result {
1529 Ok(_) => ffi::SQLITE_OK,
1530 Err(Error::SqliteFailure(err, s)) => {
1531 if let Some(err_msg) = s {
1532 set_err_msg(vtab, &err_msg);
1533 }
1534 err.extended_code
1535 }
1536 Err(err) => {
1537 set_err_msg(vtab, &err.to_string());
1538 ffi::SQLITE_ERROR
1539 }
1540 }
1541 }
1542}
1543
1544#[cold]
1547unsafe fn set_err_msg(vtab: *mut sqlite3_vtab, err_msg: &str) {
1548 unsafe {
1549 if !(*vtab).zErrMsg.is_null() {
1550 sqlite3_free((*vtab).zErrMsg.cast::<c_void>());
1551 }
1552 (*vtab).zErrMsg = alloc(err_msg);
1553 }
1554}
1555
1556#[cold]
1559unsafe fn result_error<T>(ctx: *mut sqlite3_context, result: Result<T>) -> c_int {
1560 unsafe {
1561 match result {
1562 Ok(_) => ffi::SQLITE_OK,
1563 Err(Error::SqliteFailure(err, s)) => {
1564 match err.extended_code {
1565 ffi::SQLITE_TOOBIG => {
1566 ffi::sqlite3_result_error_toobig(ctx);
1567 }
1568 ffi::SQLITE_NOMEM => {
1569 ffi::sqlite3_result_error_nomem(ctx);
1570 }
1571 code => {
1572 ffi::sqlite3_result_error_code(ctx, code);
1573 if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
1574 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1575 }
1576 }
1577 }
1578 err.extended_code
1579 }
1580 Err(err) => {
1581 ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_ERROR);
1582 if let Ok(cstr) = str_to_cstring(&err.to_string()) {
1583 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
1584 }
1585 ffi::SQLITE_ERROR
1586 }
1587 }
1588 }
1589}
1590
1591#[cfg(feature = "array")]
1592pub mod array;
1593#[cfg(feature = "csvtab")]
1594pub mod csvtab;
1595#[cfg(feature = "series")]
1596pub mod series; #[cfg(all(test, not(miri)))]
1598mod vtablog;
1599
1600#[cfg(test)]
1601mod test {
1602 use std::borrow::Cow;
1603
1604 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1605 use wasm_bindgen_test::wasm_bindgen_test as test;
1606
1607 #[test]
1608 fn test_dequote() {
1609 assert_eq!("", super::dequote(""));
1610 assert_eq!("'", super::dequote("'"));
1611 assert_eq!("\"", super::dequote("\""));
1612
1613 assert_eq!("'\"", super::dequote("'\""));
1614
1615 assert_eq!("", super::dequote("''"));
1616 assert_eq!("", super::dequote("\"\""));
1617 assert_eq!("", super::dequote("``"));
1618 assert_eq!("", super::dequote("[]"));
1619
1620 assert_eq!("x", super::dequote("'x'"));
1621 assert_eq!("x", super::dequote("\"x\""));
1622 assert_eq!("x", super::dequote("x"));
1623 assert_eq!("x", super::dequote("`x`"));
1624 assert_eq!("x", super::dequote("[x]"));
1625
1626 assert_eq!("x'", super::dequote("'x'''"));
1627 assert_eq!("x`", super::dequote("`x```"));
1628
1629 assert_eq!("x'", super::dequote("'x''"));
1630 assert_eq!("x`", super::dequote("`x``"));
1631 }
1632 #[test]
1633 fn test_parse_boolean() {
1634 assert_eq!(None, super::parse_boolean(""));
1635 assert_eq!(Some(true), super::parse_boolean("1"));
1636 assert_eq!(Some(true), super::parse_boolean("yes"));
1637 assert_eq!(Some(true), super::parse_boolean("on"));
1638 assert_eq!(Some(true), super::parse_boolean("true"));
1639 assert_eq!(Some(false), super::parse_boolean("0"));
1640 assert_eq!(Some(false), super::parse_boolean("no"));
1641 assert_eq!(Some(false), super::parse_boolean("off"));
1642 assert_eq!(Some(false), super::parse_boolean("false"));
1643 }
1644 #[test]
1645 fn test_parse_parameters() {
1646 assert_eq!(
1647 Ok(("key", Cow::Borrowed("value"))),
1648 super::parameter(b"key='value'")
1649 );
1650 assert_eq!(
1651 Ok(("key", Cow::Borrowed("foo=bar"))),
1652 super::parameter(b"key='foo=bar'")
1653 );
1654 }
1655
1656 #[cfg(all(feature = "functions", not(miri)))]
1657 #[test]
1658 fn test_values_get_subtype() -> crate::Result<()> {
1659 use std::ffi::{CStr, c_int, c_uint};
1660 use std::sync::atomic::{AtomicU32, Ordering};
1661
1662 use crate::ffi;
1663 use crate::functions::{FunctionFlags, SqlFnArg, SubType};
1664 use crate::types::Value;
1665 use crate::vtab::{
1666 Context, CreateVTab, Filters, IndexConstraintOp, IndexInfo, Inserts, Module,
1667 UpdateVTab, Updates, VTab, VTabConnection, VTabCursor, VTabKind,
1668 };
1669 use crate::{Connection, Result};
1670
1671 static FILTER_SUBTYPE: AtomicU32 = AtomicU32::new(0);
1672 static INSERT_SUBTYPE: AtomicU32 = AtomicU32::new(0);
1673
1674 fn set_subtype(ctx: &crate::functions::Context<'_>) -> Result<(SqlFnArg, SubType)> {
1675 let value = ctx.get_arg(0);
1676 let sub_type = ctx.get::<c_uint>(1)?;
1677 Ok((value, Some(sub_type)))
1678 }
1679
1680 #[repr(C)]
1681 struct SubTypeVTab {
1682 base: ffi::sqlite3_vtab,
1683 }
1684 #[repr(C)]
1685 struct SubTypeVTabCursor {
1686 base: ffi::sqlite3_vtab_cursor,
1687 }
1688
1689 unsafe impl<'vtab> VTab<'vtab> for SubTypeVTab {
1690 type Aux = ();
1691 type Cursor = SubTypeVTabCursor;
1692
1693 fn connect(
1694 _db: &mut VTabConnection,
1695 _aux: Option<&Self::Aux>,
1696 _module_name: &[u8],
1697 _database_name: &[u8],
1698 _table_name: &[u8],
1699 _args: &[&[u8]],
1700 ) -> Result<(Cow<'static, CStr>, Self)> {
1701 Ok((
1702 Cow::Borrowed(c"CREATE TABLE x(value BLOB)"),
1703 Self {
1704 base: ffi::sqlite3_vtab::default(),
1705 },
1706 ))
1707 }
1708
1709 fn best_index(&self, info: &mut IndexInfo) -> Result<bool> {
1710 let mut argv_index = 1;
1711 let mut usable_constraints = Vec::new();
1712 for (i, constraint) in info.constraints().enumerate() {
1713 if constraint.is_usable()
1714 && constraint.operator() == IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ
1715 {
1716 usable_constraints.push(i);
1717 }
1718 }
1719 for i in usable_constraints {
1720 let mut usage = info.constraint_usage(i);
1721 usage.set_argv_index(argv_index);
1722 usage.set_omit(true);
1723 argv_index += 1;
1724 }
1725 info.set_estimated_cost(1.0);
1726 Ok(true)
1727 }
1728
1729 fn open(&'vtab mut self) -> Result<Self::Cursor> {
1730 Ok(SubTypeVTabCursor {
1731 base: ffi::sqlite3_vtab_cursor::default(),
1732 })
1733 }
1734 }
1735
1736 impl CreateVTab<'_> for SubTypeVTab {
1737 const KIND: VTabKind = VTabKind::Default;
1738 }
1739
1740 impl UpdateVTab<'_> for SubTypeVTab {
1741 fn delete(&mut self, _arg: crate::types::ValueRef<'_>) -> Result<()> {
1742 Ok(())
1743 }
1744
1745 fn insert(&mut self, args: &Inserts<'_>) -> Result<i64> {
1746 INSERT_SUBTYPE.store(args.get_subtype(2), Ordering::SeqCst);
1750 Ok(0)
1751 }
1752
1753 fn update(&mut self, _args: &Updates<'_>) -> Result<()> {
1754 Ok(())
1755 }
1756 }
1757
1758 unsafe impl VTabCursor for SubTypeVTabCursor {
1759 fn filter(
1760 &mut self,
1761 _idx_num: c_int,
1762 _idx_str: Option<&str>,
1763 args: &Filters<'_>,
1764 ) -> Result<()> {
1765 FILTER_SUBTYPE.store(args.get_subtype(0), Ordering::SeqCst);
1766 Ok(())
1767 }
1768
1769 fn next(&mut self) -> Result<()> {
1770 Ok(())
1771 }
1772
1773 fn eof(&self) -> bool {
1774 true
1775 }
1776
1777 fn column(&self, ctx: &mut Context, _i: c_int) -> Result<()> {
1778 ctx.set_result(Value::Null)
1779 }
1780
1781 fn rowid(&self) -> Result<i64> {
1782 Ok(0)
1783 }
1784 }
1785
1786 let db = Connection::open_in_memory()?;
1787 db.create_scalar_function(
1788 c"set_subtype",
1789 2,
1790 FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_RESULT_SUBTYPE,
1791 set_subtype,
1792 )?;
1793 const MODULE: Module<SubTypeVTab> = Module::update_module();
1794 db.create_module(c"subtype_vtab", &MODULE, None)?;
1795
1796 db.execute("CREATE VIRTUAL TABLE st USING subtype_vtab()", [])?;
1797
1798 FILTER_SUBTYPE.store(0, Ordering::SeqCst);
1799 INSERT_SUBTYPE.store(0, Ordering::SeqCst);
1800
1801 let _: Result<String> = db.query_row(
1803 "SELECT value FROM st WHERE value = set_subtype('a', 223)",
1804 [],
1805 |row| row.get(0),
1806 );
1807 assert_eq!(FILTER_SUBTYPE.load(Ordering::SeqCst), 223);
1808
1809 db.execute(
1812 "INSERT INTO st(rowid, value) VALUES (1, set_subtype(X'62', 225))",
1813 [],
1814 )?;
1815 assert_eq!(INSERT_SUBTYPE.load(Ordering::SeqCst), 225);
1816
1817 Ok(())
1818 }
1819}