1#![allow(non_snake_case, non_camel_case_types, clippy::type_complexity)]
2#![cfg_attr(test, allow(deref_nullptr))] use 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#[derive(Clone, Copy, Debug, PartialEq, Eq)]
114#[non_exhaustive]
115pub enum ErrorCode {
116    InternalMalfunction,
118    PermissionDenied,
120    OperationAborted,
122    DatabaseBusy,
124    DatabaseLocked,
126    OutOfMemory,
128    ReadOnly,
130    OperationInterrupted,
132    SystemIoFailure,
134    DatabaseCorrupt,
136    NotFound,
138    DiskFull,
140    CannotOpen,
142    FileLockingProtocolFailed,
144    SchemaChanged,
146    TooBig,
148    ConstraintViolation,
150    TypeMismatch,
152    ApiMisuse,
154    NoLargeFileSupport,
156    AuthorizationForStatementDenied,
158    ParameterOutOfRange,
160    NotADatabase,
162    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", 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", 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", 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", 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", 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", _ => "Unknown error code",
345    }
346}