Skip to main content

powersync_sqlite_nostd/
nostd.rs

1extern crate alloc;
2
3use alloc::boxed::Box;
4use alloc::ffi::{IntoStringError, NulError};
5use alloc::vec::Vec;
6use alloc::{ffi::CString, string::String};
7use core::array::TryFromSliceError;
8use core::cell::{BorrowError, BorrowMutError};
9use core::ffi::{CStr, c_char, c_int, c_void};
10use core::ptr::null_mut;
11use core::{error::Error, slice, str::Utf8Error};
12
13use num_derive::FromPrimitive;
14use num_traits::FromPrimitive;
15
16use crate::bindings;
17use crate::capi as sqlite3_capi;
18pub use crate::capi::*;
19
20// https://www.sqlite.org/c3ref/c_alter_table.html
21#[derive(FromPrimitive, PartialEq, Debug, Clone, Copy)]
22pub enum ActionCode {
23    COPY = 0,
24    CREATE_INDEX = 1,
25    CREATE_TABLE = 2,
26    CREATE_TEMP_INDEX = 3,
27    CREATE_TEMP_TABLE = 4,
28    CREATE_TEMP_TRIGGER = 5,
29    CREATE_TEMP_VIEW = 6,
30    CREATE_TRIGGER = 7,
31    CREATE_VIEW = 8,
32    DELETE = 9,
33    DROP_INDEX = 10,
34    DROP_TABLE = 11,
35    DROP_TEMP_INDEX = 12,
36    DROP_TEMP_TABLE = 13,
37    DROP_TEMP_TRIGGER = 14,
38    DROP_TEMP_VIEW = 15,
39    DROP_TRIGGER = 16,
40    DROP_VIEW = 17,
41    INSERT = 18,
42    PRAGMA = 19,
43    READ = 20,
44    SELECT = 21,
45    TRANSACTION = 22,
46    UPDATE = 23,
47    ATTACH = 24,
48    DETACH = 25,
49    ALTER_TABLE = 26,
50    REINDEX = 27,
51    ANALYZE = 28,
52    CREATE_VTABLE = 29,
53    DROP_VTABLE = 30,
54    FUNCTION = 31,
55    SAVEPOINT = 32,
56    RECURSIVE = 33,
57}
58
59#[derive(FromPrimitive, PartialEq, Debug, Clone, Copy)]
60pub enum ResultCode {
61    OK = 0,
62    ERROR = 1,
63    INTERNAL = 2,
64    PERM = 3,
65    ABORT = 4,
66    BUSY = 5,
67    LOCKED = 6,
68    NOMEM = 7,
69    READONLY = 8,
70    INTERRUPT = 9,
71    IOERR = 10,
72    CORRUPT = 11,
73    NOTFOUND = 12,
74    FULL = 13,
75    CANTOPEN = 14,
76    PROTOCOL = 15,
77    EMPTY = 16,
78    SCHEMA = 17,
79    TOOBIG = 18,
80    CONSTRAINT = 19,
81    MISMATCH = 20,
82    MISUSE = 21,
83    NOLFS = 22,
84    AUTH = 23,
85    FORMAT = 24,
86    RANGE = 25,
87    NOTADB = 26,
88    NOTICE = 27,
89    WARNING = 28,
90    ROW = 100,
91    DONE = 101,
92    ERROR_MISSING_COLLSEQ = bindings::SQLITE_ERROR_MISSING_COLLSEQ as isize,
93    ERROR_RETRY = bindings::SQLITE_ERROR_RETRY as isize,
94    ERROR_SNAPSHOT = bindings::SQLITE_ERROR_SNAPSHOT as isize,
95    IOERR_READ = bindings::SQLITE_IOERR_READ as isize,
96    IOERR_SHORT_READ = bindings::SQLITE_IOERR_SHORT_READ as isize,
97    IOERR_WRITE = bindings::SQLITE_IOERR_WRITE as isize,
98    IOERR_FSYNC = bindings::SQLITE_IOERR_FSYNC as isize,
99    IOERR_DIR_FSYNC = bindings::SQLITE_IOERR_DIR_FSYNC as isize,
100    IOERR_TRUNCATE = bindings::SQLITE_IOERR_TRUNCATE as isize,
101    IOERR_FSTAT = bindings::SQLITE_IOERR_FSTAT as isize,
102    IOERR_UNLOCK = bindings::SQLITE_IOERR_UNLOCK as isize,
103    IOERR_RDLOCK = bindings::SQLITE_IOERR_RDLOCK as isize,
104    IOERR_DELETE = bindings::SQLITE_IOERR_DELETE as isize,
105    IOERR_BLOCKED = bindings::SQLITE_IOERR_BLOCKED as isize,
106    IOERR_NOMEM = bindings::SQLITE_IOERR_NOMEM as isize,
107    IOERR_ACCESS = bindings::SQLITE_IOERR_ACCESS as isize,
108    IOERR_CHECKRESERVEDLOCK = bindings::SQLITE_IOERR_CHECKRESERVEDLOCK as isize,
109    IOERR_LOCK = bindings::SQLITE_IOERR_LOCK as isize,
110    IOERR_CLOSE = bindings::SQLITE_IOERR_CLOSE as isize,
111    IOERR_DIR_CLOSE = bindings::SQLITE_IOERR_DIR_CLOSE as isize,
112    IOERR_SHMOPEN = bindings::SQLITE_IOERR_SHMOPEN as isize,
113    IOERR_SHMSIZE = bindings::SQLITE_IOERR_SHMSIZE as isize,
114    IOERR_SHMLOCK = bindings::SQLITE_IOERR_SHMLOCK as isize,
115    IOERR_SHMMAP = bindings::SQLITE_IOERR_SHMMAP as isize,
116    IOERR_SEEK = bindings::SQLITE_IOERR_SEEK as isize,
117    IOERR_DELETE_NOENT = bindings::SQLITE_IOERR_DELETE_NOENT as isize,
118    IOERR_MMAP = bindings::SQLITE_IOERR_MMAP as isize,
119    IOERR_GETTEMPPATH = bindings::SQLITE_IOERR_GETTEMPPATH as isize,
120    IOERR_CONVPATH = bindings::SQLITE_IOERR_CONVPATH as isize,
121    IOERR_VNODE = bindings::SQLITE_IOERR_VNODE as isize,
122    IOERR_AUTH = bindings::SQLITE_IOERR_AUTH as isize,
123    IOERR_BEGIN_ATOMIC = bindings::SQLITE_IOERR_BEGIN_ATOMIC as isize,
124    IOERR_COMMIT_ATOMIC = bindings::SQLITE_IOERR_COMMIT_ATOMIC as isize,
125    IOERR_ROLLBACK_ATOMIC = bindings::SQLITE_IOERR_ROLLBACK_ATOMIC as isize,
126    IOERR_DATA = bindings::SQLITE_IOERR_DATA as isize,
127    IOERR_CORRUPTFS = bindings::SQLITE_IOERR_CORRUPTFS as isize,
128    LOCKED_SHAREDCACHE = bindings::SQLITE_LOCKED_SHAREDCACHE as isize,
129    LOCKED_VTAB = bindings::SQLITE_LOCKED_VTAB as isize,
130    BUSY_RECOVERY = bindings::SQLITE_BUSY_RECOVERY as isize,
131    BUSY_SNAPSHOT = bindings::SQLITE_BUSY_SNAPSHOT as isize,
132    BUSY_TIMEOUT = bindings::SQLITE_BUSY_TIMEOUT as isize,
133    CANTOPEN_NOTEMPDIR = bindings::SQLITE_CANTOPEN_NOTEMPDIR as isize,
134    CANTOPEN_ISDIR = bindings::SQLITE_CANTOPEN_ISDIR as isize,
135    CANTOPEN_FULLPATH = bindings::SQLITE_CANTOPEN_FULLPATH as isize,
136    CANTOPEN_CONVPATH = bindings::SQLITE_CANTOPEN_CONVPATH as isize,
137    CANTOPEN_DIRTYWAL = bindings::SQLITE_CANTOPEN_DIRTYWAL as isize,
138    CANTOPEN_SYMLINK = bindings::SQLITE_CANTOPEN_SYMLINK as isize,
139    CORRUPT_VTAB = bindings::SQLITE_CORRUPT_VTAB as isize,
140    CORRUPT_SEQUENCE = bindings::SQLITE_CORRUPT_SEQUENCE as isize,
141    CORRUPT_INDEX = bindings::SQLITE_CORRUPT_INDEX as isize,
142    READONLY_RECOVERY = bindings::SQLITE_READONLY_RECOVERY as isize,
143    READONLY_CANTLOCK = bindings::SQLITE_READONLY_CANTLOCK as isize,
144    READONLY_ROLLBACK = bindings::SQLITE_READONLY_ROLLBACK as isize,
145    READONLY_DBMOVED = bindings::SQLITE_READONLY_DBMOVED as isize,
146    READONLY_CANTINIT = bindings::SQLITE_READONLY_CANTINIT as isize,
147    READONLY_DIRECTORY = bindings::SQLITE_READONLY_DIRECTORY as isize,
148    ABORT_ROLLBACK = bindings::SQLITE_ABORT_ROLLBACK as isize,
149    CONSTRAINT_CHECK = bindings::SQLITE_CONSTRAINT_CHECK as isize,
150    CONSTRAINT_COMMITHOOK = bindings::SQLITE_CONSTRAINT_COMMITHOOK as isize,
151    CONSTRAINT_FOREIGNKEY = bindings::SQLITE_CONSTRAINT_FOREIGNKEY as isize,
152    CONSTRAINT_FUNCTION = bindings::SQLITE_CONSTRAINT_FUNCTION as isize,
153    CONSTRAINT_NOTNULL = bindings::SQLITE_CONSTRAINT_NOTNULL as isize,
154    CONSTRAINT_PRIMARYKEY = bindings::SQLITE_CONSTRAINT_PRIMARYKEY as isize,
155    CONSTRAINT_TRIGGER = bindings::SQLITE_CONSTRAINT_TRIGGER as isize,
156    CONSTRAINT_UNIQUE = bindings::SQLITE_CONSTRAINT_UNIQUE as isize,
157    CONSTRAINT_VTAB = bindings::SQLITE_CONSTRAINT_VTAB as isize,
158    CONSTRAINT_ROWID = bindings::SQLITE_CONSTRAINT_ROWID as isize,
159    CONSTRAINT_PINNED = bindings::SQLITE_CONSTRAINT_PINNED as isize,
160    CONSTRAINT_DATATYPE = bindings::SQLITE_CONSTRAINT_DATATYPE as isize,
161    NOTICE_RECOVER_WAL = bindings::SQLITE_NOTICE_RECOVER_WAL as isize,
162    NOTICE_RECOVER_ROLLBACK = bindings::SQLITE_NOTICE_RECOVER_ROLLBACK as isize,
163    WARNING_AUTOINDEX = bindings::SQLITE_WARNING_AUTOINDEX as isize,
164    AUTH_USER = bindings::SQLITE_AUTH_USER as isize,
165    OK_LOAD_PERMANENTLY = bindings::SQLITE_OK_LOAD_PERMANENTLY as isize,
166    OK_SYMLINK = bindings::SQLITE_OK_SYMLINK as isize,
167
168    NULL = 5000,
169}
170
171impl core::fmt::Display for ResultCode {
172    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
173        write!(f, "{:?}", self)
174    }
175}
176
177impl Error for ResultCode {}
178
179impl From<Utf8Error> for ResultCode {
180    fn from(_error: Utf8Error) -> Self {
181        ResultCode::FORMAT
182    }
183}
184
185impl From<TryFromSliceError> for ResultCode {
186    fn from(_error: TryFromSliceError) -> Self {
187        ResultCode::RANGE
188    }
189}
190
191impl From<NulError> for ResultCode {
192    fn from(_error: NulError) -> Self {
193        ResultCode::NOMEM
194    }
195}
196
197impl From<IntoStringError> for ResultCode {
198    fn from(_error: IntoStringError) -> Self {
199        ResultCode::FORMAT
200    }
201}
202
203impl From<BorrowError> for ResultCode {
204    fn from(_error: BorrowError) -> Self {
205        ResultCode::ERROR
206    }
207}
208
209impl From<BorrowMutError> for ResultCode {
210    fn from(_error: BorrowMutError) -> Self {
211        ResultCode::ERROR
212    }
213}
214
215impl From<String> for ResultCode {
216    fn from(_error: String) -> Self {
217        ResultCode::ERROR
218    }
219}
220
221#[derive(FromPrimitive, PartialEq, Debug, Clone, Copy)]
222pub enum ColumnType {
223    Integer = 1,
224    Float = 2,
225    Text = 3,
226    Blob = 4,
227    Null = 5,
228}
229
230pub fn open(filename: *const c_char) -> Result<ManagedConnection, ResultCode> {
231    let mut db = core::ptr::null_mut();
232    let rc =
233        ResultCode::from_i32(sqlite3_capi::open(filename, &mut db as *mut *mut sqlite3)).unwrap();
234    if rc == ResultCode::OK {
235        Ok(ManagedConnection { db })
236    } else {
237        Err(rc)
238    }
239}
240
241pub fn libversion() -> &'static str {
242    unsafe { CStr::from_ptr(sqlite3_capi::libversion()) }
243        .to_str()
244        .unwrap()
245}
246
247pub fn libversion_number() -> c_int {
248    sqlite3_capi::libversion_number()
249}
250
251pub fn randomness(blob: &mut [u8]) {
252    sqlite3_capi::randomness(blob.len() as c_int, blob.as_mut_ptr() as *mut c_void)
253}
254
255pub struct ManagedConnection {
256    pub db: *mut sqlite3,
257}
258
259pub trait Connection {
260    fn commit_hook(&self, callback: Option<xCommitHook>, user_data: *mut c_void) -> *mut c_void;
261
262    fn create_function_v2(
263        &self,
264        name: &str,
265        n_arg: i32,
266        flags: u32,
267        user_data: Option<*mut c_void>,
268        func: Option<xFunc>,
269        step: Option<xStep>,
270        final_func: Option<xFinal>,
271        destroy: Option<xDestroy>,
272    ) -> Result<ResultCode, ResultCode>;
273
274    fn create_module_v2(
275        &self,
276        name: &str,
277        module: *const module,
278        user_data: Option<*mut c_void>,
279        destroy: Option<xDestroy>,
280    ) -> Result<ResultCode, ResultCode>;
281
282    fn changes64(&self) -> i64;
283
284    fn errcode(&self) -> ResultCode;
285    fn errmsg(&self) -> Result<String, IntoStringError>;
286    fn error_offset(&self) -> Option<usize>;
287
288    /// sql should be a null terminated string! However you find is most efficient to craft those,
289    /// hence why we have no opinion on &str vs String vs CString vs whatever
290    /// todo: we should make some sort of opaque type to force null termination
291    /// this is inehritly unsafe
292    unsafe fn exec(&self, sql: *const c_char) -> Result<ResultCode, ResultCode>;
293
294    fn exec_safe(&self, sql: &str) -> Result<ResultCode, ResultCode>;
295
296    fn next_stmt(&self, s: Option<*mut stmt>) -> Option<*mut stmt>;
297
298    fn prepare_v2(&self, sql: &str) -> Result<ManagedStmt, ResultCode>;
299
300    fn prepare_v3(&self, sql: &str, flags: u32) -> Result<ManagedStmt, ResultCode>;
301
302    fn set_authorizer(
303        &self,
304        x_auth: Option<XAuthorizer>,
305        user_data: *mut c_void,
306    ) -> Result<ResultCode, ResultCode>;
307
308    fn rollback_hook(&self, callback: Option<xRollbackHook>, ctx: *mut c_void) -> *mut c_void;
309
310    fn update_hook(&self, callback: Option<xUpdateHook>, ctx: *mut c_void) -> *mut c_void;
311
312    fn get_autocommit(&self) -> bool;
313}
314
315impl Connection for ManagedConnection {
316    fn changes64(&self) -> i64 {
317        self.db.changes64()
318    }
319
320    fn commit_hook(&self, callback: Option<xCommitHook>, user_data: *mut c_void) -> *mut c_void {
321        self.db.commit_hook(callback, user_data)
322    }
323
324    /// TODO: create_function is infrequent enough that we can pay the cost of the copy rather than
325    /// take a c_char
326    fn create_function_v2(
327        &self,
328        name: &str,
329        n_arg: i32,
330        flags: u32,
331        user_data: Option<*mut c_void>,
332        func: Option<xFunc>,
333        step: Option<xStep>,
334        final_func: Option<xFinal>,
335        destroy: Option<xDestroy>,
336    ) -> Result<ResultCode, ResultCode> {
337        self.db.create_function_v2(
338            name, n_arg, flags, user_data, func, step, final_func, destroy,
339        )
340    }
341
342    fn set_authorizer(
343        &self,
344        x_auth: Option<XAuthorizer>,
345        user_data: *mut c_void,
346    ) -> Result<ResultCode, ResultCode> {
347        self.db.set_authorizer(x_auth, user_data)
348    }
349
350    fn create_module_v2(
351        &self,
352        name: &str,
353        module: *const module,
354        user_data: Option<*mut c_void>,
355        destroy: Option<xDestroy>,
356    ) -> Result<ResultCode, ResultCode> {
357        self.db.create_module_v2(name, module, user_data, destroy)
358    }
359
360    #[inline]
361    fn next_stmt(&self, s: Option<*mut stmt>) -> Option<*mut stmt> {
362        self.db.next_stmt(s)
363    }
364
365    #[inline]
366    fn prepare_v2(&self, sql: &str) -> Result<ManagedStmt, ResultCode> {
367        self.db.prepare_v2(sql)
368    }
369
370    #[inline]
371    fn prepare_v3(&self, sql: &str, flags: u32) -> Result<ManagedStmt, ResultCode> {
372        self.db.prepare_v3(sql, flags)
373    }
374
375    #[inline]
376    unsafe fn exec(&self, sql: *const c_char) -> Result<ResultCode, ResultCode> {
377        unsafe { self.db.exec(sql) }
378    }
379
380    #[inline]
381    fn exec_safe(&self, sql: &str) -> Result<ResultCode, ResultCode> {
382        self.db.exec_safe(sql)
383    }
384
385    #[inline]
386    fn errmsg(&self) -> Result<String, IntoStringError> {
387        self.db.errmsg()
388    }
389
390    #[inline]
391    fn errcode(&self) -> ResultCode {
392        self.db.errcode()
393    }
394
395    fn error_offset(&self) -> Option<usize> {
396        self.db.error_offset()
397    }
398
399    #[inline]
400    fn get_autocommit(&self) -> bool {
401        self.db.get_autocommit()
402    }
403
404    fn rollback_hook(&self, callback: Option<xRollbackHook>, ctx: *mut c_void) -> *mut c_void {
405        self.db.rollback_hook(callback, ctx)
406    }
407
408    fn update_hook(&self, callback: Option<xUpdateHook>, ctx: *mut c_void) -> *mut c_void {
409        self.db.update_hook(callback, ctx)
410    }
411}
412
413impl Drop for ManagedConnection {
414    fn drop(&mut self) {
415        // todo: iterate over all stmts and finalize them?
416        let rc = sqlite3_capi::close(self.db);
417        if rc != 0 {
418            // This seems aggressive...
419            // The alternative is to make users manually drop connections and manually finalize
420            // stmts :/
421            // Or we could not panic.. but then you will unknowningly have memory
422            // leaks in your app. The reason being that a failure to close the db
423            // does not release the memory of that db.
424            panic!(
425                "SQLite returned error {:?} when trying to close the db!",
426                rc
427            );
428        }
429    }
430}
431
432impl Connection for *mut sqlite3 {
433    fn changes64(&self) -> i64 {
434        changes64(*self)
435    }
436
437    fn commit_hook(&self, callback: Option<xCommitHook>, user_data: *mut c_void) -> *mut c_void {
438        commit_hook(*self, callback, user_data)
439    }
440
441    fn create_function_v2(
442        &self,
443        name: &str,
444        n_arg: i32,
445        flags: u32,
446        user_data: Option<*mut c_void>,
447        func: Option<xFunc>,
448        step: Option<xStep>,
449        final_func: Option<xFinal>,
450        destroy: Option<xDestroy>,
451    ) -> Result<ResultCode, ResultCode> {
452        if let Ok(name) = CString::new(name) {
453            convert_rc(create_function_v2(
454                *self,
455                name.as_ptr(),
456                n_arg,
457                flags as c_int,
458                user_data.unwrap_or(core::ptr::null_mut()),
459                func,
460                step,
461                final_func,
462                destroy,
463            ))
464        } else {
465            Err(ResultCode::NOMEM)
466        }
467    }
468
469    fn create_module_v2(
470        &self,
471        name: &str,
472        module: *const module,
473        user_data: Option<*mut c_void>,
474        destroy: Option<xDestroy>,
475    ) -> Result<ResultCode, ResultCode> {
476        if let Ok(name) = CString::new(name) {
477            convert_rc(create_module_v2(
478                *self,
479                name.as_ptr(),
480                module,
481                user_data.unwrap_or(core::ptr::null_mut()),
482                destroy,
483            ))
484        } else {
485            Err(ResultCode::NOMEM)
486        }
487    }
488
489    #[inline]
490    fn prepare_v2(&self, sql: &str) -> Result<ManagedStmt, ResultCode> {
491        let mut stmt = core::ptr::null_mut();
492        let mut tail = core::ptr::null();
493        let rc = ResultCode::from_i32(prepare_v2(
494            *self,
495            sql.as_ptr() as *const c_char,
496            sql.len() as i32,
497            &mut stmt as *mut *mut stmt,
498            &mut tail as *mut *const c_char,
499        ))
500        .unwrap();
501        if rc == ResultCode::OK {
502            Ok(ManagedStmt { stmt: stmt })
503        } else {
504            Err(rc)
505        }
506    }
507
508    #[inline]
509    fn prepare_v3(&self, sql: &str, flags: u32) -> Result<ManagedStmt, ResultCode> {
510        let mut stmt = core::ptr::null_mut();
511        let mut tail = core::ptr::null();
512        let rc = ResultCode::from_i32(prepare_v3(
513            *self,
514            sql.as_ptr() as *const c_char,
515            sql.len() as i32,
516            flags,
517            &mut stmt as *mut *mut stmt,
518            &mut tail as *mut *const c_char,
519        ))
520        .unwrap();
521        if rc == ResultCode::OK {
522            Ok(ManagedStmt { stmt: stmt })
523        } else {
524            Err(rc)
525        }
526    }
527
528    #[inline]
529    unsafe fn exec(&self, sql: *const c_char) -> Result<ResultCode, ResultCode> {
530        convert_rc(exec(*self, sql))
531    }
532
533    #[inline]
534    fn exec_safe(&self, sql: &str) -> Result<ResultCode, ResultCode> {
535        if let Ok(sql) = CString::new(sql) {
536            convert_rc(exec(*self, sql.as_ptr()))
537        } else {
538            return Err(ResultCode::NOMEM);
539        }
540    }
541
542    #[inline]
543    fn next_stmt(&self, s: Option<*mut stmt>) -> Option<*mut stmt> {
544        let s = if let Some(s) = s {
545            s
546        } else {
547            core::ptr::null_mut()
548        };
549
550        let ptr = next_stmt(*self, s);
551        if ptr.is_null() { None } else { Some(ptr) }
552    }
553
554    fn set_authorizer(
555        &self,
556        x_auth: Option<XAuthorizer>,
557        user_data: *mut c_void,
558    ) -> Result<ResultCode, ResultCode> {
559        convert_rc(set_authorizer(*self, x_auth, user_data))
560    }
561
562    fn errmsg(&self) -> Result<String, IntoStringError> {
563        errmsg(*self).into_string()
564    }
565
566    fn errcode(&self) -> ResultCode {
567        ResultCode::from_i32(errcode(*self)).unwrap()
568    }
569
570    fn error_offset(&self) -> Option<usize> {
571        match error_offset(*self) {
572            -1 => None,
573            other => Some(other as usize),
574        }
575    }
576
577    fn get_autocommit(&self) -> bool {
578        get_autocommit(*self) != 0
579    }
580
581    fn rollback_hook(&self, callback: Option<xRollbackHook>, ctx: *mut c_void) -> *mut c_void {
582        rollback_hook(*self, callback, ctx)
583    }
584
585    fn update_hook(&self, callback: Option<xUpdateHook>, ctx: *mut c_void) -> *mut c_void {
586        update_hook(*self, callback, ctx)
587    }
588}
589
590pub fn convert_rc(rc: i32) -> Result<ResultCode, ResultCode> {
591    let rc = ResultCode::from_i32(rc).unwrap_or(ResultCode::ABORT);
592    if rc == ResultCode::OK {
593        Ok(rc)
594    } else {
595        Err(rc)
596    }
597}
598
599pub struct ManagedStmt {
600    pub stmt: *mut stmt,
601}
602
603impl ManagedStmt {
604    pub fn reset(&self) -> Result<ResultCode, ResultCode> {
605        convert_rc(reset(self.stmt))
606    }
607
608    pub fn step(&self) -> Result<ResultCode, ResultCode> {
609        let rc = ResultCode::from_i32(step(self.stmt)).unwrap();
610        if (rc == ResultCode::ROW) || (rc == ResultCode::DONE) {
611            Ok(rc)
612        } else {
613            Err(rc)
614        }
615    }
616
617    pub fn sql(&self) -> Result<&str, ResultCode> {
618        let ptr = sql(self.stmt);
619        Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?)
620    }
621
622    #[inline]
623    pub fn column_count(&self) -> i32 {
624        column_count(self.stmt)
625    }
626
627    /// Calls to `step` or addiitonal calls to `column_name` will invalidate the
628    /// returned string. Unclear if there's any way to capture this
629    /// behavior in the type system.
630    #[inline]
631    pub fn column_name(&self, i: i32) -> Result<&str, ResultCode> {
632        let ptr = column_name(self.stmt, i);
633        if ptr.is_null() {
634            Err(ResultCode::NULL)
635        } else {
636            Ok(
637                unsafe {
638                    core::str::from_utf8_unchecked(core::ffi::CStr::from_ptr(ptr).to_bytes())
639                },
640            )
641        }
642    }
643
644    #[inline]
645    pub fn column_type(&self, i: i32) -> Result<ColumnType, ResultCode> {
646        ColumnType::from_i32(column_type(self.stmt, i)).ok_or(ResultCode::NULL)
647    }
648
649    #[inline]
650    pub fn column_text(&self, i: i32) -> Result<&str, ResultCode> {
651        let len = column_bytes(self.stmt, i);
652        let ptr = column_text_ptr(self.stmt, i);
653        if ptr.is_null() {
654            Err(ResultCode::NULL)
655        } else {
656            Ok(unsafe {
657                let slice = core::slice::from_raw_parts(ptr as *const u8, len as usize);
658                core::str::from_utf8_unchecked(slice)
659            })
660        }
661    }
662
663    #[inline]
664    pub fn column_blob(&self, i: i32) -> Result<&[u8], ResultCode> {
665        let len = column_bytes(self.stmt, i);
666        let ptr = column_blob(self.stmt, i);
667        if ptr.is_null() {
668            Err(ResultCode::NULL)
669        } else {
670            Ok(unsafe { core::slice::from_raw_parts(ptr as *const u8, len as usize) })
671        }
672    }
673
674    #[inline]
675    pub fn column_double(&self, i: i32) -> f64 {
676        column_double(self.stmt, i)
677    }
678
679    #[inline]
680    pub fn column_int(&self, i: i32) -> i32 {
681        column_int(self.stmt, i)
682    }
683
684    #[inline]
685    pub fn column_int64(&self, i: i32) -> int64 {
686        column_int64(self.stmt, i)
687    }
688
689    // TODO: this should return `Option<*mut valu>`
690    #[inline]
691    pub fn column_value(&self, i: i32) -> Result<*mut value, ResultCode> {
692        let ptr = column_value(self.stmt, i);
693        if ptr.is_null() {
694            Err(ResultCode::NULL)
695        } else {
696            Ok(ptr)
697        }
698    }
699
700    pub fn bind_blob(&self, i: i32, val: &[u8], d: Destructor) -> Result<ResultCode, ResultCode> {
701        convert_rc(bind_blob(
702            self.stmt,
703            i,
704            val.as_ptr() as *const c_void,
705            val.len() as i32,
706            d,
707        ))
708    }
709
710    #[inline]
711    pub fn bind_value(&self, i: i32, val: *mut value) -> Result<ResultCode, ResultCode> {
712        convert_rc(bind_value(self.stmt, i, val))
713    }
714
715    #[inline]
716    pub fn bind_text(&self, i: i32, text: &str, d: Destructor) -> Result<ResultCode, ResultCode> {
717        convert_rc(bind_text(
718            self.stmt,
719            i,
720            text.as_ptr() as *const c_char,
721            text.len() as i32,
722            d,
723        ))
724    }
725
726    #[inline]
727    pub fn bind_int64(&self, i: i32, val: int64) -> Result<ResultCode, ResultCode> {
728        convert_rc(bind_int64(self.stmt, i, val))
729    }
730
731    #[inline]
732    pub fn bind_int(&self, i: i32, val: i32) -> Result<ResultCode, ResultCode> {
733        convert_rc(bind_int(self.stmt, i, val))
734    }
735
736    #[inline]
737    pub fn bind_double(&self, i: i32, val: f64) -> Result<ResultCode, ResultCode> {
738        convert_rc(bind_double(self.stmt, i, val))
739    }
740
741    #[inline]
742    pub fn bind_null(&self, i: i32) -> Result<ResultCode, ResultCode> {
743        convert_rc(bind_null(self.stmt, i))
744    }
745
746    #[inline]
747    pub fn clear_bindings(&self) -> Result<ResultCode, ResultCode> {
748        convert_rc(clear_bindings(self.stmt))
749    }
750
751    #[inline]
752    pub fn bind_parameter_count(&self) -> c_int {
753        bind_parameter_count(self.stmt)
754    }
755
756    pub fn bind_parameter_name(&self, i: i32) -> Result<Option<&str>, Utf8Error> {
757        let ptr = bind_parameter_name(self.stmt, i);
758        if ptr.is_null() {
759            Ok(None)
760        } else {
761            let name = unsafe { CStr::from_ptr(ptr) };
762            Ok(Some(name.to_str()?))
763        }
764    }
765
766    #[inline]
767    pub fn finalize(self) -> Result<ResultCode, ResultCode> {
768        self.stmt.finalize()
769    }
770
771    pub fn into_raw(self) -> *mut stmt {
772        let stmt = self.stmt;
773        core::mem::forget(self);
774        stmt
775    }
776}
777
778impl Drop for ManagedStmt {
779    fn drop(&mut self) {
780        finalize(self.stmt);
781    }
782}
783
784pub trait Context {
785    fn result_text_transient(&self, text: &str);
786    fn result_text_static(&self, text: &str);
787    fn result_blob_transient(&self, blob: &[u8]);
788    fn result_blob_static(&self, blob: &[u8]);
789    fn result_error(&self, text: &str);
790    fn result_error_code(&self, code: ResultCode);
791    fn result_value(&self, value: *mut value);
792    fn result_double(&self, value: f64);
793    fn result_int(&self, value: i32);
794    fn result_int64(&self, value: int64);
795    fn result_null(&self);
796    fn result_subtype(&self, subtype: u32);
797    fn db_handle(&self) -> *mut sqlite3;
798    fn user_data(&self) -> *mut c_void;
799}
800
801impl Context for *mut context {
802    #[inline]
803    fn result_null(&self) {
804        result_null(*self)
805    }
806
807    /// Takes a reference to a string, has SQLite copy the contents
808    /// and take ownership of the copy.
809    #[inline]
810    fn result_text_transient(&self, text: &str) {
811        result_text(
812            *self,
813            text.as_ptr() as *mut c_char,
814            text.len() as i32,
815            Destructor::TRANSIENT,
816        );
817    }
818
819    /// Takes a reference to a string that will outlive SQLite's use of the string.
820    /// SQLite will not copy this string.
821    #[inline]
822    fn result_text_static(&self, text: &str) {
823        result_text(
824            *self,
825            text.as_ptr() as *mut c_char,
826            text.len() as i32,
827            Destructor::STATIC,
828        );
829    }
830
831    /// SQLite will make a copy of the blob
832    #[inline]
833    fn result_blob_transient(&self, blob: &[u8]) {
834        result_blob(
835            *self,
836            blob.as_ptr(),
837            blob.len() as i32,
838            Destructor::TRANSIENT,
839        );
840    }
841
842    #[inline]
843    fn result_blob_static(&self, blob: &[u8]) {
844        result_blob(*self, blob.as_ptr(), blob.len() as i32, Destructor::STATIC);
845    }
846
847    #[inline]
848    fn result_error(&self, text: &str) {
849        result_error(*self, text.as_ptr() as *mut c_char, text.len() as c_int);
850    }
851
852    #[inline]
853    fn result_error_code(&self, code: ResultCode) {
854        result_error_code(*self, code as c_int);
855    }
856
857    #[inline]
858    fn result_value(&self, value: *mut value) {
859        result_value(*self, value);
860    }
861
862    #[inline]
863    fn result_double(&self, value: f64) {
864        result_double(*self, value);
865    }
866
867    #[inline]
868    fn result_int64(&self, value: int64) {
869        result_int64(*self, value);
870    }
871
872    #[inline]
873    fn result_int(&self, value: i32) {
874        result_int(*self, value);
875    }
876
877    #[inline]
878    fn result_subtype(&self, subtype: u32) {
879        result_subtype(*self, subtype);
880    }
881
882    #[inline]
883    fn db_handle(&self) -> *mut sqlite3 {
884        context_db_handle(*self)
885    }
886
887    #[inline]
888    fn user_data(&self) -> *mut c_void {
889        user_data(*self)
890    }
891}
892
893pub trait Stmt {
894    fn sql(&self) -> &str;
895    fn bind_blob(&self, i: i32, val: &[u8], d: Destructor) -> Result<ResultCode, ResultCode>;
896    fn bind_value(&self, i: i32, val: *mut value) -> Result<ResultCode, ResultCode>;
897    fn bind_text(&self, i: i32, text: &str, d: Destructor) -> Result<ResultCode, ResultCode>;
898    fn bind_int64(&self, i: i32, val: int64) -> Result<ResultCode, ResultCode>;
899    fn bind_int(&self, i: i32, val: i32) -> Result<ResultCode, ResultCode>;
900    fn bind_double(&self, i: i32, val: f64) -> Result<ResultCode, ResultCode>;
901    fn bind_null(&self, i: i32) -> Result<ResultCode, ResultCode>;
902
903    fn clear_bindings(&self) -> Result<ResultCode, ResultCode>;
904
905    fn column_value(&self, i: i32) -> *mut value;
906    fn column_int64(&self, i: i32) -> int64;
907    fn column_int(&self, i: i32) -> i32;
908    fn column_blob(&self, i: i32) -> &[u8];
909    fn column_double(&self, i: i32) -> f64;
910    fn column_text(&self, i: i32) -> &str;
911    fn column_bytes(&self, i: i32) -> i32;
912
913    fn finalize(&self) -> Result<ResultCode, ResultCode>;
914
915    fn reset(&self) -> Result<ResultCode, ResultCode>;
916    fn step(&self) -> Result<ResultCode, ResultCode>;
917}
918
919impl Stmt for *mut stmt {
920    fn sql(&self) -> &str {
921        unsafe { core::str::from_utf8_unchecked(core::ffi::CStr::from_ptr(sql(*self)).to_bytes()) }
922    }
923
924    #[inline]
925    fn bind_blob(&self, i: i32, val: &[u8], d: Destructor) -> Result<ResultCode, ResultCode> {
926        convert_rc(bind_blob(
927            *self,
928            i,
929            val.as_ptr() as *const c_void,
930            val.len() as i32,
931            d,
932        ))
933    }
934
935    #[inline]
936    fn bind_double(&self, i: i32, val: f64) -> Result<ResultCode, ResultCode> {
937        convert_rc(bind_double(*self, i, val))
938    }
939
940    #[inline]
941    fn bind_value(&self, i: i32, val: *mut value) -> Result<ResultCode, ResultCode> {
942        convert_rc(bind_value(*self, i, val))
943    }
944
945    #[inline]
946    fn bind_text(&self, i: i32, text: &str, d: Destructor) -> Result<ResultCode, ResultCode> {
947        convert_rc(bind_text(
948            *self,
949            i,
950            text.as_ptr() as *const c_char,
951            text.len() as i32,
952            d,
953        ))
954    }
955
956    #[inline]
957    fn bind_int64(&self, i: i32, val: int64) -> Result<ResultCode, ResultCode> {
958        convert_rc(bind_int64(*self, i, val))
959    }
960
961    #[inline]
962    fn bind_int(&self, i: i32, val: i32) -> Result<ResultCode, ResultCode> {
963        convert_rc(bind_int(*self, i, val))
964    }
965
966    #[inline]
967    fn bind_null(&self, i: i32) -> Result<ResultCode, ResultCode> {
968        convert_rc(bind_null(*self, i))
969    }
970
971    #[inline]
972    fn clear_bindings(&self) -> Result<ResultCode, ResultCode> {
973        convert_rc(clear_bindings(*self))
974    }
975
976    #[inline]
977    fn column_value(&self, i: i32) -> *mut value {
978        column_value(*self, i)
979    }
980
981    #[inline]
982    fn column_int64(&self, i: i32) -> int64 {
983        column_int64(*self, i)
984    }
985
986    #[inline]
987    fn column_int(&self, i: i32) -> i32 {
988        column_int(*self, i)
989    }
990
991    #[inline]
992    fn column_blob(&self, i: i32) -> &[u8] {
993        let len = column_bytes(*self, i);
994        let ptr = column_blob(*self, i);
995        unsafe { core::slice::from_raw_parts(ptr as *const u8, len as usize) }
996    }
997
998    #[inline]
999    fn column_double(&self, i: i32) -> f64 {
1000        column_double(*self, i)
1001    }
1002
1003    #[inline]
1004    fn column_text(&self, i: i32) -> &str {
1005        column_text(*self, i)
1006    }
1007
1008    #[inline]
1009    fn column_bytes(&self, i: i32) -> i32 {
1010        column_bytes(*self, i)
1011    }
1012
1013    #[inline]
1014    fn reset(&self) -> Result<ResultCode, ResultCode> {
1015        convert_rc(reset(*self))
1016    }
1017
1018    #[inline]
1019    fn step(&self) -> Result<ResultCode, ResultCode> {
1020        match ResultCode::from_i32(step(*self)) {
1021            Some(ResultCode::ROW) => Ok(ResultCode::ROW),
1022            Some(ResultCode::DONE) => Ok(ResultCode::DONE),
1023            Some(rc) => Err(rc),
1024            None => Err(ResultCode::ERROR),
1025        }
1026    }
1027
1028    #[inline]
1029    fn finalize(&self) -> Result<ResultCode, ResultCode> {
1030        match ResultCode::from_i32(finalize(*self)) {
1031            Some(ResultCode::OK) => Ok(ResultCode::OK),
1032            Some(rc) => Err(rc),
1033            None => Err(ResultCode::ABORT),
1034        }
1035    }
1036}
1037
1038pub trait Value {
1039    fn blob(&self) -> &[u8];
1040    fn double(&self) -> f64;
1041    fn int(&self) -> i32;
1042    fn int64(&self) -> int64;
1043    fn text(&self) -> &str;
1044    fn bytes(&self) -> i32;
1045    fn value_type(&self) -> ColumnType;
1046}
1047
1048impl Value for *mut value {
1049    #[inline]
1050    fn value_type(&self) -> ColumnType {
1051        ColumnType::from_i32(value_type(*self)).unwrap()
1052    }
1053
1054    #[inline]
1055    fn blob(&self) -> &[u8] {
1056        value_blob(*self)
1057    }
1058
1059    #[inline]
1060    fn double(&self) -> f64 {
1061        value_double(*self)
1062    }
1063
1064    #[inline]
1065    fn int(&self) -> i32 {
1066        value_int(*self)
1067    }
1068
1069    #[inline]
1070    fn int64(&self) -> int64 {
1071        value_int64(*self)
1072    }
1073
1074    #[inline]
1075    fn text(&self) -> &str {
1076        value_text(*self)
1077    }
1078
1079    #[inline]
1080    fn bytes(&self) -> i32 {
1081        value_bytes(*self)
1082    }
1083}
1084
1085pub trait StrRef {
1086    fn set(&self, val: &str);
1087}
1088
1089impl StrRef for *mut *mut c_char {
1090    /**
1091     * Sets the error message, copying the contents of `val`.
1092     * If the error has already been set, future calls to `set` are ignored.
1093     */
1094    fn set(&self, val: &str) {
1095        unsafe {
1096            if **self != null_mut() {
1097                return;
1098            }
1099            if let Ok(cstring) = CString::new(val) {
1100                **self = cstring.into_raw();
1101            } else {
1102                if let Ok(s) = CString::new("Failed setting error message.") {
1103                    **self = s.into_raw();
1104                }
1105            }
1106        }
1107    }
1108}
1109
1110// TODO: on `T` can I enforce that T has a pointer of name `base` as first item to `vtab`?
1111pub trait VTabRef {
1112    fn set<T>(&self, val: Box<T>);
1113}
1114
1115impl VTabRef for *mut *mut vtab {
1116    fn set<T>(&self, val: Box<T>) {
1117        unsafe {
1118            let raw_val = Box::into_raw(val);
1119            **self = raw_val.cast::<sqlite3_capi::vtab>();
1120        }
1121    }
1122}
1123
1124pub trait CursorRef {
1125    fn set<T>(&self, val: Box<T>);
1126}
1127
1128impl CursorRef for *mut *mut vtab_cursor {
1129    fn set<T>(&self, val: Box<T>) {
1130        unsafe {
1131            let raw_val = Box::into_raw(val);
1132            **self = raw_val.cast::<sqlite3_capi::vtab_cursor>();
1133        }
1134    }
1135}
1136
1137pub trait VTab {
1138    fn set_err(&self, val: &str);
1139}
1140
1141impl VTab for *mut vtab {
1142    /**
1143     * Sets the error message, copying the contents of `val`.
1144     * If the error has already been set, future calls to `set` are ignored.
1145     */
1146    fn set_err(&self, val: &str) {
1147        unsafe {
1148            if (**self).zErrMsg != null_mut() {
1149                return;
1150            }
1151            if let Ok(e) = CString::new(val) {
1152                (**self).zErrMsg = e.into_raw();
1153            }
1154        }
1155    }
1156}
1157
1158// from: https://github.com/asg017/sqlite-loadable-rs/blob/main/src/table.rs#L722
1159pub struct VTabArgs<'a> {
1160    /// Name of the module being invoked, the argument in the USING clause.
1161    /// Example: `"CREATE VIRTUAL TABLE xxx USING custom_vtab"` would have
1162    /// a `module_name` of `"custom_vtab"`.
1163    /// Sourced from `argv[0]`
1164    pub module_name: &'a str,
1165    /// Name of the database where the virtual table will be created,
1166    /// typically `"main"` or `"temp"` or another name from an
1167    /// [`ATTACH`'ed database](https://www.sqlite.org/lang_attach.html).
1168    /// Sourced from `argv[1]`
1169    pub database_name: &'a str,
1170
1171    /// Name of the table being created.
1172    /// Example: `"CREATE VIRTUAL TABLE xxx USING custom_vtab"` would
1173    /// have a `table_name` of `"xxx"`.
1174    /// Sourced from `argv[2]`
1175    pub table_name: &'a str,
1176    /// The remaining arguments given in the constructor of the virtual
1177    /// table, inside `CREATE VIRTUAL TABLE xxx USING custom_vtab(...)`.
1178    /// Sourced from `argv[3:]`
1179    pub arguments: Vec<&'a str>,
1180}
1181
1182/// Generally do not use this. Does a bunch of copying.
1183fn c_string_to_str<'a>(c: *const c_char) -> Result<&'a str, Utf8Error> {
1184    let s = unsafe { CStr::from_ptr(c).to_str()? };
1185    Ok(s)
1186}
1187
1188pub fn parse_vtab_args<'a>(
1189    argc: c_int,
1190    argv: *const *const c_char,
1191) -> Result<VTabArgs<'a>, Utf8Error> {
1192    let raw_args = unsafe { slice::from_raw_parts(argv, argc as usize) };
1193    let mut args = Vec::with_capacity(argc as usize);
1194    for arg in raw_args {
1195        args.push(c_string_to_str(*arg)?);
1196    }
1197
1198    // SQLite guarantees that argv[0-2] will be filled, hence the .expects() -
1199    // If SQLite is wrong, then may god save our souls
1200    let module_name = args
1201        .get(0)
1202        .expect("argv[0] should be the name of the module");
1203    let database_name = args
1204        .get(1)
1205        .expect("argv[1] should be the name of the database the module is in");
1206    let table_name = args
1207        .get(2)
1208        .expect("argv[2] should be the name of the virtual table");
1209    let arguments = &args[3..];
1210
1211    Ok(VTabArgs {
1212        module_name,
1213        database_name,
1214        table_name,
1215        arguments: arguments.to_vec(),
1216    })
1217}
1218
1219pub fn declare_vtab(db: *mut sqlite3, def: &str) -> Result<ResultCode, ResultCode> {
1220    let cstring = CString::new(def)?;
1221    let ret = sqlite3_capi::declare_vtab(db, cstring.as_ptr());
1222    convert_rc(ret)
1223}
1224
1225pub fn vtab_config(db: *mut sqlite3, options: u32) -> Result<ResultCode, ResultCode> {
1226    let rc = sqlite3_capi::vtab_config(db, options);
1227    convert_rc(rc)
1228}
1229
1230// type xCreateC = extern "C" fn(
1231//     *mut sqlite3,
1232//     *mut c_void,
1233//     c_int,
1234//     *const *const c_char,
1235//     *mut *mut vtab,
1236//     *mut *mut c_char,
1237// ) -> c_int;
1238
1239// // return a lambda that invokes f appropriately?
1240// pub const fn xCreate(
1241//     f: fn(
1242//         db: *mut sqlite3,
1243//         aux: *mut c_void,
1244//         args: Vec<&str>,
1245//         tab: *mut *mut vtab,   // declare tab for them?
1246//         err: *mut *mut c_char, // box?
1247//     ) -> Result<ResultCode, ResultCode>,
1248// ) -> xCreateC {
1249//     move |db, aux, argc, argv, ppvtab, errmsg| match f(db, aux, str_args, ppvtab, errmsg) {
1250//         Ok(rc) => rc as c_int,
1251//         Err(rc) => rc as c_int,
1252//     }
1253// }
1254
1255// *mut sqlite3, *mut c_void, Vec<&str>, *mut *mut vtab, *mut *mut c_char