1use core::ffi::{c_char, c_void};
2use core::ptr::NonNull;
3
4use crate::error::Result;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
8pub struct ApiVersion {
9 pub major: u16,
10 pub minor: u16,
11 pub patch: u16,
12}
13
14impl ApiVersion {
15 pub const fn new(major: u16, minor: u16, patch: u16) -> Self {
16 Self { major, minor, patch }
17 }
18}
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub struct FeatureSet {
23 bits: u64,
24}
25
26impl FeatureSet {
27 pub const PREPARE_V3: FeatureSet = FeatureSet { bits: 1 << 0 };
28 pub const CREATE_FUNCTION_V2: FeatureSet = FeatureSet { bits: 1 << 1 };
29 pub const VIRTUAL_TABLES: FeatureSet = FeatureSet { bits: 1 << 2 };
30 pub const EXTENDED_ERRCODES: FeatureSet = FeatureSet { bits: 1 << 3 };
31 pub const WINDOW_FUNCTIONS: FeatureSet = FeatureSet { bits: 1 << 4 };
32 pub const KEYING: FeatureSet = FeatureSet { bits: 1 << 5 };
33
34 pub const fn empty() -> Self {
35 Self { bits: 0 }
36 }
37
38 pub const fn from_bits(bits: u64) -> Self {
39 Self { bits }
40 }
41
42 pub const fn bits(self) -> u64 {
43 self.bits
44 }
45
46 pub const fn contains(self, other: FeatureSet) -> bool {
47 (self.bits & other.bits) == other.bits
48 }
49}
50
51impl core::ops::BitOr for FeatureSet {
52 type Output = FeatureSet;
53
54 fn bitor(self, rhs: FeatureSet) -> FeatureSet {
55 FeatureSet { bits: self.bits | rhs.bits }
56 }
57}
58
59impl core::ops::BitOrAssign for FeatureSet {
60 fn bitor_assign(&mut self, rhs: FeatureSet) {
61 self.bits |= rhs.bits;
62 }
63}
64
65impl core::ops::BitAnd for FeatureSet {
66 type Output = FeatureSet;
67
68 fn bitand(self, rhs: FeatureSet) -> FeatureSet {
69 FeatureSet { bits: self.bits & rhs.bits }
70 }
71}
72
73impl core::ops::BitAndAssign for FeatureSet {
74 fn bitand_assign(&mut self, rhs: FeatureSet) {
75 self.bits &= rhs.bits;
76 }
77}
78
79impl core::ops::Not for FeatureSet {
80 type Output = FeatureSet;
81
82 fn not(self) -> FeatureSet {
83 FeatureSet { bits: !self.bits }
84 }
85}
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq)]
89pub struct OpenFlags {
90 bits: u32,
91}
92
93impl OpenFlags {
94 pub const READ_ONLY: OpenFlags = OpenFlags { bits: 1 << 0 };
95 pub const READ_WRITE: OpenFlags = OpenFlags { bits: 1 << 1 };
96 pub const CREATE: OpenFlags = OpenFlags { bits: 1 << 2 };
97 pub const URI: OpenFlags = OpenFlags { bits: 1 << 3 };
98 pub const NO_MUTEX: OpenFlags = OpenFlags { bits: 1 << 4 };
99 pub const FULL_MUTEX: OpenFlags = OpenFlags { bits: 1 << 5 };
100 pub const SHARED_CACHE: OpenFlags = OpenFlags { bits: 1 << 6 };
101 pub const PRIVATE_CACHE: OpenFlags = OpenFlags { bits: 1 << 7 };
102 pub const EXRESCODE: OpenFlags = OpenFlags { bits: 1 << 8 };
103
104 pub const fn empty() -> Self {
105 Self { bits: 0 }
106 }
107
108 pub const fn from_bits(bits: u32) -> Self {
109 Self { bits }
110 }
111
112 pub const fn bits(self) -> u32 {
113 self.bits
114 }
115
116 pub const fn contains(self, other: OpenFlags) -> bool {
117 (self.bits & other.bits) == other.bits
118 }
119}
120
121impl core::ops::BitOr for OpenFlags {
122 type Output = OpenFlags;
123
124 fn bitor(self, rhs: OpenFlags) -> OpenFlags {
125 OpenFlags { bits: self.bits | rhs.bits }
126 }
127}
128
129impl core::ops::BitOrAssign for OpenFlags {
130 fn bitor_assign(&mut self, rhs: OpenFlags) {
131 self.bits |= rhs.bits;
132 }
133}
134
135impl core::ops::BitAnd for OpenFlags {
136 type Output = OpenFlags;
137
138 fn bitand(self, rhs: OpenFlags) -> OpenFlags {
139 OpenFlags { bits: self.bits & rhs.bits }
140 }
141}
142
143impl core::ops::BitAndAssign for OpenFlags {
144 fn bitand_assign(&mut self, rhs: OpenFlags) {
145 self.bits &= rhs.bits;
146 }
147}
148
149impl core::ops::Not for OpenFlags {
150 type Output = OpenFlags;
151
152 fn not(self) -> OpenFlags {
153 OpenFlags { bits: !self.bits }
154 }
155}
156
157pub struct OpenOptions<'a> {
159 pub flags: OpenFlags,
160 pub vfs: Option<&'a str>,
161}
162
163#[derive(Clone, Copy, Debug, PartialEq, Eq)]
165pub enum StepResult {
166 Row,
167 Done,
168}
169
170#[derive(Clone, Copy, Debug, PartialEq, Eq)]
172pub enum ValueType {
173 Null,
174 Integer,
175 Float,
176 Text,
177 Blob,
178}
179
180impl ValueType {
181 pub const fn from_code(code: i32) -> ValueType {
182 match code {
183 1 => ValueType::Integer,
184 2 => ValueType::Float,
185 3 => ValueType::Text,
186 4 => ValueType::Blob,
187 _ => ValueType::Null,
188 }
189 }
190
191 pub const fn to_code(self) -> i32 {
192 match self {
193 ValueType::Null => 5,
194 ValueType::Integer => 1,
195 ValueType::Float => 2,
196 ValueType::Text => 3,
197 ValueType::Blob => 4,
198 }
199 }
200}
201
202#[derive(Clone, Copy, Debug)]
208pub struct RawBytes {
209 pub ptr: *const u8,
210 pub len: usize,
211}
212
213impl RawBytes {
214 pub const fn empty() -> Self {
215 Self { ptr: core::ptr::null(), len: 0 }
216 }
217
218 pub unsafe fn as_slice<'a>(self) -> &'a [u8] {
221 if self.ptr.is_null() {
222 return &[];
223 }
224 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
225 }
226
227 pub unsafe fn as_str<'a>(self) -> Option<&'a str> {
230 core::str::from_utf8(unsafe { self.as_slice() }).ok()
231 }
232
233 pub unsafe fn as_str_unchecked<'a>(self) -> &'a str {
236 unsafe { core::str::from_utf8_unchecked(self.as_slice()) }
237 }
238}
239
240#[derive(Clone, Copy, Debug, PartialEq, Eq)]
242pub struct FunctionFlags {
243 bits: u32,
244}
245
246impl FunctionFlags {
247 pub const DETERMINISTIC: FunctionFlags = FunctionFlags { bits: 1 << 0 };
248 pub const DIRECT_ONLY: FunctionFlags = FunctionFlags { bits: 1 << 1 };
249 pub const INNOCUOUS: FunctionFlags = FunctionFlags { bits: 1 << 2 };
250
251 pub const fn empty() -> Self {
252 Self { bits: 0 }
253 }
254
255 pub const fn from_bits(bits: u32) -> Self {
256 Self { bits }
257 }
258
259 pub const fn bits(self) -> u32 {
260 self.bits
261 }
262
263 pub const fn contains(self, other: FunctionFlags) -> bool {
264 (self.bits & other.bits) == other.bits
265 }
266}
267
268impl core::ops::BitOr for FunctionFlags {
269 type Output = FunctionFlags;
270
271 fn bitor(self, rhs: FunctionFlags) -> FunctionFlags {
272 FunctionFlags { bits: self.bits | rhs.bits }
273 }
274}
275
276impl core::ops::BitOrAssign for FunctionFlags {
277 fn bitor_assign(&mut self, rhs: FunctionFlags) {
278 self.bits |= rhs.bits;
279 }
280}
281
282impl core::ops::BitAnd for FunctionFlags {
283 type Output = FunctionFlags;
284
285 fn bitand(self, rhs: FunctionFlags) -> FunctionFlags {
286 FunctionFlags { bits: self.bits & rhs.bits }
287 }
288}
289
290impl core::ops::BitAndAssign for FunctionFlags {
291 fn bitand_assign(&mut self, rhs: FunctionFlags) {
292 self.bits &= rhs.bits;
293 }
294}
295
296impl core::ops::Not for FunctionFlags {
297 type Output = FunctionFlags;
298
299 fn not(self) -> FunctionFlags {
300 FunctionFlags { bits: !self.bits }
301 }
302}
303
304#[allow(clippy::missing_safety_doc, clippy::too_many_arguments)]
309pub unsafe trait Sqlite3Api: Send + Sync + 'static {
310 type Db;
311 type Stmt;
312 type Value;
313 type Context;
314 type VTab;
315 type VTabCursor;
316
317 fn api_version(&self) -> ApiVersion;
318 fn feature_set(&self) -> FeatureSet;
319 fn backend_name(&self) -> &'static str;
320 fn backend_version(&self) -> Option<ApiVersion>;
321
322 unsafe fn open(&self, filename: &str, options: OpenOptions<'_>) -> Result<NonNull<Self::Db>>;
323 unsafe fn close(&self, db: NonNull<Self::Db>) -> Result<()>;
324
325 unsafe fn prepare_v2(&self, db: NonNull<Self::Db>, sql: &str) -> Result<NonNull<Self::Stmt>>;
326 unsafe fn prepare_v3(
327 &self,
328 db: NonNull<Self::Db>,
329 sql: &str,
330 flags: u32,
331 ) -> Result<NonNull<Self::Stmt>>;
332
333 unsafe fn step(&self, stmt: NonNull<Self::Stmt>) -> Result<StepResult>;
334 unsafe fn reset(&self, stmt: NonNull<Self::Stmt>) -> Result<()>;
335 unsafe fn finalize(&self, stmt: NonNull<Self::Stmt>) -> Result<()>;
336
337 unsafe fn bind_null(&self, stmt: NonNull<Self::Stmt>, idx: i32) -> Result<()>;
338 unsafe fn bind_int64(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: i64) -> Result<()>;
339 unsafe fn bind_double(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: f64) -> Result<()>;
340 unsafe fn bind_text(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: &str) -> Result<()>;
341 unsafe fn bind_blob(&self, stmt: NonNull<Self::Stmt>, idx: i32, v: &[u8]) -> Result<()>;
342
343 unsafe fn column_count(&self, stmt: NonNull<Self::Stmt>) -> i32;
344 unsafe fn column_type(&self, stmt: NonNull<Self::Stmt>, col: i32) -> ValueType;
345 unsafe fn column_int64(&self, stmt: NonNull<Self::Stmt>, col: i32) -> i64;
346 unsafe fn column_double(&self, stmt: NonNull<Self::Stmt>, col: i32) -> f64;
347 unsafe fn column_text(&self, stmt: NonNull<Self::Stmt>, col: i32) -> RawBytes;
348 unsafe fn column_blob(&self, stmt: NonNull<Self::Stmt>, col: i32) -> RawBytes;
349
350 unsafe fn errcode(&self, db: NonNull<Self::Db>) -> i32;
351 unsafe fn errmsg(&self, db: NonNull<Self::Db>) -> *const c_char;
352 unsafe fn extended_errcode(&self, db: NonNull<Self::Db>) -> Option<i32>;
353
354 unsafe fn create_function_v2(
355 &self,
356 db: NonNull<Self::Db>,
357 name: &str,
358 n_args: i32,
359 flags: FunctionFlags,
360 x_func: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
361 x_step: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
362 x_final: Option<extern "C" fn(*mut Self::Context)>,
363 user_data: *mut c_void,
364 drop_user_data: Option<extern "C" fn(*mut c_void)>,
365 ) -> Result<()>;
366
367 unsafe fn create_window_function(
368 &self,
369 db: NonNull<Self::Db>,
370 name: &str,
371 n_args: i32,
372 flags: FunctionFlags,
373 x_step: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
374 x_final: Option<extern "C" fn(*mut Self::Context)>,
375 x_value: Option<extern "C" fn(*mut Self::Context)>,
376 x_inverse: Option<extern "C" fn(*mut Self::Context, i32, *mut *mut Self::Value)>,
377 user_data: *mut c_void,
378 drop_user_data: Option<extern "C" fn(*mut c_void)>,
379 ) -> Result<()>;
380
381 unsafe fn aggregate_context(&self, ctx: NonNull<Self::Context>, bytes: usize) -> *mut c_void;
382
383 unsafe fn result_null(&self, ctx: NonNull<Self::Context>);
384 unsafe fn result_int64(&self, ctx: NonNull<Self::Context>, v: i64);
385 unsafe fn result_double(&self, ctx: NonNull<Self::Context>, v: f64);
386 unsafe fn result_text(&self, ctx: NonNull<Self::Context>, v: &str);
388 unsafe fn result_blob(&self, ctx: NonNull<Self::Context>, v: &[u8]);
390 unsafe fn result_error(&self, ctx: NonNull<Self::Context>, msg: &str);
391 unsafe fn user_data(ctx: NonNull<Self::Context>) -> *mut c_void;
392
393 unsafe fn value_type(&self, v: NonNull<Self::Value>) -> ValueType;
394 unsafe fn value_int64(&self, v: NonNull<Self::Value>) -> i64;
395 unsafe fn value_double(&self, v: NonNull<Self::Value>) -> f64;
396 unsafe fn value_text(&self, v: NonNull<Self::Value>) -> RawBytes;
397 unsafe fn value_blob(&self, v: NonNull<Self::Value>) -> RawBytes;
398
399 unsafe fn declare_vtab(&self, db: NonNull<Self::Db>, schema: &str) -> Result<()>;
401
402 unsafe fn create_module_v2(
403 &self,
404 db: NonNull<Self::Db>,
405 name: &str,
406 module: &'static sqlite3_module<Self>,
407 user_data: *mut c_void,
408 drop_user_data: Option<extern "C" fn(*mut c_void)>,
409 ) -> Result<()>
410 where
411 Self: Sized;
412}
413
414#[allow(clippy::missing_safety_doc)]
420pub unsafe trait Sqlite3Keying: Sqlite3Api {
421 unsafe fn key(&self, db: NonNull<Self::Db>, key: &[u8]) -> Result<()>;
422 unsafe fn rekey(&self, db: NonNull<Self::Db>, key: &[u8]) -> Result<()>;
423}
424
425#[derive(Clone, Copy, Debug)]
427pub struct OwnedBytes {
428 pub ptr: NonNull<u8>,
429 pub len: usize,
430}
431
432#[allow(clippy::missing_safety_doc)]
438pub unsafe trait Sqlite3Hooks: Sqlite3Api {
439 unsafe fn trace_v2(
440 &self,
441 db: NonNull<Self::Db>,
442 mask: u32,
443 callback: Option<extern "C" fn(u32, *mut c_void, *mut c_void, *mut c_void)>,
444 context: *mut c_void,
445 ) -> Result<()>;
446 unsafe fn progress_handler(
447 &self,
448 db: NonNull<Self::Db>,
449 n: i32,
450 callback: Option<extern "C" fn() -> i32>,
451 context: *mut c_void,
452 ) -> Result<()>;
453 unsafe fn busy_timeout(&self, db: NonNull<Self::Db>, ms: i32) -> Result<()>;
454 unsafe fn set_authorizer(
455 &self,
456 db: NonNull<Self::Db>,
457 callback: Option<
458 extern "C" fn(
459 *mut c_void,
460 i32,
461 *const c_char,
462 *const c_char,
463 *const c_char,
464 *const c_char,
465 ) -> i32,
466 >,
467 context: *mut c_void,
468 ) -> Result<()>;
469}
470
471#[allow(clippy::missing_safety_doc)]
477pub unsafe trait Sqlite3Backup: Sqlite3Api {
478 type Backup;
479 unsafe fn backup_init(
480 &self,
481 dest_db: NonNull<Self::Db>,
482 dest_name: &str,
483 source_db: NonNull<Self::Db>,
484 source_name: &str,
485 ) -> Result<NonNull<Self::Backup>>;
486 unsafe fn backup_step(&self, backup: NonNull<Self::Backup>, pages: i32) -> Result<()>;
487 unsafe fn backup_remaining(&self, backup: NonNull<Self::Backup>) -> i32;
488 unsafe fn backup_pagecount(&self, backup: NonNull<Self::Backup>) -> i32;
489 unsafe fn backup_finish(&self, backup: NonNull<Self::Backup>) -> Result<()>;
490}
491
492#[allow(clippy::missing_safety_doc)]
498pub unsafe trait Sqlite3BlobIo: Sqlite3Api {
499 type Blob;
500 unsafe fn blob_open(
501 &self,
502 db: NonNull<Self::Db>,
503 db_name: &str,
504 table: &str,
505 column: &str,
506 rowid: i64,
507 flags: u32,
508 ) -> Result<NonNull<Self::Blob>>;
509 unsafe fn blob_read(&self, blob: NonNull<Self::Blob>, data: &mut [u8], offset: i32)
510 -> Result<()>;
511 unsafe fn blob_write(&self, blob: NonNull<Self::Blob>, data: &[u8], offset: i32)
512 -> Result<()>;
513 unsafe fn blob_bytes(&self, blob: NonNull<Self::Blob>) -> i32;
514 unsafe fn blob_close(&self, blob: NonNull<Self::Blob>) -> Result<()>;
515}
516
517#[allow(clippy::missing_safety_doc)]
523pub unsafe trait Sqlite3Serialize: Sqlite3Api {
524 unsafe fn serialize(
525 &self,
526 db: NonNull<Self::Db>,
527 schema: Option<&str>,
528 flags: u32,
529 ) -> Result<OwnedBytes>;
530 unsafe fn deserialize(
531 &self,
532 db: NonNull<Self::Db>,
533 schema: Option<&str>,
534 data: &[u8],
535 flags: u32,
536 ) -> Result<()>;
537 unsafe fn free(&self, bytes: OwnedBytes);
538}
539
540#[allow(clippy::missing_safety_doc)]
546pub unsafe trait Sqlite3Wal: Sqlite3Api {
547 unsafe fn wal_checkpoint(&self, db: NonNull<Self::Db>, db_name: Option<&str>) -> Result<()>;
548 unsafe fn wal_checkpoint_v2(
549 &self,
550 db: NonNull<Self::Db>,
551 db_name: Option<&str>,
552 mode: i32,
553 ) -> Result<(i32, i32)>;
554 unsafe fn wal_frame_count(&self, db: NonNull<Self::Db>) -> Result<Option<u32>>;
555}
556
557#[allow(clippy::missing_safety_doc)]
563pub unsafe trait Sqlite3Metadata: Sqlite3Api {
564 unsafe fn table_column_metadata(
565 &self,
566 db: NonNull<Self::Db>,
567 db_name: Option<&str>,
568 table: &str,
569 column: &str,
570 ) -> Result<ColumnMetadata>;
571 unsafe fn column_decltype(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes>;
572 unsafe fn column_name(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes>;
573 unsafe fn column_table_name(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes>;
574}
575
576#[derive(Clone, Copy, Debug)]
578pub struct ColumnMetadata {
579 pub data_type: Option<RawBytes>,
580 pub coll_seq: Option<RawBytes>,
581 pub not_null: bool,
582 pub primary_key: bool,
583 pub autoinc: bool,
584}
585
586#[repr(C)]
588pub struct sqlite3_module<P: Sqlite3Api> {
589 pub i_version: i32,
590 pub x_create: Option<
591 extern "C" fn(
592 *mut P::Db,
593 *mut c_void,
594 i32,
595 *const *const u8,
596 *mut *mut P::VTab,
597 *mut *mut u8,
598 ) -> i32,
599 >,
600 pub x_connect: Option<
601 extern "C" fn(
602 *mut P::Db,
603 *mut c_void,
604 i32,
605 *const *const u8,
606 *mut *mut P::VTab,
607 *mut *mut u8,
608 ) -> i32,
609 >,
610 pub x_best_index: Option<extern "C" fn(*mut P::VTab, *mut c_void) -> i32>,
611 pub x_disconnect: Option<extern "C" fn(*mut P::VTab) -> i32>,
612 pub x_destroy: Option<extern "C" fn(*mut P::VTab) -> i32>,
613 pub x_open: Option<extern "C" fn(*mut P::VTab, *mut *mut P::VTabCursor) -> i32>,
614 pub x_close: Option<extern "C" fn(*mut P::VTabCursor) -> i32>,
615 pub x_filter: Option<
616 extern "C" fn(*mut P::VTabCursor, i32, *const u8, i32, *mut *mut P::Value) -> i32,
617 >,
618 pub x_next: Option<extern "C" fn(*mut P::VTabCursor) -> i32>,
619 pub x_eof: Option<extern "C" fn(*mut P::VTabCursor) -> i32>,
620 pub x_column: Option<extern "C" fn(*mut P::VTabCursor, *mut P::Context, i32) -> i32>,
621 pub x_rowid: Option<extern "C" fn(*mut P::VTabCursor, *mut i64) -> i32>,
622}