libsql_ffi/
lib.rs

1#![allow(non_snake_case, non_camel_case_types, clippy::type_complexity)]
2#![cfg_attr(test, allow(deref_nullptr))] // https://github.com/rust-lang/rust-bindgen/issues/2066
3
4use std::default::Default;
5use std::error;
6use std::fmt;
7use std::marker::PhantomData;
8use std::mem;
9use std::os::raw::c_int;
10
11#[cfg(feature = "wasmtime-bindings")]
12pub use libsql_wasm::{
13    libsql_compile_wasm_module, libsql_free_wasm_module, libsql_run_wasm, libsql_wasm_engine_new,
14};
15
16pub use bindgen::*;
17mod bindgen {
18    #![allow(dead_code)]
19    include!(concat!(env!("OUT_DIR"), "/bindgen.rs"));
20}
21
22#[must_use]
23pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
24    None
25}
26
27#[must_use]
28pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
29    Some(unsafe { mem::transmute(-1_isize) })
30}
31
32impl Default for sqlite3_vtab {
33    fn default() -> Self {
34        unsafe { mem::zeroed() }
35    }
36}
37
38impl Default for sqlite3_vtab_cursor {
39    fn default() -> Self {
40        unsafe { mem::zeroed() }
41    }
42}
43
44pub struct PageHdrIter<'a> {
45    current_ptr: *const PgHdr,
46    page_size: usize,
47    _pth: PhantomData<&'a ()>,
48}
49
50impl<'a> PageHdrIter<'a> {
51    pub fn new(current_ptr: *const PgHdr, page_size: usize) -> Self {
52        Self {
53            current_ptr,
54            page_size,
55            _pth: PhantomData,
56        }
57    }
58
59    pub fn current_ptr(&self) -> *const PgHdr {
60        self.current_ptr
61    }
62}
63
64impl<'a> std::iter::Iterator for PageHdrIter<'a> {
65    type Item = (u32, &'a [u8]);
66
67    fn next(&mut self) -> Option<Self::Item> {
68        if self.current_ptr.is_null() {
69            return None;
70        }
71        let current_hdr: &PgHdr = unsafe { &*self.current_ptr };
72        let raw_data =
73            unsafe { std::slice::from_raw_parts(current_hdr.pData as *const u8, self.page_size) };
74        let item = Some((current_hdr.pgno, raw_data));
75        self.current_ptr = current_hdr.pDirty;
76        item
77    }
78}
79
80pub struct PageHdrIterMut<'a> {
81    current_ptr: *mut PgHdr,
82    page_size: usize,
83    _pth: PhantomData<&'a ()>,
84}
85
86impl<'a> PageHdrIterMut<'a> {
87    pub fn new(current_ptr: *mut PgHdr, page_size: usize) -> Self {
88        Self {
89            current_ptr,
90            page_size,
91            _pth: PhantomData,
92        }
93    }
94}
95
96impl<'a> std::iter::Iterator for PageHdrIterMut<'a> {
97    type Item = (u32, &'a mut [u8]);
98
99    fn next(&mut self) -> Option<Self::Item> {
100        if self.current_ptr.is_null() {
101            return None;
102        }
103        let current_hdr: &PgHdr = unsafe { &*self.current_ptr };
104        let raw_data =
105            unsafe { std::slice::from_raw_parts_mut(current_hdr.pData as *mut u8, self.page_size) };
106        let item = Some((current_hdr.pgno, raw_data));
107        self.current_ptr = current_hdr.pDirty;
108        item
109    }
110}
111
112/// Error Codes
113#[derive(Clone, Copy, Debug, PartialEq, Eq)]
114#[non_exhaustive]
115pub enum ErrorCode {
116    /// Internal logic error in SQLite
117    InternalMalfunction,
118    /// Access permission denied
119    PermissionDenied,
120    /// Callback routine requested an abort
121    OperationAborted,
122    /// The database file is locked
123    DatabaseBusy,
124    /// A table in the database is locked
125    DatabaseLocked,
126    /// A malloc() failed
127    OutOfMemory,
128    /// Attempt to write a readonly database
129    ReadOnly,
130    /// Operation terminated by sqlite3_interrupt()
131    OperationInterrupted,
132    /// Some kind of disk I/O error occurred
133    SystemIoFailure,
134    /// The database disk image is malformed
135    DatabaseCorrupt,
136    /// Unknown opcode in sqlite3_file_control()
137    NotFound,
138    /// Insertion failed because database is full
139    DiskFull,
140    /// Unable to open the database file
141    CannotOpen,
142    /// Database lock protocol error
143    FileLockingProtocolFailed,
144    /// The database schema changed
145    SchemaChanged,
146    /// String or BLOB exceeds size limit
147    TooBig,
148    /// Abort due to constraint violation
149    ConstraintViolation,
150    /// Data type mismatch
151    TypeMismatch,
152    /// Library used incorrectly
153    ApiMisuse,
154    /// Uses OS features not supported on host
155    NoLargeFileSupport,
156    /// Authorization denied
157    AuthorizationForStatementDenied,
158    /// 2nd parameter to sqlite3_bind out of range
159    ParameterOutOfRange,
160    /// File opened that is not a database file
161    NotADatabase,
162    /// SQL error or missing database
163    Unknown,
164}
165
166#[derive(Clone, Copy, Debug, PartialEq, Eq)]
167pub struct Error {
168    pub code: ErrorCode,
169    pub extended_code: c_int,
170}
171
172impl Error {
173    #[must_use]
174    pub fn new(result_code: c_int) -> Error {
175        let code = match result_code & 0xff {
176            SQLITE_INTERNAL => ErrorCode::InternalMalfunction,
177            SQLITE_PERM => ErrorCode::PermissionDenied,
178            SQLITE_ABORT => ErrorCode::OperationAborted,
179            SQLITE_BUSY => ErrorCode::DatabaseBusy,
180            SQLITE_LOCKED => ErrorCode::DatabaseLocked,
181            SQLITE_NOMEM => ErrorCode::OutOfMemory,
182            SQLITE_READONLY => ErrorCode::ReadOnly,
183            SQLITE_INTERRUPT => ErrorCode::OperationInterrupted,
184            SQLITE_IOERR => ErrorCode::SystemIoFailure,
185            SQLITE_CORRUPT => ErrorCode::DatabaseCorrupt,
186            SQLITE_NOTFOUND => ErrorCode::NotFound,
187            SQLITE_FULL => ErrorCode::DiskFull,
188            SQLITE_CANTOPEN => ErrorCode::CannotOpen,
189            SQLITE_PROTOCOL => ErrorCode::FileLockingProtocolFailed,
190            SQLITE_SCHEMA => ErrorCode::SchemaChanged,
191            SQLITE_TOOBIG => ErrorCode::TooBig,
192            SQLITE_CONSTRAINT => ErrorCode::ConstraintViolation,
193            SQLITE_MISMATCH => ErrorCode::TypeMismatch,
194            SQLITE_MISUSE => ErrorCode::ApiMisuse,
195            SQLITE_NOLFS => ErrorCode::NoLargeFileSupport,
196            SQLITE_AUTH => ErrorCode::AuthorizationForStatementDenied,
197            SQLITE_RANGE => ErrorCode::ParameterOutOfRange,
198            SQLITE_NOTADB => ErrorCode::NotADatabase,
199            _ => ErrorCode::Unknown,
200        };
201
202        Error {
203            code,
204            extended_code: result_code,
205        }
206    }
207}
208
209impl fmt::Display for Error {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211        write!(
212            f,
213            "Error code {}: {}",
214            self.extended_code,
215            code_to_str(self.extended_code)
216        )
217    }
218}
219
220impl error::Error for Error {
221    fn description(&self) -> &str {
222        code_to_str(self.extended_code)
223    }
224}
225
226#[must_use]
227pub fn code_to_str(code: c_int) -> &'static str {
228    match code {
229        SQLITE_OK        => "Successful result",
230        SQLITE_ERROR     => "SQL error or missing database",
231        SQLITE_INTERNAL  => "Internal logic error in SQLite",
232        SQLITE_PERM      => "Access permission denied",
233        SQLITE_ABORT     => "Callback routine requested an abort",
234        SQLITE_BUSY      => "The database file is locked",
235        SQLITE_LOCKED    => "A table in the database is locked",
236        SQLITE_NOMEM     => "A malloc() failed",
237        SQLITE_READONLY  => "Attempt to write a readonly database",
238        SQLITE_INTERRUPT => "Operation terminated by sqlite3_interrupt()",
239        SQLITE_IOERR     => "Some kind of disk I/O error occurred",
240        SQLITE_CORRUPT   => "The database disk image is malformed",
241        SQLITE_NOTFOUND  => "Unknown opcode in sqlite3_file_control()",
242        SQLITE_FULL      => "Insertion failed because database is full",
243        SQLITE_CANTOPEN  => "Unable to open the database file",
244        SQLITE_PROTOCOL  => "Database lock protocol error",
245        SQLITE_EMPTY     => "Database is empty",
246        SQLITE_SCHEMA    => "The database schema changed",
247        SQLITE_TOOBIG    => "String or BLOB exceeds size limit",
248        SQLITE_CONSTRAINT=> "Abort due to constraint violation",
249        SQLITE_MISMATCH  => "Data type mismatch",
250        SQLITE_MISUSE    => "Library used incorrectly",
251        SQLITE_NOLFS     => "Uses OS features not supported on host",
252        SQLITE_AUTH      => "Authorization denied",
253        SQLITE_FORMAT    => "Auxiliary database format error",
254        SQLITE_RANGE     => "2nd parameter to sqlite3_bind out of range",
255        SQLITE_NOTADB    => "File opened that is not a database file",
256        SQLITE_NOTICE    => "Notifications from sqlite3_log()",
257        SQLITE_WARNING   => "Warnings from sqlite3_log()",
258        SQLITE_ROW       => "sqlite3_step() has another row ready",
259        SQLITE_DONE      => "sqlite3_step() has finished executing",
260
261        SQLITE_ERROR_MISSING_COLLSEQ   => "SQLITE_ERROR_MISSING_COLLSEQ",
262        SQLITE_ERROR_RETRY   => "SQLITE_ERROR_RETRY",
263        SQLITE_ERROR_SNAPSHOT   => "SQLITE_ERROR_SNAPSHOT",
264
265        SQLITE_IOERR_READ              => "Error reading from disk",
266        SQLITE_IOERR_SHORT_READ        => "Unable to obtain number of requested bytes (file truncated?)",
267        SQLITE_IOERR_WRITE             => "Error writing to disk",
268        SQLITE_IOERR_FSYNC             => "Error flushing data to persistent storage (fsync)",
269        SQLITE_IOERR_DIR_FSYNC         => "Error calling fsync on a directory",
270        SQLITE_IOERR_TRUNCATE          => "Error attempting to truncate file",
271        SQLITE_IOERR_FSTAT             => "Error invoking fstat to get file metadata",
272        SQLITE_IOERR_UNLOCK            => "I/O error within xUnlock of a VFS object",
273        SQLITE_IOERR_RDLOCK            => "I/O error within xLock of a VFS object (trying to obtain a read lock)",
274        SQLITE_IOERR_DELETE            => "I/O error within xDelete of a VFS object",
275        SQLITE_IOERR_BLOCKED           => "SQLITE_IOERR_BLOCKED", // no longer used
276        SQLITE_IOERR_NOMEM             => "Out of memory in I/O layer",
277        SQLITE_IOERR_ACCESS            => "I/O error within xAccess of a VFS object",
278        SQLITE_IOERR_CHECKRESERVEDLOCK => "I/O error within then xCheckReservedLock method",
279        SQLITE_IOERR_LOCK              => "I/O error in the advisory file locking layer",
280        SQLITE_IOERR_CLOSE             => "I/O error within the xClose method",
281        SQLITE_IOERR_DIR_CLOSE         => "SQLITE_IOERR_DIR_CLOSE", // no longer used
282        SQLITE_IOERR_SHMOPEN           => "I/O error within the xShmMap method (trying to open a new shared-memory segment)",
283        SQLITE_IOERR_SHMSIZE           => "I/O error within the xShmMap method (trying to resize an existing shared-memory segment)",
284        SQLITE_IOERR_SHMLOCK           => "SQLITE_IOERR_SHMLOCK", // no longer used
285        SQLITE_IOERR_SHMMAP            => "I/O error within the xShmMap method (trying to map a shared-memory segment into process address space)",
286        SQLITE_IOERR_SEEK              => "I/O error within the xRead or xWrite (trying to seek within a file)",
287        SQLITE_IOERR_DELETE_NOENT      => "File being deleted does not exist",
288        SQLITE_IOERR_MMAP              => "I/O error while trying to map or unmap part of the database file into process address space",
289        SQLITE_IOERR_GETTEMPPATH       => "VFS is unable to determine a suitable directory for temporary files",
290        SQLITE_IOERR_CONVPATH          => "cygwin_conv_path() system call failed",
291        SQLITE_IOERR_VNODE             => "SQLITE_IOERR_VNODE", // not documented?
292        SQLITE_IOERR_AUTH              => "SQLITE_IOERR_AUTH",
293        SQLITE_IOERR_BEGIN_ATOMIC      => "SQLITE_IOERR_BEGIN_ATOMIC",
294        SQLITE_IOERR_COMMIT_ATOMIC     => "SQLITE_IOERR_COMMIT_ATOMIC",
295        SQLITE_IOERR_ROLLBACK_ATOMIC   => "SQLITE_IOERR_ROLLBACK_ATOMIC",
296        SQLITE_IOERR_DATA              => "SQLITE_IOERR_DATA",
297
298        SQLITE_LOCKED_SHAREDCACHE      => "Locking conflict due to another connection with a shared cache",
299        SQLITE_LOCKED_VTAB             => "SQLITE_LOCKED_VTAB",
300
301        SQLITE_BUSY_RECOVERY           => "Another process is recovering a WAL mode database file",
302        SQLITE_BUSY_SNAPSHOT           => "Cannot promote read transaction to write transaction because of writes by another connection",
303        SQLITE_BUSY_TIMEOUT            => "SQLITE_BUSY_TIMEOUT",
304
305        SQLITE_CANTOPEN_NOTEMPDIR      => "SQLITE_CANTOPEN_NOTEMPDIR", // no longer used
306        SQLITE_CANTOPEN_ISDIR          => "Attempted to open directory as file",
307        SQLITE_CANTOPEN_FULLPATH       => "Unable to convert filename into full pathname",
308        SQLITE_CANTOPEN_CONVPATH       => "cygwin_conv_path() system call failed",
309        SQLITE_CANTOPEN_SYMLINK        => "SQLITE_CANTOPEN_SYMLINK",
310
311        SQLITE_CORRUPT_VTAB            => "Content in the virtual table is corrupt",
312        SQLITE_CORRUPT_SEQUENCE        => "SQLITE_CORRUPT_SEQUENCE",
313        SQLITE_CORRUPT_INDEX           => "SQLITE_CORRUPT_INDEX",
314
315        SQLITE_READONLY_RECOVERY       => "WAL mode database file needs recovery (requires write access)",
316        SQLITE_READONLY_CANTLOCK       => "Shared-memory file associated with WAL mode database is read-only",
317        SQLITE_READONLY_ROLLBACK       => "Database has hot journal that must be rolled back (requires write access)",
318        SQLITE_READONLY_DBMOVED        => "Database cannot be modified because database file has moved",
319        SQLITE_READONLY_CANTINIT       => "SQLITE_READONLY_CANTINIT",
320        SQLITE_READONLY_DIRECTORY      => "SQLITE_READONLY_DIRECTORY",
321
322        SQLITE_ABORT_ROLLBACK          => "Transaction was rolled back",
323
324        SQLITE_CONSTRAINT_CHECK        => "A CHECK constraint failed",
325        SQLITE_CONSTRAINT_COMMITHOOK   => "Commit hook caused rollback",
326        SQLITE_CONSTRAINT_FOREIGNKEY   => "Foreign key constraint failed",
327        SQLITE_CONSTRAINT_FUNCTION     => "Error returned from extension function",
328        SQLITE_CONSTRAINT_NOTNULL      => "A NOT NULL constraint failed",
329        SQLITE_CONSTRAINT_PRIMARYKEY   => "A PRIMARY KEY constraint failed",
330        SQLITE_CONSTRAINT_TRIGGER      => "A RAISE function within a trigger fired",
331        SQLITE_CONSTRAINT_UNIQUE       => "A UNIQUE constraint failed",
332        SQLITE_CONSTRAINT_VTAB         => "An application-defined virtual table error occurred",
333        SQLITE_CONSTRAINT_ROWID        => "A non-unique rowid occurred",
334        SQLITE_CONSTRAINT_PINNED       => "SQLITE_CONSTRAINT_PINNED",
335        SQLITE_CONSTRAINT_DATATYPE     => "SQLITE_CONSTRAINT_DATATYPE",
336
337        SQLITE_NOTICE_RECOVER_WAL      => "A WAL mode database file was recovered",
338        SQLITE_NOTICE_RECOVER_ROLLBACK => "Hot journal was rolled back",
339
340        SQLITE_WARNING_AUTOINDEX       => "Automatic indexing used - database might benefit from additional indexes",
341
342        SQLITE_AUTH_USER               => "SQLITE_AUTH_USER", // not documented?
343
344        _ => "Unknown error code",
345    }
346}