Skip to main content

sqlite_provider/
provider.rs

1use core::ffi::{c_char, c_void};
2use core::ptr::NonNull;
3
4use crate::error::Result;
5
6/// SQLite API version.
7#[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/// Backend feature flags exposed by the provider.
21#[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/// Flags for opening a database connection.
88#[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
157/// Options passed to `Sqlite3Api::open`.
158pub struct OpenOptions<'a> {
159    pub flags: OpenFlags,
160    pub vfs: Option<&'a str>,
161}
162
163/// Result of a `step` call.
164#[derive(Clone, Copy, Debug, PartialEq, Eq)]
165pub enum StepResult {
166    Row,
167    Done,
168}
169
170/// SQLite storage class for a value.
171#[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/// Raw view into SQLite-managed bytes.
203///
204/// The pointer/length are only valid until the next text/blob access on the same
205/// handle, or until the statement/value is reset or finalized. Callers that need
206/// longer-lived data must copy the bytes.
207#[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    /// # Safety
219    /// Caller must ensure the pointer/length remain valid for the returned slice.
220    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    /// # Safety
228    /// Caller must ensure the bytes are valid UTF-8 and remain valid for `'a`.
229    pub unsafe fn as_str<'a>(self) -> Option<&'a str> {
230        core::str::from_utf8(unsafe { self.as_slice() }).ok()
231    }
232
233    /// # Safety
234    /// Caller must ensure the bytes are valid UTF-8 and remain valid for `'a`.
235    pub unsafe fn as_str_unchecked<'a>(self) -> &'a str {
236        unsafe { core::str::from_utf8_unchecked(self.as_slice()) }
237    }
238}
239
240/// Function flags passed to `create_function_v2` / `create_window_function`.
241#[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/// Provider SPI over a SQLite C API backend.
305///
306/// # Safety
307/// Implementations must uphold the SQLite C ABI contracts.
308#[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    /// Providers must ensure SQLite copies or retains the buffer for `v`.
387    unsafe fn result_text(&self, ctx: NonNull<Self::Context>, v: &str);
388    /// Providers must ensure SQLite copies or retains the buffer for `v`.
389    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    /// Declare a virtual table schema during xCreate/xConnect.
400    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/// Optional backend extension for SQLCipher-style keying.
415///
416/// # Safety
417/// Implementations must uphold the same pointer and lifetime guarantees as
418/// `Sqlite3Api` for key material and database handles.
419#[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/// Bytes owned by the backend and freed via `Sqlite3Serialize::free`.
426#[derive(Clone, Copy, Debug)]
427pub struct OwnedBytes {
428    pub ptr: NonNull<u8>,
429    pub len: usize,
430}
431
432/// Optional backend extension for hooks (trace/progress/busy/authorizer).
433///
434/// # Safety
435/// Implementations must keep callback/context pointers valid per SQLite's hook
436/// registration contract and ensure callback ABI compatibility.
437#[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/// Optional backend extension for online backup.
472///
473/// # Safety
474/// Implementations must return backup handles tied to the provided database
475/// handles and honor SQLite's backup lifecycle requirements.
476#[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/// Optional backend extension for incremental blob I/O.
493///
494/// # Safety
495/// Implementations must validate offsets/buffer sizes and preserve SQLite blob
496/// handle validity across read/write operations.
497#[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/// Optional backend extension for serialize/deserialize.
518///
519/// # Safety
520/// Implementations must pair `serialize` allocations with `free`, and
521/// `deserialize` must not retain references to caller-owned `data`.
522#[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/// Optional backend extension for WAL helpers.
541///
542/// # Safety
543/// Implementations must only operate on valid database handles and obey SQLite
544/// checkpoint and WAL-state semantics.
545#[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/// Optional backend extension for metadata helpers.
558///
559/// # Safety
560/// Implementations must ensure returned raw metadata pointers are valid for the
561/// documented SQLite lifetime and ownership rules.
562#[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/// Column metadata returned by `Sqlite3Metadata`.
577#[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/// Typed wrapper for `sqlite3_module`.
587#[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}