1use core::ffi::{c_char, c_void};
2use core::ptr::NonNull;
3
4use crate::error::{Error, ErrorCode, Result};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
8pub struct ApiVersion {
9 pub major: u16,
11 pub minor: u16,
13 pub patch: u16,
15}
16
17impl ApiVersion {
18 pub const fn new(major: u16, minor: u16, patch: u16) -> Self {
20 Self {
21 major,
22 minor,
23 patch,
24 }
25 }
26}
27
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub struct FeatureSet {
31 bits: u64,
32}
33
34impl FeatureSet {
35 pub const PREPARE_V3: FeatureSet = FeatureSet { bits: 1 << 0 };
37 pub const CREATE_FUNCTION_V2: FeatureSet = FeatureSet { bits: 1 << 1 };
39 pub const VIRTUAL_TABLES: FeatureSet = FeatureSet { bits: 1 << 2 };
41 pub const EXTENDED_ERRCODES: FeatureSet = FeatureSet { bits: 1 << 3 };
43 pub const WINDOW_FUNCTIONS: FeatureSet = FeatureSet { bits: 1 << 4 };
45 pub const KEYING: FeatureSet = FeatureSet { bits: 1 << 5 };
47
48 pub const fn empty() -> Self {
50 Self { bits: 0 }
51 }
52
53 pub const fn from_bits(bits: u64) -> Self {
55 Self { bits }
56 }
57
58 pub const fn bits(self) -> u64 {
60 self.bits
61 }
62
63 pub const fn contains(self, other: FeatureSet) -> bool {
65 (self.bits & other.bits) == other.bits
66 }
67}
68
69impl core::ops::BitOr for FeatureSet {
70 type Output = FeatureSet;
71
72 fn bitor(self, rhs: FeatureSet) -> FeatureSet {
73 FeatureSet {
74 bits: self.bits | rhs.bits,
75 }
76 }
77}
78
79impl core::ops::BitOrAssign for FeatureSet {
80 fn bitor_assign(&mut self, rhs: FeatureSet) {
81 self.bits |= rhs.bits;
82 }
83}
84
85impl core::ops::BitAnd for FeatureSet {
86 type Output = FeatureSet;
87
88 fn bitand(self, rhs: FeatureSet) -> FeatureSet {
89 FeatureSet {
90 bits: self.bits & rhs.bits,
91 }
92 }
93}
94
95impl core::ops::BitAndAssign for FeatureSet {
96 fn bitand_assign(&mut self, rhs: FeatureSet) {
97 self.bits &= rhs.bits;
98 }
99}
100
101impl core::ops::Not for FeatureSet {
102 type Output = FeatureSet;
103
104 fn not(self) -> FeatureSet {
105 FeatureSet { bits: !self.bits }
106 }
107}
108
109#[derive(Clone, Copy, Debug, PartialEq, Eq)]
111pub struct OpenFlags {
112 bits: u32,
113}
114
115impl OpenFlags {
116 pub const READ_ONLY: OpenFlags = OpenFlags { bits: 1 << 0 };
118 pub const READ_WRITE: OpenFlags = OpenFlags { bits: 1 << 1 };
120 pub const CREATE: OpenFlags = OpenFlags { bits: 1 << 2 };
122 pub const URI: OpenFlags = OpenFlags { bits: 1 << 3 };
124 pub const NO_MUTEX: OpenFlags = OpenFlags { bits: 1 << 4 };
126 pub const FULL_MUTEX: OpenFlags = OpenFlags { bits: 1 << 5 };
128 pub const SHARED_CACHE: OpenFlags = OpenFlags { bits: 1 << 6 };
130 pub const PRIVATE_CACHE: OpenFlags = OpenFlags { bits: 1 << 7 };
132 pub const EXRESCODE: OpenFlags = OpenFlags { bits: 1 << 8 };
134
135 pub const fn empty() -> Self {
137 Self { bits: 0 }
138 }
139
140 pub const fn from_bits(bits: u32) -> Self {
142 Self { bits }
143 }
144
145 pub const fn bits(self) -> u32 {
147 self.bits
148 }
149
150 pub const fn contains(self, other: OpenFlags) -> bool {
152 (self.bits & other.bits) == other.bits
153 }
154}
155
156impl core::ops::BitOr for OpenFlags {
157 type Output = OpenFlags;
158
159 fn bitor(self, rhs: OpenFlags) -> OpenFlags {
160 OpenFlags {
161 bits: self.bits | rhs.bits,
162 }
163 }
164}
165
166impl core::ops::BitOrAssign for OpenFlags {
167 fn bitor_assign(&mut self, rhs: OpenFlags) {
168 self.bits |= rhs.bits;
169 }
170}
171
172impl core::ops::BitAnd for OpenFlags {
173 type Output = OpenFlags;
174
175 fn bitand(self, rhs: OpenFlags) -> OpenFlags {
176 OpenFlags {
177 bits: self.bits & rhs.bits,
178 }
179 }
180}
181
182impl core::ops::BitAndAssign for OpenFlags {
183 fn bitand_assign(&mut self, rhs: OpenFlags) {
184 self.bits &= rhs.bits;
185 }
186}
187
188impl core::ops::Not for OpenFlags {
189 type Output = OpenFlags;
190
191 fn not(self) -> OpenFlags {
192 OpenFlags { bits: !self.bits }
193 }
194}
195
196pub struct OpenOptions<'a> {
198 pub flags: OpenFlags,
200 pub vfs: Option<&'a str>,
202}
203
204#[derive(Clone, Copy, Debug, PartialEq, Eq)]
206pub enum StepResult {
207 Row,
209 Done,
211}
212
213#[derive(Clone, Copy, Debug, PartialEq, Eq)]
215pub enum ValueType {
216 Null,
218 Integer,
220 Float,
222 Text,
224 Blob,
226}
227
228impl ValueType {
229 pub const fn from_code(code: i32) -> ValueType {
231 match code {
232 1 => ValueType::Integer,
233 2 => ValueType::Float,
234 3 => ValueType::Text,
235 4 => ValueType::Blob,
236 _ => ValueType::Null,
237 }
238 }
239
240 pub const fn to_code(self) -> i32 {
242 match self {
243 ValueType::Null => 5,
244 ValueType::Integer => 1,
245 ValueType::Float => 2,
246 ValueType::Text => 3,
247 ValueType::Blob => 4,
248 }
249 }
250}
251
252#[derive(Clone, Copy, Debug)]
261pub struct RawBytes {
262 pub ptr: *const u8,
264 pub len: usize,
266}
267
268impl RawBytes {
269 pub const fn empty() -> Self {
271 Self {
272 ptr: core::ptr::null(),
273 len: 0,
274 }
275 }
276
277 pub unsafe fn as_slice<'a>(self) -> &'a [u8] {
280 if self.ptr.is_null() {
281 return &[];
282 }
283 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
284 }
285
286 pub unsafe fn as_str<'a>(self) -> Option<&'a str> {
289 core::str::from_utf8(unsafe { self.as_slice() }).ok()
290 }
291
292 pub unsafe fn as_str_unchecked<'a>(self) -> &'a str {
295 unsafe { core::str::from_utf8_unchecked(self.as_slice()) }
296 }
297}
298
299#[derive(Clone, Copy, Debug, PartialEq, Eq)]
301pub struct FunctionFlags {
302 bits: u32,
303}
304
305impl FunctionFlags {
306 pub const DETERMINISTIC: FunctionFlags = FunctionFlags { bits: 1 << 0 };
308 pub const DIRECT_ONLY: FunctionFlags = FunctionFlags { bits: 1 << 1 };
310 pub const INNOCUOUS: FunctionFlags = FunctionFlags { bits: 1 << 2 };
312
313 pub const fn empty() -> Self {
315 Self { bits: 0 }
316 }
317
318 pub const fn from_bits(bits: u32) -> Self {
320 Self { bits }
321 }
322
323 pub const fn bits(self) -> u32 {
325 self.bits
326 }
327
328 pub const fn contains(self, other: FunctionFlags) -> bool {
330 (self.bits & other.bits) == other.bits
331 }
332}
333
334impl core::ops::BitOr for FunctionFlags {
335 type Output = FunctionFlags;
336
337 fn bitor(self, rhs: FunctionFlags) -> FunctionFlags {
338 FunctionFlags {
339 bits: self.bits | rhs.bits,
340 }
341 }
342}
343
344impl core::ops::BitOrAssign for FunctionFlags {
345 fn bitor_assign(&mut self, rhs: FunctionFlags) {
346 self.bits |= rhs.bits;
347 }
348}
349
350impl core::ops::BitAnd for FunctionFlags {
351 type Output = FunctionFlags;
352
353 fn bitand(self, rhs: FunctionFlags) -> FunctionFlags {
354 FunctionFlags {
355 bits: self.bits & rhs.bits,
356 }
357 }
358}
359
360impl core::ops::BitAndAssign for FunctionFlags {
361 fn bitand_assign(&mut self, rhs: FunctionFlags) {
362 self.bits &= rhs.bits;
363 }
364}
365
366impl core::ops::Not for FunctionFlags {
367 type Output = FunctionFlags;
368
369 fn not(self) -> FunctionFlags {
370 FunctionFlags { bits: !self.bits }
371 }
372}
373
374#[allow(clippy::missing_safety_doc, clippy::too_many_arguments)]
379pub unsafe trait Sqlite3Api: Send + Sync + 'static {
380 type Db;
382 type Stmt;
384 type Value;
386 type Context;
388 type VTab;
390 type VTabCursor;
392
393 fn api_version(&self) -> ApiVersion;
395 fn feature_set(&self) -> FeatureSet;
397 fn backend_name(&self) -> &'static str;
399 fn backend_version(&self) -> Option<ApiVersion>;
401 unsafe fn malloc(&self, size: usize) -> *mut c_void;
406 unsafe fn free(&self, ptr: *mut c_void);
408 fn threadsafe(&self) -> i32 {
410 0
411 }
412
413 unsafe fn open(&self, filename: &str, options: OpenOptions<'_>) -> Result<NonNull<Self::Db>>;
415 unsafe fn close(&self, db: NonNull<Self::Db>) -> Result<()>;
417
418 unsafe fn prepare_v2(&self, db: NonNull<Self::Db>, sql: &str) -> Result<NonNull<Self::Stmt>>;
420 unsafe fn prepare_v3(
422 &self,
423 db: NonNull<Self::Db>,
424 sql: &str,
425 flags: u32,
426 ) -> Result<NonNull<Self::Stmt>>;
427
428 unsafe fn step(&self, stmt: NonNull<Self::Stmt>) -> Result<StepResult>;
430 unsafe fn reset(&self, stmt: NonNull<Self::Stmt>) -> Result<()>;
432 unsafe fn finalize(&self, stmt: NonNull<Self::Stmt>) -> Result<()>;
434
435 unsafe fn bind_null(&self, stmt: NonNull<Self::Stmt>, idx: i32) -> Result<()>;
437 unsafe fn bind_int64(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: i64) -> Result<()>;
439 unsafe fn bind_double(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: f64) -> Result<()>;
441 unsafe fn bind_text(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: &str) -> Result<()>;
445 unsafe fn bind_text_bytes(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: &[u8]) -> Result<()> {
451 match core::str::from_utf8(v) {
452 Ok(text) => unsafe { self.bind_text(stmt, idx, text) },
453 Err(_) => Err(Error::with_message(ErrorCode::Misuse, "invalid utf-8 text")),
454 }
455 }
456 unsafe fn bind_blob(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: &[u8]) -> Result<()>;
460
461 unsafe fn column_count(&self, stmt: NonNull<Self::Stmt>) -> i32;
463 unsafe fn column_type(&self, stmt: NonNull<Self::Stmt>, col: i32) -> ValueType;
465 unsafe fn column_int64(&self, stmt: NonNull<Self::Stmt>, col: i32) -> i64;
467 unsafe fn column_double(&self, stmt: NonNull<Self::Stmt>, col: i32) -> f64;
469 unsafe fn column_text(&self, stmt: NonNull<Self::Stmt>, col: i32) -> RawBytes;
471 unsafe fn column_blob(&self, stmt: NonNull<Self::Stmt>, col: i32) -> RawBytes;
473
474 unsafe fn errcode(&self, db: NonNull<Self::Db>) -> i32;
476 unsafe fn errmsg(&self, db: NonNull<Self::Db>) -> *const c_char;
478 unsafe fn extended_errcode(&self, db: NonNull<Self::Db>) -> Option<i32>;
480
481 unsafe fn create_function_v2(
497 &self,
498 db: NonNull<Self::Db>,
499 name: &str,
500 n_args: i32,
501 flags: FunctionFlags,
502 x_func: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
503 x_step: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
504 x_final: Option<extern "C" fn(*mut Self::Context)>,
505 user_data: *mut c_void,
506 drop_user_data: Option<extern "C" fn(*mut c_void)>,
507 ) -> Result<()>;
508
509 unsafe fn create_window_function(
525 &self,
526 db: NonNull<Self::Db>,
527 name: &str,
528 n_args: i32,
529 flags: FunctionFlags,
530 x_step: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
531 x_final: Option<extern "C" fn(*mut Self::Context)>,
532 x_value: Option<extern "C" fn(*mut Self::Context)>,
533 x_inverse: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
534 user_data: *mut c_void,
535 drop_user_data: Option<extern "C" fn(*mut c_void)>,
536 ) -> Result<()>;
537
538 unsafe fn create_collation_v2(
544 &self,
545 _db: NonNull<Self::Db>,
546 _name: &str,
547 _enc: i32,
548 _context: *mut c_void,
549 _cmp: Option<extern "C" fn(*mut c_void, i32, *const c_void, i32, *const c_void) -> i32>,
550 _destroy: Option<extern "C" fn(*mut c_void)>,
551 ) -> Result<()> {
552 Err(Error::feature_unavailable(
553 "create_collation_v2 unsupported",
554 ))
555 }
556
557 unsafe fn aggregate_context(&self, ctx: NonNull<Self::Context>, bytes: usize) -> *mut c_void;
559
560 unsafe fn result_null(&self, ctx: NonNull<Self::Context>);
562 unsafe fn result_int64(&self, ctx: NonNull<Self::Context>, v: i64);
564 unsafe fn result_double(&self, ctx: NonNull<Self::Context>, v: f64);
566 unsafe fn result_text(&self, ctx: NonNull<Self::Context>, v: &str);
568 unsafe fn result_text_bytes(&self, ctx: NonNull<Self::Context>, v: &[u8]) {
573 match core::str::from_utf8(v) {
574 Ok(text) => unsafe { self.result_text(ctx, text) },
575 Err(_) => unsafe { self.result_error(ctx, "invalid utf-8") },
576 }
577 }
578 unsafe fn result_blob(&self, ctx: NonNull<Self::Context>, v: &[u8]);
580 unsafe fn result_error(&self, ctx: NonNull<Self::Context>, msg: &str);
582 unsafe fn user_data(ctx: NonNull<Self::Context>) -> *mut c_void;
584
585 unsafe fn value_type(&self, v: NonNull<Self::Value>) -> ValueType;
587 unsafe fn value_int64(&self, v: NonNull<Self::Value>) -> i64;
589 unsafe fn value_double(&self, v: NonNull<Self::Value>) -> f64;
591 unsafe fn value_text(&self, v: NonNull<Self::Value>) -> RawBytes;
593 unsafe fn value_blob(&self, v: NonNull<Self::Value>) -> RawBytes;
595
596 unsafe fn declare_vtab(&self, db: NonNull<Self::Db>, schema: &str) -> Result<()>;
598
599 unsafe fn create_module_v2(
601 &self,
602 db: NonNull<Self::Db>,
603 name: &str,
604 module: &'static sqlite3_module<Self>,
605 user_data: *mut c_void,
606 drop_user_data: Option<extern "C" fn(*mut c_void)>,
607 ) -> Result<()>
608 where
609 Self: Sized;
610}
611
612#[allow(clippy::missing_safety_doc)]
618pub unsafe trait Sqlite3Keying: Sqlite3Api {
619 unsafe fn key(&self, db: NonNull<Self::Db>, key: &[u8]) -> Result<()>;
621 unsafe fn rekey(&self, db: NonNull<Self::Db>, key: &[u8]) -> Result<()>;
623}
624
625#[derive(Clone, Copy, Debug)]
627pub struct OwnedBytes {
628 pub ptr: NonNull<u8>,
630 pub len: usize,
632}
633
634#[allow(clippy::missing_safety_doc)]
640pub unsafe trait Sqlite3Hooks: Sqlite3Api {
641 unsafe fn trace_v2(
643 &self,
644 db: NonNull<Self::Db>,
645 mask: u32,
646 callback: Option<extern "C" fn(u32, *mut c_void, *mut c_void, *mut c_void)>,
647 context: *mut c_void,
648 ) -> Result<()>;
649 unsafe fn progress_handler(
651 &self,
652 db: NonNull<Self::Db>,
653 n: i32,
654 callback: Option<extern "C" fn(*mut c_void) -> i32>,
655 context: *mut c_void,
656 ) -> Result<()>;
657 unsafe fn busy_timeout(&self, db: NonNull<Self::Db>, ms: i32) -> Result<()>;
659 unsafe fn set_authorizer(
661 &self,
662 db: NonNull<Self::Db>,
663 callback: Option<
664 extern "C" fn(
665 *mut c_void,
666 i32,
667 *const c_char,
668 *const c_char,
669 *const c_char,
670 *const c_char,
671 ) -> i32,
672 >,
673 context: *mut c_void,
674 ) -> Result<()>;
675}
676
677#[allow(clippy::missing_safety_doc)]
683pub unsafe trait Sqlite3Backup: Sqlite3Api {
684 type Backup;
686 unsafe fn backup_init(
688 &self,
689 dest_db: NonNull<Self::Db>,
690 dest_name: &str,
691 source_db: NonNull<Self::Db>,
692 source_name: &str,
693 ) -> Result<NonNull<Self::Backup>>;
694 unsafe fn backup_step(&self, backup: NonNull<Self::Backup>, pages: i32) -> Result<()>;
696 unsafe fn backup_remaining(&self, backup: NonNull<Self::Backup>) -> i32;
698 unsafe fn backup_pagecount(&self, backup: NonNull<Self::Backup>) -> i32;
700 unsafe fn backup_finish(&self, backup: NonNull<Self::Backup>) -> Result<()>;
702}
703
704#[allow(clippy::missing_safety_doc)]
710pub unsafe trait Sqlite3BlobIo: Sqlite3Api {
711 type Blob;
713 unsafe fn blob_open(
715 &self,
716 db: NonNull<Self::Db>,
717 db_name: &str,
718 table: &str,
719 column: &str,
720 rowid: i64,
721 flags: u32,
722 ) -> Result<NonNull<Self::Blob>>;
723 unsafe fn blob_read(
725 &self,
726 blob: NonNull<Self::Blob>,
727 data: &mut [u8],
728 offset: i32,
729 ) -> Result<()>;
730 unsafe fn blob_write(&self, blob: NonNull<Self::Blob>, data: &[u8], offset: i32) -> Result<()>;
732 unsafe fn blob_bytes(&self, blob: NonNull<Self::Blob>) -> i32;
734 unsafe fn blob_close(&self, blob: NonNull<Self::Blob>) -> Result<()>;
736}
737
738#[allow(clippy::missing_safety_doc)]
744pub unsafe trait Sqlite3Serialize: Sqlite3Api {
745 unsafe fn serialize(
747 &self,
748 db: NonNull<Self::Db>,
749 schema: Option<&str>,
750 flags: u32,
751 ) -> Result<OwnedBytes>;
752 unsafe fn deserialize(
754 &self,
755 db: NonNull<Self::Db>,
756 schema: Option<&str>,
757 data: &[u8],
758 flags: u32,
759 ) -> Result<()>;
760 unsafe fn free(&self, bytes: OwnedBytes);
762}
763
764#[allow(clippy::missing_safety_doc)]
770pub unsafe trait Sqlite3Wal: Sqlite3Api {
771 unsafe fn wal_checkpoint(&self, db: NonNull<Self::Db>, db_name: Option<&str>) -> Result<()>;
773 unsafe fn wal_checkpoint_v2(
775 &self,
776 db: NonNull<Self::Db>,
777 db_name: Option<&str>,
778 mode: i32,
779 ) -> Result<(i32, i32)>;
780 unsafe fn wal_frame_count(&self, db: NonNull<Self::Db>) -> Result<Option<u32>>;
782}
783
784#[allow(clippy::missing_safety_doc)]
790pub unsafe trait Sqlite3Metadata: Sqlite3Api {
791 unsafe fn table_column_metadata(
793 &self,
794 db: NonNull<Self::Db>,
795 db_name: Option<&str>,
796 table: &str,
797 column: &str,
798 ) -> Result<ColumnMetadata>;
799 unsafe fn column_decltype(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes>;
801 unsafe fn column_name(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes>;
803 unsafe fn column_table_name(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes>;
805}
806
807#[derive(Clone, Copy, Debug)]
809pub struct ColumnMetadata {
810 pub data_type: Option<RawBytes>,
812 pub coll_seq: Option<RawBytes>,
814 pub not_null: bool,
816 pub primary_key: bool,
818 pub autoinc: bool,
820}
821
822#[repr(C)]
824pub struct sqlite3_module<P: Sqlite3Api> {
825 pub i_version: i32,
827 pub x_create: Option<
829 extern "C" fn(
830 *mut P::Db,
831 *mut c_void,
832 i32,
833 *const *const u8,
834 *mut *mut P::VTab,
835 *mut *mut u8,
836 ) -> i32,
837 >,
838 pub x_connect: Option<
840 extern "C" fn(
841 *mut P::Db,
842 *mut c_void,
843 i32,
844 *const *const u8,
845 *mut *mut P::VTab,
846 *mut *mut u8,
847 ) -> i32,
848 >,
849 pub x_best_index: Option<extern "C" fn(*mut P::VTab, *mut c_void) -> i32>,
851 pub x_disconnect: Option<extern "C" fn(*mut P::VTab) -> i32>,
853 pub x_destroy: Option<extern "C" fn(*mut P::VTab) -> i32>,
855 pub x_open: Option<extern "C" fn(*mut P::VTab, *mut *mut P::VTabCursor) -> i32>,
857 pub x_close: Option<extern "C" fn(*mut P::VTabCursor) -> i32>,
859 pub x_filter:
861 Option<extern "C" fn(*mut P::VTabCursor, i32, *const u8, i32, *mut *mut P::Value) -> i32>,
862 pub x_next: Option<extern "C" fn(*mut P::VTabCursor) -> i32>,
864 pub x_eof: Option<extern "C" fn(*mut P::VTabCursor) -> i32>,
866 pub x_column: Option<extern "C" fn(*mut P::VTabCursor, *mut P::Context, i32) -> i32>,
868 pub x_rowid: Option<extern "C" fn(*mut P::VTabCursor, *mut i64) -> i32>,
870}