1#![allow(non_camel_case_types)]
4
5use libc::{c_char, c_int, c_uchar, c_void};
6use sqlite_provider::{
7 ApiVersion, ColumnMetadata, Error, ErrorCode, FeatureSet, FunctionFlags, OpenFlags,
8 OpenOptions, OwnedBytes, RawBytes, Result, Sqlite3Api, Sqlite3Backup, Sqlite3BlobIo,
9 Sqlite3Hooks, Sqlite3Metadata, Sqlite3Serialize, Sqlite3Wal, StepResult, ValueType,
10};
11use std::ffi::{CStr, CString};
12use std::ptr::{NonNull, null, null_mut};
13use std::sync::OnceLock;
14
15#[cfg(target_os = "linux")]
16#[link(name = "dl")]
17unsafe extern "C" {}
18
19const SQLITE_OK: i32 = 0;
20const SQLITE_MISUSE: i32 = 21;
21const SQLITE_ROW: i32 = 100;
22const SQLITE_DONE: i32 = 101;
23const SQLITE_DESERIALIZE_FREEONCLOSE: u32 = 0x0000_0001;
24
25const SQLITE_OPEN_READONLY: i32 = 0x0000_0001;
26const SQLITE_OPEN_READWRITE: i32 = 0x0000_0002;
27const SQLITE_OPEN_CREATE: i32 = 0x0000_0004;
28const SQLITE_OPEN_URI: i32 = 0x0000_0040;
29const SQLITE_OPEN_NOMUTEX: i32 = 0x0000_8000;
30const SQLITE_OPEN_FULLMUTEX: i32 = 0x0001_0000;
31const SQLITE_OPEN_SHAREDCACHE: i32 = 0x0002_0000;
32const SQLITE_OPEN_PRIVATECACHE: i32 = 0x0004_0000;
33const SQLITE_OPEN_EXRESCODE: i32 = 0x0200_0000;
34
35const SQLITE_UTF8: i32 = 0x0000_0001;
36const SQLITE_DETERMINISTIC: i32 = 0x0000_0800;
37const SQLITE_INNOCUOUS: i32 = 0x0002_0000;
38const SQLITE_DIRECTONLY: i32 = 0x0008_0000;
39const EMPTY_BYTE: u8 = 0;
40
41type sqlite3 = c_void;
42type sqlite3_stmt = c_void;
43type sqlite3_value = c_void;
44type sqlite3_context = c_void;
45type sqlite3_backup = c_void;
46type sqlite3_blob = c_void;
47
48type sqlite3_destructor_type = Option<unsafe extern "C" fn(*mut c_void)>;
49
50type OpenV2 = unsafe extern "C" fn(*const c_char, *mut *mut sqlite3, c_int, *const c_char) -> c_int;
51type Close = unsafe extern "C" fn(*mut sqlite3) -> c_int;
52type PrepareV2 = unsafe extern "C" fn(
53 *mut sqlite3,
54 *const c_char,
55 c_int,
56 *mut *mut sqlite3_stmt,
57 *mut *const c_char,
58) -> c_int;
59type PrepareV3 = unsafe extern "C" fn(
60 *mut sqlite3,
61 *const c_char,
62 c_int,
63 u32,
64 *mut *mut sqlite3_stmt,
65 *mut *const c_char,
66) -> c_int;
67type Step = unsafe extern "C" fn(*mut sqlite3_stmt) -> c_int;
68type Reset = unsafe extern "C" fn(*mut sqlite3_stmt) -> c_int;
69type Finalize = unsafe extern "C" fn(*mut sqlite3_stmt) -> c_int;
70
71type BindNull = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> c_int;
72type BindInt64 = unsafe extern "C" fn(*mut sqlite3_stmt, c_int, i64) -> c_int;
73type BindDouble = unsafe extern "C" fn(*mut sqlite3_stmt, c_int, f64) -> c_int;
74type BindText = unsafe extern "C" fn(
75 *mut sqlite3_stmt,
76 c_int,
77 *const c_char,
78 c_int,
79 sqlite3_destructor_type,
80) -> c_int;
81type BindBlob = unsafe extern "C" fn(
82 *mut sqlite3_stmt,
83 c_int,
84 *const c_void,
85 c_int,
86 sqlite3_destructor_type,
87) -> c_int;
88
89type ColumnCount = unsafe extern "C" fn(*mut sqlite3_stmt) -> c_int;
90type ColumnType = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> c_int;
91type ColumnInt64 = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> i64;
92type ColumnDouble = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> f64;
93type ColumnText = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> *const c_uchar;
94type ColumnBlob = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> *const c_void;
95type ColumnBytes = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> c_int;
96
97type ErrCode = unsafe extern "C" fn(*mut sqlite3) -> c_int;
98type ErrMsg = unsafe extern "C" fn(*mut sqlite3) -> *const c_char;
99type ExtendedErrCode = unsafe extern "C" fn(*mut sqlite3) -> c_int;
100
101type CreateFunctionV2 = unsafe extern "C" fn(
102 *mut sqlite3,
103 *const c_char,
104 c_int,
105 c_int,
106 *mut c_void,
107 Option<extern "C" fn(*mut sqlite3_context, c_int, *mut *mut sqlite3_value)>,
108 Option<extern "C" fn(*mut sqlite3_context, c_int, *mut *mut sqlite3_value)>,
109 Option<extern "C" fn(*mut sqlite3_context)>,
110 Option<extern "C" fn(*mut c_void)>,
111) -> c_int;
112
113type CreateWindowFunction = unsafe extern "C" fn(
114 *mut sqlite3,
115 *const c_char,
116 c_int,
117 c_int,
118 *mut c_void,
119 Option<extern "C" fn(*mut sqlite3_context, c_int, *mut *mut sqlite3_value)>,
120 Option<extern "C" fn(*mut sqlite3_context)>,
121 Option<extern "C" fn(*mut sqlite3_context)>,
122 Option<extern "C" fn(*mut sqlite3_context, c_int, *mut *mut sqlite3_value)>,
123 Option<extern "C" fn(*mut c_void)>,
124) -> c_int;
125type CreateCollationV2 = unsafe extern "C" fn(
126 *mut sqlite3,
127 *const c_char,
128 c_int,
129 *mut c_void,
130 Option<extern "C" fn(*mut c_void, c_int, *const c_void, c_int, *const c_void) -> c_int>,
131 Option<extern "C" fn(*mut c_void)>,
132) -> c_int;
133
134type AggregateContext = unsafe extern "C" fn(*mut sqlite3_context, c_int) -> *mut c_void;
135type ResultNull = unsafe extern "C" fn(*mut sqlite3_context);
136type ResultInt64 = unsafe extern "C" fn(*mut sqlite3_context, i64);
137type ResultDouble = unsafe extern "C" fn(*mut sqlite3_context, f64);
138type ResultText =
139 unsafe extern "C" fn(*mut sqlite3_context, *const c_char, c_int, sqlite3_destructor_type);
140type ResultBlob =
141 unsafe extern "C" fn(*mut sqlite3_context, *const c_void, c_int, sqlite3_destructor_type);
142type ResultError = unsafe extern "C" fn(*mut sqlite3_context, *const c_char, c_int);
143type UserData = unsafe extern "C" fn(*mut sqlite3_context) -> *mut c_void;
144
145type ValueTypeFn = unsafe extern "C" fn(*mut sqlite3_value) -> c_int;
146type ValueInt64Fn = unsafe extern "C" fn(*mut sqlite3_value) -> i64;
147type ValueDoubleFn = unsafe extern "C" fn(*mut sqlite3_value) -> f64;
148type ValueTextFn = unsafe extern "C" fn(*mut sqlite3_value) -> *const c_uchar;
149type ValueBlobFn = unsafe extern "C" fn(*mut sqlite3_value) -> *const c_void;
150type ValueBytesFn = unsafe extern "C" fn(*mut sqlite3_value) -> c_int;
151
152type DeclareVTab = unsafe extern "C" fn(*mut sqlite3, *const c_char) -> c_int;
153type CreateModuleV2 = unsafe extern "C" fn(
154 *mut sqlite3,
155 *const c_char,
156 *const c_void,
157 *mut c_void,
158 Option<extern "C" fn(*mut c_void)>,
159) -> c_int;
160
161type LibversionNumber = unsafe extern "C" fn() -> c_int;
162type Threadsafe = unsafe extern "C" fn() -> c_int;
163
164type Malloc = unsafe extern "C" fn(c_int) -> *mut c_void;
165type Free = unsafe extern "C" fn(*mut c_void);
166
167type ColumnDecltype = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> *const c_char;
168type ColumnName = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> *const c_char;
169type ColumnTableName = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> *const c_char;
170type TableColumnMetadata = unsafe extern "C" fn(
171 *mut sqlite3,
172 *const c_char,
173 *const c_char,
174 *const c_char,
175 *mut *const c_char,
176 *mut *const c_char,
177 *mut c_int,
178 *mut c_int,
179 *mut c_int,
180) -> c_int;
181type DbFilename = unsafe extern "C" fn(*mut sqlite3, *const c_char) -> *const c_char;
182type GetAutocommit = unsafe extern "C" fn(*mut sqlite3) -> c_int;
183type TotalChanges = unsafe extern "C" fn(*mut sqlite3) -> c_int;
184type Changes = unsafe extern "C" fn(*mut sqlite3) -> c_int;
185type Changes64 = unsafe extern "C" fn(*mut sqlite3) -> i64;
186type LastInsertRowid = unsafe extern "C" fn(*mut sqlite3) -> i64;
187type Interrupt = unsafe extern "C" fn(*mut sqlite3);
188type DbConfig = unsafe extern "C" fn(*mut sqlite3, c_int, ...) -> c_int;
189type Limit = unsafe extern "C" fn(*mut sqlite3, c_int, c_int) -> c_int;
190type StmtReadonly = unsafe extern "C" fn(*mut sqlite3_stmt) -> c_int;
191type StmtBusy = unsafe extern "C" fn(*mut sqlite3_stmt) -> c_int;
192type BindParameterCount = unsafe extern "C" fn(*mut sqlite3_stmt) -> c_int;
193type BindParameterName = unsafe extern "C" fn(*mut sqlite3_stmt, c_int) -> *const c_char;
194type BindParameterIndex = unsafe extern "C" fn(*mut sqlite3_stmt, *const c_char) -> c_int;
195type ContextDbHandle = unsafe extern "C" fn(*mut sqlite3_context) -> *mut sqlite3;
196type TraceV2 = unsafe extern "C" fn(
197 *mut sqlite3,
198 u32,
199 Option<extern "C" fn(u32, *mut c_void, *mut c_void, *mut c_void)>,
200 *mut c_void,
201) -> c_int;
202type ProgressHandler = unsafe extern "C" fn(
203 *mut sqlite3,
204 c_int,
205 Option<extern "C" fn(*mut c_void) -> c_int>,
206 *mut c_void,
207);
208type BusyTimeout = unsafe extern "C" fn(*mut sqlite3, c_int) -> c_int;
209type SetAuthorizer = unsafe extern "C" fn(
210 *mut sqlite3,
211 Option<
212 extern "C" fn(
213 *mut c_void,
214 c_int,
215 *const c_char,
216 *const c_char,
217 *const c_char,
218 *const c_char,
219 ) -> c_int,
220 >,
221 *mut c_void,
222) -> c_int;
223type BackupInit = unsafe extern "C" fn(
224 *mut sqlite3,
225 *const c_char,
226 *mut sqlite3,
227 *const c_char,
228) -> *mut sqlite3_backup;
229type BackupStep = unsafe extern "C" fn(*mut sqlite3_backup, c_int) -> c_int;
230type BackupRemaining = unsafe extern "C" fn(*mut sqlite3_backup) -> c_int;
231type BackupPagecount = unsafe extern "C" fn(*mut sqlite3_backup) -> c_int;
232type BackupFinish = unsafe extern "C" fn(*mut sqlite3_backup) -> c_int;
233type BlobOpen = unsafe extern "C" fn(
234 *mut sqlite3,
235 *const c_char,
236 *const c_char,
237 *const c_char,
238 i64,
239 c_int,
240 *mut *mut sqlite3_blob,
241) -> c_int;
242type BlobRead = unsafe extern "C" fn(*mut sqlite3_blob, *mut c_void, c_int, c_int) -> c_int;
243type BlobWrite = unsafe extern "C" fn(*mut sqlite3_blob, *const c_void, c_int, c_int) -> c_int;
244type BlobBytes = unsafe extern "C" fn(*mut sqlite3_blob) -> c_int;
245type BlobClose = unsafe extern "C" fn(*mut sqlite3_blob) -> c_int;
246type Serialize = unsafe extern "C" fn(*mut sqlite3, *const c_char, *mut i64, u32) -> *mut c_uchar;
247type Deserialize =
248 unsafe extern "C" fn(*mut sqlite3, *const c_char, *mut c_uchar, i64, i64, u32) -> c_int;
249type WalCheckpoint = unsafe extern "C" fn(*mut sqlite3, *const c_char) -> c_int;
250type WalCheckpointV2 =
251 unsafe extern "C" fn(*mut sqlite3, *const c_char, c_int, *mut c_int, *mut c_int) -> c_int;
252type LibsqlWalFrameCount = unsafe extern "C" fn(*mut sqlite3, *mut u32) -> c_int;
253
254struct LibHandle {
255 handle: *mut c_void,
256}
257
258unsafe impl Send for LibHandle {}
259unsafe impl Sync for LibHandle {}
260
261#[allow(unsafe_op_in_unsafe_fn)]
262impl LibHandle {
263 unsafe fn open() -> Option<Self> {
264 let mut handle = null_mut();
265 for name in lib_names() {
266 let cstr = CStr::from_bytes_with_nul_unchecked(name);
267 handle = libc::dlopen(cstr.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL);
268 if !handle.is_null() {
269 break;
270 }
271 }
272 if handle.is_null() {
273 None
274 } else {
275 Some(Self { handle })
276 }
277 }
278
279 unsafe fn symbol<T>(&self, name: &'static [u8]) -> Option<T>
280 where
281 T: Copy,
282 {
283 let sym = libc::dlsym(self.handle, name.as_ptr() as *const c_char);
284 if sym.is_null() {
285 None
286 } else {
287 debug_assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<*mut c_void>());
288 Some(std::mem::transmute_copy(&sym))
289 }
290 }
291}
292
293struct LibSqlite3Fns {
294 open_v2: OpenV2,
295 close: Close,
296 prepare_v2: PrepareV2,
297 prepare_v3: Option<PrepareV3>,
298 step: Step,
299 reset: Reset,
300 finalize: Finalize,
301 bind_null: BindNull,
302 bind_int64: BindInt64,
303 bind_double: BindDouble,
304 bind_text: BindText,
305 bind_blob: BindBlob,
306 column_count: ColumnCount,
307 column_type: ColumnType,
308 column_int64: ColumnInt64,
309 column_double: ColumnDouble,
310 column_text: ColumnText,
311 column_blob: ColumnBlob,
312 column_bytes: ColumnBytes,
313 errcode: ErrCode,
314 errmsg: ErrMsg,
315 extended_errcode: Option<ExtendedErrCode>,
316 create_function_v2: CreateFunctionV2,
317 create_window_function: Option<CreateWindowFunction>,
318 create_collation_v2: Option<CreateCollationV2>,
319 aggregate_context: AggregateContext,
320 result_null: ResultNull,
321 result_int64: ResultInt64,
322 result_double: ResultDouble,
323 result_text: ResultText,
324 result_blob: ResultBlob,
325 result_error: ResultError,
326 user_data: UserData,
327 value_type: ValueTypeFn,
328 value_int64: ValueInt64Fn,
329 value_double: ValueDoubleFn,
330 value_text: ValueTextFn,
331 value_blob: ValueBlobFn,
332 value_bytes: ValueBytesFn,
333 declare_vtab: DeclareVTab,
334 create_module_v2: Option<CreateModuleV2>,
335 libversion_number: LibversionNumber,
336 threadsafe: Option<Threadsafe>,
337 malloc: Malloc,
338 free: Free,
339 column_decltype: ColumnDecltype,
340 column_name: ColumnName,
341 column_table_name: Option<ColumnTableName>,
342 table_column_metadata: Option<TableColumnMetadata>,
343 db_filename: Option<DbFilename>,
344 get_autocommit: Option<GetAutocommit>,
345 total_changes: Option<TotalChanges>,
346 changes: Option<Changes>,
347 changes64: Option<Changes64>,
348 last_insert_rowid: Option<LastInsertRowid>,
349 interrupt: Option<Interrupt>,
350 db_config: Option<DbConfig>,
351 limit: Option<Limit>,
352 stmt_readonly: Option<StmtReadonly>,
353 stmt_busy: Option<StmtBusy>,
354 bind_parameter_count: Option<BindParameterCount>,
355 bind_parameter_name: Option<BindParameterName>,
356 bind_parameter_index: Option<BindParameterIndex>,
357 context_db_handle: Option<ContextDbHandle>,
358 trace_v2: Option<TraceV2>,
359 progress_handler: Option<ProgressHandler>,
360 busy_timeout: Option<BusyTimeout>,
361 set_authorizer: Option<SetAuthorizer>,
362 backup_init: Option<BackupInit>,
363 backup_step: Option<BackupStep>,
364 backup_remaining: Option<BackupRemaining>,
365 backup_pagecount: Option<BackupPagecount>,
366 backup_finish: Option<BackupFinish>,
367 blob_open: Option<BlobOpen>,
368 blob_read: Option<BlobRead>,
369 blob_write: Option<BlobWrite>,
370 blob_bytes: Option<BlobBytes>,
371 blob_close: Option<BlobClose>,
372 serialize: Option<Serialize>,
373 deserialize: Option<Deserialize>,
374 wal_checkpoint: Option<WalCheckpoint>,
375 wal_checkpoint_v2: Option<WalCheckpointV2>,
376 libsql_wal_frame_count: Option<LibsqlWalFrameCount>,
377}
378
379#[allow(unsafe_op_in_unsafe_fn)]
380impl LibSqlite3Fns {
381 unsafe fn load(lib: &LibHandle) -> Option<Self> {
382 Some(Self {
383 open_v2: lib.symbol(b"sqlite3_open_v2\0")?,
384 close: lib.symbol(b"sqlite3_close\0")?,
385 prepare_v2: lib.symbol(b"sqlite3_prepare_v2\0")?,
386 prepare_v3: lib.symbol(b"sqlite3_prepare_v3\0"),
387 step: lib.symbol(b"sqlite3_step\0")?,
388 reset: lib.symbol(b"sqlite3_reset\0")?,
389 finalize: lib.symbol(b"sqlite3_finalize\0")?,
390 bind_null: lib.symbol(b"sqlite3_bind_null\0")?,
391 bind_int64: lib.symbol(b"sqlite3_bind_int64\0")?,
392 bind_double: lib.symbol(b"sqlite3_bind_double\0")?,
393 bind_text: lib.symbol(b"sqlite3_bind_text\0")?,
394 bind_blob: lib.symbol(b"sqlite3_bind_blob\0")?,
395 column_count: lib.symbol(b"sqlite3_column_count\0")?,
396 column_type: lib.symbol(b"sqlite3_column_type\0")?,
397 column_int64: lib.symbol(b"sqlite3_column_int64\0")?,
398 column_double: lib.symbol(b"sqlite3_column_double\0")?,
399 column_text: lib.symbol(b"sqlite3_column_text\0")?,
400 column_blob: lib.symbol(b"sqlite3_column_blob\0")?,
401 column_bytes: lib.symbol(b"sqlite3_column_bytes\0")?,
402 errcode: lib.symbol(b"sqlite3_errcode\0")?,
403 errmsg: lib.symbol(b"sqlite3_errmsg\0")?,
404 extended_errcode: lib.symbol(b"sqlite3_extended_errcode\0"),
405 create_function_v2: lib.symbol(b"sqlite3_create_function_v2\0")?,
406 create_window_function: lib.symbol(b"sqlite3_create_window_function\0"),
407 create_collation_v2: lib.symbol(b"sqlite3_create_collation_v2\0"),
408 aggregate_context: lib.symbol(b"sqlite3_aggregate_context\0")?,
409 result_null: lib.symbol(b"sqlite3_result_null\0")?,
410 result_int64: lib.symbol(b"sqlite3_result_int64\0")?,
411 result_double: lib.symbol(b"sqlite3_result_double\0")?,
412 result_text: lib.symbol(b"sqlite3_result_text\0")?,
413 result_blob: lib.symbol(b"sqlite3_result_blob\0")?,
414 result_error: lib.symbol(b"sqlite3_result_error\0")?,
415 user_data: lib.symbol(b"sqlite3_user_data\0")?,
416 value_type: lib.symbol(b"sqlite3_value_type\0")?,
417 value_int64: lib.symbol(b"sqlite3_value_int64\0")?,
418 value_double: lib.symbol(b"sqlite3_value_double\0")?,
419 value_text: lib.symbol(b"sqlite3_value_text\0")?,
420 value_blob: lib.symbol(b"sqlite3_value_blob\0")?,
421 value_bytes: lib.symbol(b"sqlite3_value_bytes\0")?,
422 declare_vtab: lib.symbol(b"sqlite3_declare_vtab\0")?,
423 create_module_v2: lib.symbol(b"sqlite3_create_module_v2\0"),
424 libversion_number: lib.symbol(b"sqlite3_libversion_number\0")?,
425 threadsafe: lib.symbol(b"sqlite3_threadsafe\0"),
426 malloc: lib.symbol(b"sqlite3_malloc\0")?,
427 free: lib.symbol(b"sqlite3_free\0")?,
428 column_decltype: lib.symbol(b"sqlite3_column_decltype\0")?,
429 column_name: lib.symbol(b"sqlite3_column_name\0")?,
430 column_table_name: lib.symbol(b"sqlite3_column_table_name\0"),
431 table_column_metadata: lib.symbol(b"sqlite3_table_column_metadata\0"),
432 db_filename: lib.symbol(b"sqlite3_db_filename\0"),
433 get_autocommit: lib.symbol(b"sqlite3_get_autocommit\0"),
434 total_changes: lib.symbol(b"sqlite3_total_changes\0"),
435 changes: lib.symbol(b"sqlite3_changes\0"),
436 changes64: lib.symbol(b"sqlite3_changes64\0"),
437 last_insert_rowid: lib.symbol(b"sqlite3_last_insert_rowid\0"),
438 interrupt: lib.symbol(b"sqlite3_interrupt\0"),
439 db_config: lib.symbol(b"sqlite3_db_config\0"),
440 limit: lib.symbol(b"sqlite3_limit\0"),
441 stmt_readonly: lib.symbol(b"sqlite3_stmt_readonly\0"),
442 stmt_busy: lib.symbol(b"sqlite3_stmt_busy\0"),
443 bind_parameter_count: lib.symbol(b"sqlite3_bind_parameter_count\0"),
444 bind_parameter_name: lib.symbol(b"sqlite3_bind_parameter_name\0"),
445 bind_parameter_index: lib.symbol(b"sqlite3_bind_parameter_index\0"),
446 context_db_handle: lib.symbol(b"sqlite3_context_db_handle\0"),
447 trace_v2: lib.symbol(b"sqlite3_trace_v2\0"),
448 progress_handler: lib.symbol(b"sqlite3_progress_handler\0"),
449 busy_timeout: lib.symbol(b"sqlite3_busy_timeout\0"),
450 set_authorizer: lib.symbol(b"sqlite3_set_authorizer\0"),
451 backup_init: lib.symbol(b"sqlite3_backup_init\0"),
452 backup_step: lib.symbol(b"sqlite3_backup_step\0"),
453 backup_remaining: lib.symbol(b"sqlite3_backup_remaining\0"),
454 backup_pagecount: lib.symbol(b"sqlite3_backup_pagecount\0"),
455 backup_finish: lib.symbol(b"sqlite3_backup_finish\0"),
456 blob_open: lib.symbol(b"sqlite3_blob_open\0"),
457 blob_read: lib.symbol(b"sqlite3_blob_read\0"),
458 blob_write: lib.symbol(b"sqlite3_blob_write\0"),
459 blob_bytes: lib.symbol(b"sqlite3_blob_bytes\0"),
460 blob_close: lib.symbol(b"sqlite3_blob_close\0"),
461 serialize: lib.symbol(b"sqlite3_serialize\0"),
462 deserialize: lib.symbol(b"sqlite3_deserialize\0"),
463 wal_checkpoint: lib.symbol(b"sqlite3_wal_checkpoint\0"),
464 wal_checkpoint_v2: lib.symbol(b"sqlite3_wal_checkpoint_v2\0"),
465 libsql_wal_frame_count: lib.symbol(b"libsql_wal_frame_count\0"),
466 })
467 }
468}
469
470static USER_DATA_FN: OnceLock<UserData> = OnceLock::new();
471static ADAPTER_INSTANCE: OnceLock<Option<&'static LibSqlite3>> = OnceLock::new();
472
473pub struct LibSqlite3 {
475 fns: LibSqlite3Fns,
476 features: FeatureSet,
477 api_version: ApiVersion,
478 _lib: LibHandle,
479}
480
481#[allow(unsafe_op_in_unsafe_fn)]
482impl LibSqlite3 {
483 pub fn load() -> Option<&'static LibSqlite3> {
487 ADAPTER_INSTANCE
488 .get_or_init(|| unsafe { Self::load_inner() })
489 .as_ref()
490 .copied()
491 }
492
493 unsafe fn load_inner() -> Option<&'static LibSqlite3> {
494 unsafe {
495 let lib = LibHandle::open()?;
496 let fns = LibSqlite3Fns::load(&lib)?;
497 let version_number = (fns.libversion_number)();
498 let api_version = api_version_from_number(version_number);
499 let mut features = FeatureSet::CREATE_FUNCTION_V2;
500 if fns.prepare_v3.is_some() {
501 features |= FeatureSet::PREPARE_V3;
502 }
503 if fns.create_window_function.is_some() {
504 features |= FeatureSet::WINDOW_FUNCTIONS;
505 }
506 if fns.extended_errcode.is_some() {
507 features |= FeatureSet::EXTENDED_ERRCODES;
508 }
509 if fns.create_module_v2.is_some() {
510 features |= FeatureSet::VIRTUAL_TABLES;
511 }
512 let _ = USER_DATA_FN.set(fns.user_data);
513 let adapter = LibSqlite3 {
514 fns,
515 features,
516 api_version,
517 _lib: lib,
518 };
519 Some(Box::leak(Box::new(adapter)))
520 }
521 }
522
523 fn error_from_rc(&self, rc: i32, db: Option<NonNull<sqlite3>>) -> Error {
524 let message = db
525 .and_then(|db| unsafe { raw_cstr((self.fns.errmsg)(db.as_ptr())) })
526 .map(|c| c.to_string_lossy().into_owned());
527 let extended =
528 db.and_then(|db| self.fns.extended_errcode.map(|f| unsafe { f(db.as_ptr()) }));
529 Error::from_code(rc, message, extended)
530 }
531
532 fn alloc_copy(&self, bytes: &[u8]) -> Result<(*const c_void, sqlite3_destructor_type)> {
534 if bytes.is_empty() {
535 return Ok((&EMPTY_BYTE as *const u8 as *const c_void, None));
536 }
537 if bytes.len() > i32::MAX as usize {
538 return Err(Error::with_message(ErrorCode::Misuse, "value too large"));
539 }
540 let ptr = unsafe { (self.fns.malloc)(bytes.len() as i32) };
541 if ptr.is_null() {
542 return Err(Error::new(ErrorCode::NoMem));
543 }
544 unsafe {
545 std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len());
546 }
547 Ok((ptr, Some(self.fns.free)))
548 }
549
550 pub unsafe fn abi_db_filename(&self, db: *mut c_void, name: Option<&str>) -> Option<RawBytes> {
559 let func = self.fns.db_filename?;
560 let name = match name {
561 Some(name) => Some(CString::new(name).ok()?),
562 None => None,
563 };
564 let ptr = func(
565 db as *mut sqlite3,
566 name.as_ref().map(|s| s.as_ptr()).unwrap_or(null()),
567 );
568 raw_cstr(ptr).map(raw_bytes_from_cstr)
569 }
570
571 pub unsafe fn abi_get_autocommit(&self, db: *mut c_void) -> i32 {
576 self.fns
577 .get_autocommit
578 .map(|f| f(db as *mut sqlite3))
579 .unwrap_or(1)
580 }
581
582 pub unsafe fn abi_total_changes(&self, db: *mut c_void) -> i32 {
587 self.fns
588 .total_changes
589 .map(|f| f(db as *mut sqlite3))
590 .unwrap_or(0)
591 }
592
593 pub unsafe fn abi_changes(&self, db: *mut c_void) -> i32 {
598 self.fns.changes.map(|f| f(db as *mut sqlite3)).unwrap_or(0)
599 }
600
601 pub unsafe fn abi_changes64(&self, db: *mut c_void) -> i64 {
606 self.fns
607 .changes64
608 .map(|f| f(db as *mut sqlite3))
609 .unwrap_or(0)
610 }
611
612 pub unsafe fn abi_last_insert_rowid(&self, db: *mut c_void) -> i64 {
617 self.fns
618 .last_insert_rowid
619 .map(|f| f(db as *mut sqlite3))
620 .unwrap_or(0)
621 }
622
623 pub unsafe fn abi_interrupt(&self, db: *mut c_void) {
628 if let Some(func) = self.fns.interrupt {
629 func(db as *mut sqlite3);
630 }
631 }
632
633 pub unsafe fn abi_db_config(&self, db: *mut c_void, op: i32) -> i32 {
638 self.fns
640 .db_config
641 .map(|f| f(db as *mut sqlite3, op))
642 .unwrap_or(SQLITE_MISUSE)
643 }
644
645 pub unsafe fn abi_limit(&self, db: *mut c_void, id: i32, new_value: i32) -> i32 {
650 self.fns
651 .limit
652 .map(|f| f(db as *mut sqlite3, id, new_value))
653 .unwrap_or(-1)
654 }
655
656 pub unsafe fn abi_stmt_readonly(&self, stmt: *mut c_void) -> i32 {
661 self.fns
662 .stmt_readonly
663 .map(|f| f(stmt as *mut sqlite3_stmt))
664 .unwrap_or(0)
665 }
666
667 pub unsafe fn abi_stmt_busy(&self, stmt: *mut c_void) -> i32 {
672 self.fns
673 .stmt_busy
674 .map(|f| f(stmt as *mut sqlite3_stmt))
675 .unwrap_or(0)
676 }
677
678 pub unsafe fn abi_bind_parameter_count(&self, stmt: *mut c_void) -> i32 {
683 self.fns
684 .bind_parameter_count
685 .map(|f| f(stmt as *mut sqlite3_stmt))
686 .unwrap_or(0)
687 }
688
689 pub unsafe fn abi_bind_parameter_name(&self, stmt: *mut c_void, idx: i32) -> Option<RawBytes> {
697 let func = self.fns.bind_parameter_name?;
698 let ptr = func(stmt as *mut sqlite3_stmt, idx);
699 raw_cstr(ptr).map(raw_bytes_from_cstr)
700 }
701
702 pub unsafe fn abi_bind_parameter_index(&self, stmt: *mut c_void, name: &str) -> i32 {
707 let func = match self.fns.bind_parameter_index {
708 Some(func) => func,
709 None => return 0,
710 };
711 let name = match CString::new(name) {
712 Ok(name) => name,
713 Err(_) => return 0,
714 };
715 func(stmt as *mut sqlite3_stmt, name.as_ptr())
716 }
717
718 pub unsafe fn abi_context_db_handle(&self, ctx: *mut c_void) -> Option<NonNull<c_void>> {
724 let func = self.fns.context_db_handle?;
725 NonNull::new(func(ctx as *mut sqlite3_context))
726 }
727}
728
729mod core_impl;
730mod extensions_impl;
731
732fn api_version_from_number(number: i32) -> ApiVersion {
733 let major = (number / 1_000_000) as u16;
734 let minor = ((number / 1_000) % 1_000) as u16;
735 let patch = (number % 1_000) as u16;
736 ApiVersion::new(major, minor, patch)
737}
738
739fn map_open_flags(flags: OpenFlags) -> i32 {
740 let mut out = 0;
741 if flags.contains(OpenFlags::READ_ONLY) {
742 out |= SQLITE_OPEN_READONLY;
743 }
744 if flags.contains(OpenFlags::READ_WRITE) {
745 out |= SQLITE_OPEN_READWRITE;
746 }
747 if flags.contains(OpenFlags::CREATE) {
748 out |= SQLITE_OPEN_CREATE;
749 }
750 if flags.contains(OpenFlags::URI) {
751 out |= SQLITE_OPEN_URI;
752 }
753 if flags.contains(OpenFlags::NO_MUTEX) {
754 out |= SQLITE_OPEN_NOMUTEX;
755 }
756 if flags.contains(OpenFlags::FULL_MUTEX) {
757 out |= SQLITE_OPEN_FULLMUTEX;
758 }
759 if flags.contains(OpenFlags::SHARED_CACHE) {
760 out |= SQLITE_OPEN_SHAREDCACHE;
761 }
762 if flags.contains(OpenFlags::PRIVATE_CACHE) {
763 out |= SQLITE_OPEN_PRIVATECACHE;
764 }
765 if flags.contains(OpenFlags::EXRESCODE) {
766 out |= SQLITE_OPEN_EXRESCODE;
767 }
768 out
769}
770
771fn map_function_flags(flags: FunctionFlags) -> i32 {
772 let mut out = SQLITE_UTF8;
773 if flags.contains(FunctionFlags::DETERMINISTIC) {
774 out |= SQLITE_DETERMINISTIC;
775 }
776 if flags.contains(FunctionFlags::DIRECT_ONLY) {
777 out |= SQLITE_DIRECTONLY;
778 }
779 if flags.contains(FunctionFlags::INNOCUOUS) {
780 out |= SQLITE_INNOCUOUS;
781 }
782 out
783}
784
785fn clamp_len(len: usize) -> i32 {
786 if len > i32::MAX as usize {
787 i32::MAX
788 } else {
789 len as i32
790 }
791}
792
793#[allow(unsafe_op_in_unsafe_fn)]
794unsafe fn raw_cstr<'a>(ptr: *const c_char) -> Option<&'a CStr> {
795 if ptr.is_null() {
796 None
797 } else {
798 Some(CStr::from_ptr(ptr))
799 }
800}
801
802fn raw_bytes_from_cstr(cstr: &CStr) -> RawBytes {
803 RawBytes {
804 ptr: cstr.as_ptr(),
805 len: cstr.to_bytes().len(),
806 }
807}
808
809fn lib_names() -> &'static [&'static [u8]] {
810 #[cfg(target_os = "macos")]
811 const NAMES: [&[u8]; 3] = [
812 b"libsqlite3.dylib\0",
813 b"libsqlite3.so.0\0",
814 b"libsqlite3.so\0",
815 ];
816 #[cfg(not(target_os = "macos"))]
817 const NAMES: [&[u8]; 2] = [b"libsqlite3.so.0\0", b"libsqlite3.so\0"];
818 &NAMES
819}
820
821#[cfg(test)]
822mod tests {
823 use super::LibSqlite3;
824
825 #[test]
826 fn load_returns_stable_process_singleton() {
827 let first = LibSqlite3::load();
828 let second = LibSqlite3::load();
829 match (first, second) {
830 (Some(first), Some(second)) => {
831 assert!(std::ptr::eq(first, second));
832 }
833 (None, None) => {}
834 _ => panic!("LibSqlite3::load result changed across calls"),
835 }
836 }
837}