1use sqlite3ext_sys::sqlite3_index_info_sqlite3_index_constraint_usage;
6use sqlite3ext_sys::{
7 sqlite3, sqlite3_context, sqlite3_index_info, sqlite3_index_info_sqlite3_index_constraint,
8 sqlite3_index_info_sqlite3_index_orderby, sqlite3_module, sqlite3_value, sqlite3_vtab,
9 sqlite3_vtab_cursor,
10};
11
12use crate::constants::*;
13use std::ffi::CString;
14use std::marker::PhantomData;
15use std::marker::Sync;
16use std::os::raw::{c_char, c_int, c_void};
17use std::ptr;
18use std::slice;
19use std::str::Utf8Error;
20
21use crate::api::{mprintf, value_type, MprintfError, ValueType};
22use crate::errors::{Error, ErrorKind, Result};
23use crate::ext::sqlitex_declare_vtab;
24use crate::ext::{sqlite3ext_create_module_v2, sqlite3ext_vtab_distinct};
25use serde::{Deserialize, Serialize};
26
27#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
31pub enum ConstraintOperator {
32 EQ,
34
35 GT,
37
38 LE,
40
41 LT,
43
44 GE,
46
47 MATCH,
49
50 LIKE,
52
53 GLOB,
55
56 REGEXP,
58
59 NE,
61
62 ISNOT,
64
65 ISNOTNULL,
67
68 ISNULL,
70
71 IS,
73
74 LIMIT,
76
77 OFFSET,
79
80 FUNCTION(u8),
82}
83
84pub fn operator(op: u8) -> Option<ConstraintOperator> {
88 match op {
89 2 => Some(ConstraintOperator::EQ),
90 4 => Some(ConstraintOperator::GT),
91 8 => Some(ConstraintOperator::LE),
92 16 => Some(ConstraintOperator::LT),
93 32 => Some(ConstraintOperator::GE),
94 64 => Some(ConstraintOperator::MATCH),
95 65 => Some(ConstraintOperator::LIKE),
96 66 => Some(ConstraintOperator::GLOB),
97 67 => Some(ConstraintOperator::REGEXP),
98 68 => Some(ConstraintOperator::NE),
99 69 => Some(ConstraintOperator::ISNOT),
100 70 => Some(ConstraintOperator::ISNOTNULL),
101 71 => Some(ConstraintOperator::ISNULL),
102 72 => Some(ConstraintOperator::IS),
103 73 => Some(ConstraintOperator::LIMIT),
104 74 => Some(ConstraintOperator::OFFSET),
105 150..=255 => Some(ConstraintOperator::FUNCTION(op)),
106 _ => None,
107 }
108}
109
110#[derive(Debug)]
115pub struct IndexInfo {
116 index_info: *mut sqlite3_index_info,
117}
118impl IndexInfo {
119 pub fn idx_flag(&self) -> i32 {
121 unsafe { (*self.index_info).idxFlags }
122 }
123 pub fn constraints(&self) -> Vec<Constraint> {
124 let constraints = unsafe {
125 slice::from_raw_parts(
126 (*self.index_info).aConstraint,
127 (*self.index_info).nConstraint as usize,
128 )
129 };
130
131 let constraint_usages = unsafe {
132 slice::from_raw_parts_mut(
133 (*self.index_info).aConstraintUsage,
134 (*self.index_info).nConstraint as usize,
135 )
136 };
137
138 return constraints
139 .iter()
140 .zip(constraint_usages.iter_mut())
141 .map(|z| Constraint {
142 constraint: *z.0,
143 usage: z.1,
144 })
145 .collect();
146 }
147 pub fn order_bys(&self) -> Vec<OrderBy> {
148 let order_bys = unsafe {
149 slice::from_raw_parts(
150 (*self.index_info).aOrderBy,
151 (*self.index_info).nOrderBy as usize,
152 )
153 };
154 return order_bys.iter().map(|o| OrderBy { order_by: *o }).collect();
155 }
156 pub fn set_idxnum(&mut self, value: i32) {
157 unsafe {
158 (*self.index_info).idxNum = value;
159 }
160 }
161 pub fn set_idxstr(&mut self, value: &str) -> crate::Result<()> {
162 let idxstr = match mprintf(value) {
163 Ok(idxstr) => idxstr,
164 Err(err) => {
165 return match err {
166 MprintfError::Oom => Err(Error::new_message("OOM todo change to code?")),
167 MprintfError::Nul(err) => Err(err.into()),
168 }
169 }
170 };
171 unsafe {
172 (*self.index_info).idxStr = idxstr;
173 (*self.index_info).needToFreeIdxStr = 1;
174 }
175 Ok(())
176 }
177 pub fn set_estimated_rows(&mut self, value: i64) {
178 unsafe {
179 (*self.index_info).estimatedRows = value;
180 }
181 }
182
183 pub fn set_estimated_cost(&mut self, value: f64) {
187 unsafe {
188 (*self.index_info).estimatedCost = value;
189 }
190 }
191 pub fn columns_used(&self) -> u64 {
196 unsafe { (*self.index_info).colUsed }
197 }
198 pub fn distinct(&self) -> i32 {
199 unsafe { sqlite3ext_vtab_distinct(self.index_info) }
200 }
201 }
203
204#[derive(Debug)]
207pub struct Constraint {
208 pub constraint: sqlite3_index_info_sqlite3_index_constraint,
209 pub usage: *mut sqlite3_index_info_sqlite3_index_constraint_usage,
210}
211
212impl Constraint {
213 pub fn column_idx(&self) -> i32 {
214 (self.constraint).iColumn
215 }
216
217 pub fn usable(&self) -> bool {
218 (self.constraint).usable != 0
219 }
220 pub fn op(&self) -> Option<ConstraintOperator> {
221 operator((self.constraint).op)
222 }
223
224 pub fn set_argv_index(&mut self, i: i32) {
225 unsafe { (*self.usage).argvIndex = i };
226 }
227 pub fn set_omit(&mut self, value: bool) {
228 unsafe { (*self.usage).omit = u8::from(value) }
229 }
230}
231
232#[derive(Debug)]
233pub enum OrderByDirection {
234 Ascending,
235 Descending,
236}
237#[derive(Debug)]
238pub struct OrderBy {
239 order_by: sqlite3_index_info_sqlite3_index_orderby,
240}
241impl OrderBy {
242 pub fn icolumn(&self) -> i32 {
243 (self.order_by).iColumn
244 }
245 pub fn direction(&self) -> OrderByDirection {
246 if (self.order_by).desc == 1 {
247 OrderByDirection::Descending
248 } else {
249 OrderByDirection::Ascending
250 }
251 }
252}
253
254pub enum BestIndexError {
256 Constraint,
258 Error,
259}
260#[repr(transparent)]
261struct Module<'vtab, T: VTab<'vtab>> {
262 base: sqlite3_module,
263 phantom: PhantomData<&'vtab T>,
264}
265
266unsafe impl<'vtab, T: VTab<'vtab>> Send for Module<'vtab, T> {}
267unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {}
268
269pub fn define_table_function<'vtab, T: VTab<'vtab> + 'vtab>(
273 db: *mut sqlite3,
274 name: &str,
275 aux: Option<T::Aux>,
276) -> Result<()> {
277 let m = &Module {
278 base: sqlite3_module {
279 iVersion: 2,
280 xCreate: None,
281 xConnect: Some(rust_connect::<T>),
282 xBestIndex: Some(rust_best_index::<T>),
283 xDisconnect: Some(rust_disconnect::<T>),
284 xDestroy: Some(rust_destroy::<T>),
285 xOpen: Some(rust_open::<T>),
286 xClose: Some(rust_close::<T::Cursor>),
287 xFilter: Some(rust_filter::<T::Cursor>),
288 xNext: Some(rust_next::<T::Cursor>),
289 xEof: Some(rust_eof::<T::Cursor>),
290 xColumn: Some(rust_column::<T::Cursor>),
291 xRowid: Some(rust_rowid::<T::Cursor>),
292 xUpdate: None,
293 xBegin: None,
294 xSync: None,
295 xCommit: None,
296 xRollback: None,
297 xFindFunction: None,
298 xRename: None,
299 xSavepoint: None,
300 xRelease: None,
301 xRollbackTo: None,
302 xShadowName: None,
303 },
304 phantom: PhantomData::<&'vtab T>,
305 };
306 let cname = CString::new(name)?;
307 let p_app = match aux {
308 Some(aux) => {
309 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
310 boxed_aux.cast::<c_void>()
311 }
312 None => ptr::null_mut(),
313 };
314 let result = unsafe {
315 sqlite3ext_create_module_v2(
316 db,
317 cname.as_ptr(),
318 &m.base,
319 p_app,
320 Some(destroy_aux::<T::Aux>),
321 )
322 };
323 if result != SQLITE_OKAY {
324 return Err(Error::new(ErrorKind::TableFunction(result)));
325 }
326 Ok(())
327}
328
329unsafe extern "C" fn destroy_aux<T>(p: *mut c_void) {
331 if !p.is_null() {
332 drop(Box::from_raw(p.cast::<T>()));
333 }
334}
335
336pub fn define_virtual_table<'vtab, T: VTab<'vtab> + 'vtab>(
339 db: *mut sqlite3,
340 name: &str,
341 aux: Option<T::Aux>,
342) -> Result<()> {
343 let m = &Module {
344 base: sqlite3_module {
345 iVersion: 2,
346 xCreate: Some(rust_create::<T>),
347 xConnect: Some(rust_connect::<T>),
348 xBestIndex: Some(rust_best_index::<T>),
349 xDisconnect: Some(rust_disconnect::<T>),
350 xDestroy: Some(rust_destroy::<T>),
351 xOpen: Some(rust_open::<T>),
352 xClose: Some(rust_close::<T::Cursor>),
353 xFilter: Some(rust_filter::<T::Cursor>),
354 xNext: Some(rust_next::<T::Cursor>),
355 xEof: Some(rust_eof::<T::Cursor>),
356 xColumn: Some(rust_column::<T::Cursor>),
357 xRowid: Some(rust_rowid::<T::Cursor>),
358 xUpdate: None,
359 xBegin: None,
360 xSync: None,
361 xCommit: None,
362 xRollback: None,
363 xFindFunction: None,
364 xRename: None,
365 xSavepoint: None,
366 xRelease: None,
367 xRollbackTo: None,
368 xShadowName: None,
369 },
370 phantom: PhantomData::<&'vtab T>,
371 };
372 let cname = CString::new(name)?;
373 let app_pointer = match aux {
374 Some(aux) => Box::into_raw(Box::new(aux)).cast::<c_void>(),
375 None => ptr::null_mut(),
376 };
377 let result = unsafe {
378 sqlite3ext_create_module_v2(
379 db,
380 cname.as_ptr(),
381 &m.base,
382 app_pointer,
383 Some(destroy_aux::<T::Aux>),
384 )
385 };
386 if result != SQLITE_OKAY {
387 return Err(Error::new(ErrorKind::TableFunction(result)));
388 }
389 Ok(())
390}
391
392pub fn define_virtual_table_writeable<'vtab, T: VTabWriteable<'vtab> + 'vtab>(
393 db: *mut sqlite3,
394 name: &str,
395 aux: Option<T::Aux>,
396) -> Result<()> {
397 let m = &Module {
398 base: sqlite3_module {
399 iVersion: 2,
400 xCreate: Some(rust_create::<T>),
401 xConnect: Some(rust_connect::<T>),
402 xBestIndex: Some(rust_best_index::<T>),
403 xDisconnect: Some(rust_disconnect::<T>),
404 xDestroy: Some(rust_destroy::<T>),
405 xOpen: Some(rust_open::<T>),
406 xClose: Some(rust_close::<T::Cursor>),
407 xFilter: Some(rust_filter::<T::Cursor>),
408 xNext: Some(rust_next::<T::Cursor>),
409 xEof: Some(rust_eof::<T::Cursor>),
410 xColumn: Some(rust_column::<T::Cursor>),
411 xRowid: Some(rust_rowid::<T::Cursor>),
412 xUpdate: Some(rust_update::<T>),
413 xBegin: None, xSync: None, xCommit: None, xRollback: None, xFindFunction: Some(rust_find_function::<T>),
418 xRename: None,
419 xSavepoint: None,
420 xRelease: None,
421 xRollbackTo: None,
422 xShadowName: None,
423 },
424 phantom: PhantomData::<&'vtab T>,
425 };
426 let cname = CString::new(name)?;
427 let p_app = match aux {
428 Some(aux) => {
429 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
430 boxed_aux.cast::<c_void>()
431 }
432 None => ptr::null_mut(),
433 };
434 let result = unsafe {
435 sqlite3ext_create_module_v2(
436 db,
437 cname.as_ptr(),
438 &m.base,
439 p_app,
440 Some(destroy_aux::<T::Aux>),
441 )
442 };
443 if result != SQLITE_OKAY {
444 return Err(Error::new(ErrorKind::TableFunction(result)));
445 }
446 Ok(())
447}
448
449pub fn define_virtual_table_writeable_with_transactions<
450 'vtab,
451 T: VTabWriteableWithTransactions<'vtab> + 'vtab,
452>(
453 db: *mut sqlite3,
454 name: &str,
455 aux: Option<T::Aux>,
456) -> Result<()> {
457 let m = &Module {
458 base: sqlite3_module {
459 iVersion: 2,
460 xCreate: Some(rust_create::<T>),
461 xConnect: Some(rust_connect::<T>),
462 xBestIndex: Some(rust_best_index::<T>),
463 xDisconnect: Some(rust_disconnect::<T>),
464 xDestroy: Some(rust_destroy::<T>),
465 xOpen: Some(rust_open::<T>),
466 xClose: Some(rust_close::<T::Cursor>),
467 xFilter: Some(rust_filter::<T::Cursor>),
468 xNext: Some(rust_next::<T::Cursor>),
469 xEof: Some(rust_eof::<T::Cursor>),
470 xColumn: Some(rust_column::<T::Cursor>),
471 xRowid: Some(rust_rowid::<T::Cursor>),
472 xUpdate: Some(rust_update::<T>),
473 xBegin: Some(rust_begin::<T>),
474 xSync: Some(rust_sync::<T>),
475 xCommit: Some(rust_commit::<T>),
476 xRollback: Some(rust_rollback::<T>),
477 xFindFunction: Some(rust_find_function::<T>),
478 xRename: None,
479 xSavepoint: None,
480 xRelease: None,
481 xRollbackTo: None,
482 xShadowName: None,
483 },
484 phantom: PhantomData::<&'vtab T>,
485 };
486 let cname = CString::new(name)?;
487 let p_app = match aux {
488 Some(aux) => {
489 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
490 boxed_aux.cast::<c_void>()
491 }
492 None => ptr::null_mut(),
493 };
494 let result = unsafe {
495 sqlite3ext_create_module_v2(
496 db,
497 cname.as_ptr(),
498 &m.base,
499 p_app,
500 Some(destroy_aux::<T::Aux>),
501 )
502 };
503 if result != SQLITE_OKAY {
504 return Err(Error::new(ErrorKind::TableFunction(result)));
505 }
506 Ok(())
507}
508
509pub fn define_virtual_table_writeablex<'vtab, T: VTabWriteable<'vtab> + 'vtab>(
510 db: *mut sqlite3,
511 name: &str,
512 aux: Option<T::Aux>,
513) -> Result<()> {
514 let m = &Module {
515 base: sqlite3_module {
516 iVersion: 2,
517 xCreate: None,
518 xConnect: Some(rust_connect::<T>),
519 xBestIndex: Some(rust_best_index::<T>),
520 xDisconnect: Some(rust_disconnect::<T>),
521 xDestroy: Some(rust_destroy::<T>),
522 xOpen: Some(rust_open::<T>),
523 xClose: Some(rust_close::<T::Cursor>),
524 xFilter: Some(rust_filter::<T::Cursor>),
525 xNext: Some(rust_next::<T::Cursor>),
526 xEof: Some(rust_eof::<T::Cursor>),
527 xColumn: Some(rust_column::<T::Cursor>),
528 xRowid: Some(rust_rowid::<T::Cursor>),
529 xUpdate: Some(rust_update::<T>),
530 xBegin: None, xSync: None, xCommit: None, xRollback: None, xFindFunction: Some(rust_find_function::<T>),
535 xRename: None,
536 xSavepoint: None,
537 xRelease: None,
538 xRollbackTo: None,
539 xShadowName: None,
540 },
541 phantom: PhantomData::<&'vtab T>,
542 };
543 let cname = CString::new(name)?;
544 let p_app = match aux {
545 Some(aux) => {
546 let boxed_aux: *mut T::Aux = Box::into_raw(Box::new(aux));
547 boxed_aux.cast::<c_void>()
548 }
549 None => ptr::null_mut(),
550 };
551 let result = unsafe {
552 sqlite3ext_create_module_v2(
553 db,
554 cname.as_ptr(),
555 &m.base,
556 p_app,
557 Some(destroy_aux::<T::Aux>),
558 )
559 };
560 if result != SQLITE_OKAY {
561 return Err(Error::new(ErrorKind::TableFunction(result)));
562 }
563 Ok(())
564}
565
566pub trait VTab<'vtab>: Sized {
567 type Aux;
568 type Cursor: VTabCursor;
569
570 fn create(
571 db: *mut sqlite3,
572 aux: Option<&Self::Aux>,
573 args: VTabArguments,
574 ) -> Result<(String, Self)> {
575 Self::connect(db, aux, args)
576 }
577
578 fn connect(
579 db: *mut sqlite3,
580 aux: Option<&Self::Aux>,
581 args: VTabArguments,
582 ) -> Result<(String, Self)>;
583
584 fn best_index(&self, info: IndexInfo) -> core::result::Result<(), BestIndexError>;
585
586 fn open(&'vtab mut self) -> Result<Self::Cursor>;
587
588 fn destroy(&self) -> Result<()> {
589 Ok(())
590 }
591}
592
593pub trait VTabWriteable<'vtab>: VTab<'vtab> {
594 fn update(&'vtab mut self, operation: UpdateOperation, p_rowid: *mut i64) -> Result<()>;
595}
596
597pub trait VTabWriteableWithTransactions<'vtab>: VTabWriteable<'vtab> {
598 fn begin(&'vtab mut self) -> Result<()>;
599 fn sync(&'vtab mut self) -> Result<()>;
600 fn commit(&'vtab mut self) -> Result<()>;
601 fn rollback(&'vtab mut self) -> Result<()>;
602}
603
604pub trait VTabWriteableNestedTransactions<'vtab>: VTabWriteable<'vtab> {
605 fn savepoint(&'vtab mut self, id: c_int) -> Result<()>;
606 fn release(&'vtab mut self, id: c_int) -> Result<()>;
607 fn rollback_to(&'vtab mut self, id: c_int) -> Result<()>;
608}
609
610pub trait VTabCursor: Sized {
611 fn filter(
612 &mut self,
613 idx_num: c_int,
614 idx_str: Option<&str>,
615 values: &[*mut sqlite3_value],
616 ) -> Result<()>;
617 fn next(&mut self) -> Result<()>;
618 fn eof(&self) -> bool;
619 fn column(&self, ctx: *mut sqlite3_context, i: c_int) -> Result<()>;
620 fn rowid(&self) -> Result<i64>;
621}
622
623use std::ffi::CStr;
624
625pub struct VTabArguments {
632 pub module_name: String,
637 pub database_name: String,
642
643 pub table_name: String,
648 pub arguments: Vec<String>,
652}
653
654fn c_string_to_string(c: &*const c_char) -> std::result::Result<String, Utf8Error> {
655 let bytes = unsafe { CStr::from_ptr(c.to_owned()).to_bytes() };
656 Ok(std::str::from_utf8(bytes)?.to_string())
657}
658fn process_create_args(
659 argc: c_int,
660 argv: *const *const c_char,
661) -> std::result::Result<VTabArguments, Utf8Error> {
662 let raw_args = unsafe { slice::from_raw_parts(argv, argc as usize) };
663 let mut args = Vec::with_capacity(argc as usize);
664 for arg in raw_args {
665 args.push(c_string_to_string(arg)?);
666 }
667
668 let module_name = args
671 .get(0)
672 .expect("argv[0] should be the name of the module")
673 .to_owned();
674 let database_name = args
675 .get(1)
676 .expect("argv[1] should be the name of the database the module is in")
677 .to_owned();
678 let table_name = args
679 .get(2)
680 .expect("argv[2] should be the name of the virtual table")
681 .to_owned();
682 let arguments = &args[3..];
683
684 Ok(VTabArguments {
685 module_name,
686 database_name,
687 table_name,
688 arguments: arguments.to_vec(),
689 })
690}
691unsafe extern "C" fn rust_create<'vtab, T>(
694 db: *mut sqlite3,
695 aux: *mut c_void,
696 argc: c_int,
697 argv: *const *const c_char,
698 pp_vtab: *mut *mut sqlite3_vtab,
699 err_msg: *mut *mut c_char,
700) -> c_int
701where
702 T: VTab<'vtab>,
703{
704 let aux = aux.cast::<T::Aux>();
705 let args = match process_create_args(argc, argv) {
706 Ok(args) => args,
707 Err(_) => return SQLITE_ERROR,
708 };
709 match T::create(db, aux.as_ref(), args) {
710 Ok((sql, vtab)) => match CString::new(sql) {
711 Ok(c_sql) => {
712 let rc = sqlitex_declare_vtab(db, c_sql.as_ptr());
713 if rc == SQLITE_OKAY {
714 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
715 *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
716 SQLITE_OKAY
717 } else {
718 rc
719 }
720 }
721 Err(_err) => SQLITE_ERROR,
722 },
723 Err(err) => {
724 if let ErrorKind::Message(msg) = err.kind() {
725 if let Ok(err) = mprintf(msg) {
726 *err_msg = err;
727 }
728 };
729 err.code()
730 }
731 }
732}
733
734unsafe extern "C" fn rust_connect<'vtab, T>(
737 db: *mut sqlite3,
738 aux: *mut c_void,
739 argc: c_int,
740 argv: *const *const c_char,
741 pp_vtab: *mut *mut sqlite3_vtab,
742 err_msg: *mut *mut c_char,
743) -> c_int
744where
745 T: VTab<'vtab>,
746{
747 let aux = aux.cast::<T::Aux>();
748 let args = match process_create_args(argc, argv) {
749 Ok(args) => args,
750 Err(_) => return SQLITE_ERROR,
751 };
752 match T::connect(db, aux.as_ref(), args) {
753 Ok((sql, vtab)) => match CString::new(sql) {
754 Ok(c_sql) => {
755 let rc = sqlitex_declare_vtab(db, c_sql.as_ptr());
756 if rc == SQLITE_OKAY {
757 let boxed_vtab: *mut T = Box::into_raw(Box::new(vtab));
758 *pp_vtab = boxed_vtab.cast::<sqlite3_vtab>();
759 SQLITE_OKAY
760 } else {
761 rc
762 }
763 }
764 Err(_err) => SQLITE_ERROR,
765 },
766 Err(err) => {
767 if let ErrorKind::Message(msg) = err.kind() {
768 if let Ok(err) = mprintf(msg) {
769 *err_msg = err;
770 }
771 };
772 err.code()
773 }
774 }
775}
776
777unsafe extern "C" fn rust_best_index<'vtab, T>(
780 vtab: *mut sqlite3_vtab,
781 index_info: *mut sqlite3_index_info,
782) -> c_int
783where
784 T: VTab<'vtab>,
785{
786 let vt = vtab.cast::<T>();
787 match (*vt).best_index(IndexInfo { index_info }) {
788 Ok(_) => SQLITE_OKAY,
789 Err(e) => match e {
790 BestIndexError::Constraint => SQLITE_CONSTRAINT,
791 BestIndexError::Error => SQLITE_ERROR,
792 },
793 }
794}
795
796unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
799where
800 T: VTab<'vtab>,
801{
802 if vtab.is_null() {
803 return SQLITE_OKAY;
804 }
805 let vtab = vtab.cast::<T>();
806 drop(Box::from_raw(vtab));
807 SQLITE_OKAY
808}
809
810unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut sqlite3_vtab) -> c_int
813where
814 T: VTab<'vtab>,
815{
816 if vtab.is_null() {
817 return SQLITE_OKAY;
818 }
819 let vt = vtab.cast::<T>();
820 match (*vt).destroy() {
821 Ok(_) => SQLITE_OKAY,
822 Err(err) => err.code(),
823 }
824}
825
826unsafe extern "C" fn rust_open<'vtab, T: 'vtab>(
829 vtab: *mut sqlite3_vtab,
830 pp_cursor: *mut *mut sqlite3_vtab_cursor,
831) -> c_int
832where
833 T: VTab<'vtab>,
834{
835 let vt = vtab.cast::<T>();
836 match (*vt).open() {
837 Ok(cursor) => {
838 let boxed_cursor: *mut T::Cursor = Box::into_raw(Box::new(cursor));
839 *pp_cursor = boxed_cursor.cast::<sqlite3_vtab_cursor>();
840 SQLITE_OKAY
841 }
842 Err(err) => err.code(),
843 }
844}
845
846#[derive(Debug)]
848pub enum UpdateOperation<'a> {
849 Delete(&'a *mut sqlite3_value),
850 Insert {
851 values: &'a [*mut sqlite3_value],
852 rowid: Option<&'a *mut sqlite3_value>,
853 },
854 Update {
855 _values: &'a [*mut sqlite3_value],
856 },
857}
858
859fn determine_update_operation<'a>(
860 argc: c_int,
861 argv: *mut *mut sqlite3_value,
862) -> UpdateOperation<'a> {
863 let args = unsafe { slice::from_raw_parts(argv, argc as usize) };
864
865 if argc == 1 {
867 return UpdateOperation::Delete(
868 args.get(0)
869 .expect("argv[0] should be non-null for DELETE operations"),
870 );
871 }
872
873 let argv0 = args
874 .get(0)
875 .expect("argv[0] should be defined on all non-delete operations");
876 let argv1 = args
877 .get(1)
878 .expect("argv[1] should be defined on all non-delete operations");
879
880 if value_type(argv1) == ValueType::Null {
883 let rowid = if value_type(argv0) == ValueType::Null {
884 None
885 } else {
886 Some(argv1)
887 };
888 UpdateOperation::Insert {
889 values: args
890 .get(2..)
891 .expect("argv[0-1] should be defined on INSERT operations"),
892 rowid,
893 }
894 }
895 else if argv0 == argv1 {
898 UpdateOperation::Update {
899 _values: args
900 .get(2..)
901 .expect("argv[0-1] should be defined on INSERT operations"),
902 }
903 }
904 else if true {
909 todo!();
910 } else {
911 todo!("some unsupported update operation?")
912 }
913}
914unsafe extern "C" fn rust_update<'vtab, T: 'vtab>(
917 vtab: *mut sqlite3_vtab,
918 argc: c_int,
919 argv: *mut *mut sqlite3_value,
920 p_rowid: *mut i64,
921) -> c_int
922where
923 T: VTabWriteable<'vtab>,
924{
925 let vt = vtab.cast::<T>();
926
927 match (*vt).update(determine_update_operation(argc, argv), p_rowid) {
928 Ok(_) => SQLITE_OKAY,
929 Err(err) => err.code(),
930 }
931}
932
933unsafe extern "C" fn rust_begin<'vtab, T: 'vtab>(vtab: *mut sqlite3_vtab) -> c_int
936where
937 T: VTabWriteableWithTransactions<'vtab>,
938{
939 let vt = vtab.cast::<T>();
940 match (*vt).begin() {
941 Ok(_) => SQLITE_OKAY,
942 Err(err) => err.code(),
943 }
944}
945
946unsafe extern "C" fn rust_sync<'vtab, T: 'vtab>(vtab: *mut sqlite3_vtab) -> c_int
949where
950 T: VTabWriteableWithTransactions<'vtab>,
951{
952 let vt = vtab.cast::<T>();
953 match (*vt).sync() {
954 Ok(_) => SQLITE_OKAY,
955 Err(err) => err.code(),
956 }
957}
958
959unsafe extern "C" fn rust_rollback<'vtab, T: 'vtab>(vtab: *mut sqlite3_vtab) -> c_int
962where
963 T: VTabWriteableWithTransactions<'vtab>,
964{
965 let vt = vtab.cast::<T>();
966 match (*vt).rollback() {
967 Ok(_) => SQLITE_OKAY,
968 Err(err) => err.code(),
969 }
970}
971
972unsafe extern "C" fn rust_commit<'vtab, T: 'vtab>(vtab: *mut sqlite3_vtab) -> c_int
975where
976 T: VTabWriteableWithTransactions<'vtab>,
977{
978 let vt = vtab.cast::<T>();
979 match (*vt).commit() {
980 Ok(_) => SQLITE_OKAY,
981 Err(err) => err.code(),
982 }
983}
984
985unsafe extern "C" fn rust_find_function<'vtab, T: 'vtab>(
988 _vtab: *mut sqlite3_vtab,
989 _n_arg: c_int,
990 _name: *const c_char,
991 _p_xfunc: *mut Option<unsafe extern "C" fn(*mut sqlite3_context, i32, *mut *mut sqlite3_value)>,
992 _p_p_arg: *mut *mut c_void,
993) -> c_int
994where
995 T: VTabWriteable<'vtab>,
996{
997 0
998}
999
1000unsafe extern "C" fn rust_close<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1003where
1004 C: VTabCursor,
1005{
1006 let cr = cursor.cast::<C>();
1007 drop(Box::from_raw(cr));
1008 SQLITE_OKAY
1009}
1010
1011unsafe extern "C" fn rust_filter<C>(
1014 cursor: *mut sqlite3_vtab_cursor,
1015 idx_num: c_int,
1016 idx_str: *const c_char,
1017 argc: c_int,
1018 argv: *mut *mut sqlite3_value,
1019) -> c_int
1020where
1021 C: VTabCursor,
1022{
1023 use std::str;
1024 let idx_name = if idx_str.is_null() {
1025 None
1026 } else {
1027 let c_slice = CStr::from_ptr(idx_str).to_bytes();
1028 Some(str::from_utf8_unchecked(c_slice))
1029 };
1030 let cr = cursor.cast::<C>();
1031 let args = slice::from_raw_parts_mut(argv, argc as usize);
1033 match (*cr).filter(idx_num, idx_name, args) {
1034 Ok(()) => SQLITE_OKAY,
1035 Err(err) => {
1036 if let ErrorKind::Message(msg) = err.kind() {
1037 if let Ok(err) = mprintf(msg) {
1038 (*(*cursor).pVtab).zErrMsg = err;
1039 }
1040 };
1041 err.code()
1042 }
1043 }
1044}
1045
1046unsafe extern "C" fn rust_next<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1049where
1050 C: VTabCursor,
1051{
1052 let cr = cursor.cast::<C>();
1053 match (*cr).next() {
1055 Ok(()) => SQLITE_OKAY,
1056 Err(err) => {
1057 if let ErrorKind::Message(msg) = err.kind() {
1058 if let Ok(err) = mprintf(msg) {
1059 (*(*cursor).pVtab).zErrMsg = err;
1060 }
1061 };
1062 err.code()
1063 }
1064 }
1065}
1066
1067unsafe extern "C" fn rust_eof<C>(cursor: *mut sqlite3_vtab_cursor) -> c_int
1070where
1071 C: VTabCursor,
1072{
1073 let cr = cursor.cast::<C>();
1074 (*cr).eof() as c_int
1075}
1076
1077unsafe extern "C" fn rust_column<C>(
1080 cursor: *mut sqlite3_vtab_cursor,
1081 ctx: *mut sqlite3_context,
1082 i: c_int,
1083) -> c_int
1084where
1085 C: VTabCursor,
1086{
1087 let cr = cursor.cast::<C>();
1088 match (*cr).column(ctx, i) {
1090 Ok(()) => SQLITE_OKAY,
1091 Err(err) => {
1092 if let ErrorKind::Message(msg) = err.kind() {
1093 if let Ok(err) = mprintf(msg) {
1094 (*(*cursor).pVtab).zErrMsg = err;
1095 }
1096 };
1097 err.code()
1098 }
1099 }
1100}
1101
1102unsafe extern "C" fn rust_rowid<C>(cursor: *mut sqlite3_vtab_cursor, p_rowid: *mut i64) -> c_int
1108where
1109 C: VTabCursor,
1110{
1111 let cr = cursor.cast::<C>();
1112 match (*cr).rowid() {
1113 Ok(rowid) => {
1114 *p_rowid = rowid;
1115 SQLITE_OKAY
1116 }
1117 Err(err) => err.code(),
1118 }
1119}