1use super::*;
2
3#[allow(unsafe_op_in_unsafe_fn)]
4unsafe impl Sqlite3Metadata for LibSqlite3 {
5 unsafe fn table_column_metadata(
6 &self,
7 db: NonNull<Self::Db>,
8 db_name: Option<&str>,
9 table: &str,
10 column: &str,
11 ) -> Result<ColumnMetadata> {
12 let table = CString::new(table)
13 .map_err(|_| Error::with_message(ErrorCode::Misuse, "table contains NUL"))?;
14 let column = CString::new(column)
15 .map_err(|_| Error::with_message(ErrorCode::Misuse, "column contains NUL"))?;
16 let db_name = match db_name {
17 Some(name) => Some(
18 CString::new(name)
19 .map_err(|_| Error::with_message(ErrorCode::Misuse, "db name contains NUL"))?,
20 ),
21 None => None,
22 };
23 let func = match self.fns.table_column_metadata {
24 Some(func) => func,
25 None => {
26 return Err(Error::feature_unavailable(
27 "table_column_metadata not available",
28 ));
29 }
30 };
31 let mut data_type = null();
32 let mut coll_seq = null();
33 let mut not_null = 0;
34 let mut primary_key = 0;
35 let mut autoinc = 0;
36 let rc = func(
37 db.as_ptr(),
38 db_name.as_ref().map(|s| s.as_ptr()).unwrap_or(null()),
39 table.as_ptr(),
40 column.as_ptr(),
41 &mut data_type,
42 &mut coll_seq,
43 &mut not_null,
44 &mut primary_key,
45 &mut autoinc,
46 );
47 if rc != SQLITE_OK {
48 return Err(self.error_from_rc(rc, Some(db)));
49 }
50 Ok(ColumnMetadata {
51 data_type: raw_cstr(data_type).map(raw_bytes_from_cstr),
52 coll_seq: raw_cstr(coll_seq).map(raw_bytes_from_cstr),
53 not_null: not_null != 0,
54 primary_key: primary_key != 0,
55 autoinc: autoinc != 0,
56 })
57 }
58
59 unsafe fn column_decltype(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes> {
60 let ptr = (self.fns.column_decltype)(stmt.as_ptr(), col);
61 raw_cstr(ptr).map(raw_bytes_from_cstr)
62 }
63
64 unsafe fn column_name(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes> {
65 let ptr = (self.fns.column_name)(stmt.as_ptr(), col);
66 raw_cstr(ptr).map(raw_bytes_from_cstr)
67 }
68
69 unsafe fn column_table_name(&self, stmt: NonNull<Self::Stmt>, col: i32) -> Option<RawBytes> {
70 let func = self.fns.column_table_name?;
71 let ptr = func(stmt.as_ptr(), col);
72 raw_cstr(ptr).map(raw_bytes_from_cstr)
73 }
74}
75
76#[allow(unsafe_op_in_unsafe_fn)]
77unsafe impl Sqlite3Hooks for LibSqlite3 {
78 unsafe fn trace_v2(
79 &self,
80 db: NonNull<Self::Db>,
81 mask: u32,
82 callback: Option<extern "C" fn(u32, *mut c_void, *mut c_void, *mut c_void)>,
83 context: *mut c_void,
84 ) -> Result<()> {
85 let trace = match self.fns.trace_v2 {
86 Some(trace) => trace,
87 None => return Err(Error::feature_unavailable("trace_v2 not available")),
88 };
89 let rc = trace(db.as_ptr(), mask, callback, context);
90 if rc == SQLITE_OK {
91 Ok(())
92 } else {
93 Err(self.error_from_rc(rc, Some(db)))
94 }
95 }
96
97 unsafe fn progress_handler(
98 &self,
99 db: NonNull<Self::Db>,
100 n: i32,
101 callback: Option<extern "C" fn(*mut c_void) -> i32>,
102 context: *mut c_void,
103 ) -> Result<()> {
104 let progress = match self.fns.progress_handler {
105 Some(progress) => progress,
106 None => return Err(Error::feature_unavailable("progress_handler not available")),
107 };
108 progress(db.as_ptr(), n, callback, context);
109 Ok(())
110 }
111
112 unsafe fn busy_timeout(&self, db: NonNull<Self::Db>, ms: i32) -> Result<()> {
113 let busy_timeout = match self.fns.busy_timeout {
114 Some(busy_timeout) => busy_timeout,
115 None => return Err(Error::feature_unavailable("busy_timeout not available")),
116 };
117 let rc = busy_timeout(db.as_ptr(), ms);
118 if rc == SQLITE_OK {
119 Ok(())
120 } else {
121 Err(self.error_from_rc(rc, Some(db)))
122 }
123 }
124
125 unsafe fn set_authorizer(
126 &self,
127 db: NonNull<Self::Db>,
128 callback: Option<
129 extern "C" fn(
130 *mut c_void,
131 i32,
132 *const c_char,
133 *const c_char,
134 *const c_char,
135 *const c_char,
136 ) -> i32,
137 >,
138 context: *mut c_void,
139 ) -> Result<()> {
140 let set_authorizer = match self.fns.set_authorizer {
141 Some(set_authorizer) => set_authorizer,
142 None => return Err(Error::feature_unavailable("set_authorizer not available")),
143 };
144 let rc = set_authorizer(db.as_ptr(), callback, context);
145 if rc == SQLITE_OK {
146 Ok(())
147 } else {
148 Err(self.error_from_rc(rc, Some(db)))
149 }
150 }
151}
152
153#[allow(unsafe_op_in_unsafe_fn)]
154unsafe impl Sqlite3Backup for LibSqlite3 {
155 type Backup = sqlite3_backup;
156
157 unsafe fn backup_init(
158 &self,
159 dest_db: NonNull<Self::Db>,
160 dest_name: &str,
161 source_db: NonNull<Self::Db>,
162 source_name: &str,
163 ) -> Result<NonNull<Self::Backup>> {
164 let backup_init = match self.fns.backup_init {
165 Some(backup_init) => backup_init,
166 None => return Err(Error::feature_unavailable("backup_init not available")),
167 };
168 let dest_name = CString::new(dest_name)
169 .map_err(|_| Error::with_message(ErrorCode::Misuse, "dest name contains NUL"))?;
170 let source_name = CString::new(source_name)
171 .map_err(|_| Error::with_message(ErrorCode::Misuse, "source name contains NUL"))?;
172 let backup = backup_init(
173 dest_db.as_ptr(),
174 dest_name.as_ptr(),
175 source_db.as_ptr(),
176 source_name.as_ptr(),
177 );
178 if let Some(backup) = NonNull::new(backup) {
179 Ok(backup)
180 } else {
181 let rc = (self.fns.errcode)(dest_db.as_ptr());
182 Err(self.error_from_rc(rc, Some(dest_db)))
183 }
184 }
185
186 unsafe fn backup_step(&self, backup: NonNull<Self::Backup>, pages: i32) -> Result<()> {
187 let backup_step = match self.fns.backup_step {
188 Some(backup_step) => backup_step,
189 None => return Err(Error::feature_unavailable("backup_step not available")),
190 };
191 let rc = backup_step(backup.as_ptr(), pages);
192 if rc == SQLITE_OK || rc == SQLITE_DONE {
193 Ok(())
194 } else {
195 Err(self.error_from_rc(rc, None))
196 }
197 }
198
199 unsafe fn backup_remaining(&self, backup: NonNull<Self::Backup>) -> i32 {
200 self.fns
201 .backup_remaining
202 .map(|f| f(backup.as_ptr()))
203 .unwrap_or(0)
204 }
205
206 unsafe fn backup_pagecount(&self, backup: NonNull<Self::Backup>) -> i32 {
207 self.fns
208 .backup_pagecount
209 .map(|f| f(backup.as_ptr()))
210 .unwrap_or(0)
211 }
212
213 unsafe fn backup_finish(&self, backup: NonNull<Self::Backup>) -> Result<()> {
214 let backup_finish = match self.fns.backup_finish {
215 Some(backup_finish) => backup_finish,
216 None => return Err(Error::feature_unavailable("backup_finish not available")),
217 };
218 let rc = backup_finish(backup.as_ptr());
219 if rc == SQLITE_OK {
220 Ok(())
221 } else {
222 Err(self.error_from_rc(rc, None))
223 }
224 }
225}
226
227#[allow(unsafe_op_in_unsafe_fn)]
228unsafe impl Sqlite3BlobIo for LibSqlite3 {
229 type Blob = sqlite3_blob;
230
231 unsafe fn blob_open(
232 &self,
233 db: NonNull<Self::Db>,
234 db_name: &str,
235 table: &str,
236 column: &str,
237 rowid: i64,
238 flags: u32,
239 ) -> Result<NonNull<Self::Blob>> {
240 let blob_open = match self.fns.blob_open {
241 Some(blob_open) => blob_open,
242 None => return Err(Error::feature_unavailable("blob_open not available")),
243 };
244 let db_name = CString::new(db_name)
245 .map_err(|_| Error::with_message(ErrorCode::Misuse, "db name contains NUL"))?;
246 let table = CString::new(table)
247 .map_err(|_| Error::with_message(ErrorCode::Misuse, "table contains NUL"))?;
248 let column = CString::new(column)
249 .map_err(|_| Error::with_message(ErrorCode::Misuse, "column contains NUL"))?;
250 let mut blob = null_mut();
251 let rc = blob_open(
252 db.as_ptr(),
253 db_name.as_ptr(),
254 table.as_ptr(),
255 column.as_ptr(),
256 rowid,
257 flags as c_int,
258 &mut blob,
259 );
260 if rc != SQLITE_OK {
261 return Err(self.error_from_rc(rc, Some(db)));
262 }
263 NonNull::new(blob).ok_or_else(|| {
264 Error::with_message(
265 ErrorCode::Error,
266 "sqlite3_blob_open returned success with null blob handle",
267 )
268 })
269 }
270
271 unsafe fn blob_read(
272 &self,
273 blob: NonNull<Self::Blob>,
274 data: &mut [u8],
275 offset: i32,
276 ) -> Result<()> {
277 if data.len() > i32::MAX as usize {
278 return Err(Error::with_message(
279 ErrorCode::TooBig,
280 "blob read buffer too large",
281 ));
282 }
283 let blob_read = match self.fns.blob_read {
284 Some(blob_read) => blob_read,
285 None => return Err(Error::feature_unavailable("blob_read not available")),
286 };
287 let ptr = if data.is_empty() {
288 null_mut()
289 } else {
290 data.as_mut_ptr() as *mut c_void
291 };
292 let rc = blob_read(blob.as_ptr(), ptr, clamp_len(data.len()), offset);
293 if rc == SQLITE_OK {
294 Ok(())
295 } else {
296 Err(self.error_from_rc(rc, None))
297 }
298 }
299
300 unsafe fn blob_write(&self, blob: NonNull<Self::Blob>, data: &[u8], offset: i32) -> Result<()> {
301 if data.len() > i32::MAX as usize {
302 return Err(Error::with_message(
303 ErrorCode::TooBig,
304 "blob write payload too large",
305 ));
306 }
307 let blob_write = match self.fns.blob_write {
308 Some(blob_write) => blob_write,
309 None => return Err(Error::feature_unavailable("blob_write not available")),
310 };
311 let ptr = if data.is_empty() {
312 null()
313 } else {
314 data.as_ptr() as *const c_void
315 };
316 let rc = blob_write(blob.as_ptr(), ptr, clamp_len(data.len()), offset);
317 if rc == SQLITE_OK {
318 Ok(())
319 } else {
320 Err(self.error_from_rc(rc, None))
321 }
322 }
323
324 unsafe fn blob_bytes(&self, blob: NonNull<Self::Blob>) -> i32 {
325 self.fns.blob_bytes.map(|f| f(blob.as_ptr())).unwrap_or(0)
326 }
327
328 unsafe fn blob_close(&self, blob: NonNull<Self::Blob>) -> Result<()> {
329 let blob_close = match self.fns.blob_close {
330 Some(blob_close) => blob_close,
331 None => return Err(Error::feature_unavailable("blob_close not available")),
332 };
333 let rc = blob_close(blob.as_ptr());
334 if rc == SQLITE_OK {
335 Ok(())
336 } else {
337 Err(self.error_from_rc(rc, None))
338 }
339 }
340}
341
342#[allow(unsafe_op_in_unsafe_fn)]
343unsafe impl Sqlite3Serialize for LibSqlite3 {
344 unsafe fn serialize(
345 &self,
346 db: NonNull<Self::Db>,
347 schema: Option<&str>,
348 flags: u32,
349 ) -> Result<OwnedBytes> {
350 let serialize = match self.fns.serialize {
351 Some(serialize) => serialize,
352 None => return Err(Error::feature_unavailable("serialize not available")),
353 };
354 let schema = match schema {
355 Some(schema) => Some(
356 CString::new(schema)
357 .map_err(|_| Error::with_message(ErrorCode::Misuse, "schema contains NUL"))?,
358 ),
359 None => None,
360 };
361 let mut len: i64 = 0;
362 let ptr = serialize(
363 db.as_ptr(),
364 schema.as_ref().map(|s| s.as_ptr()).unwrap_or(null()),
365 &mut len,
366 flags,
367 );
368 if ptr.is_null() {
369 if len == 0 {
370 let empty_ptr = (self.fns.malloc)(1);
371 let empty_ptr = NonNull::new(empty_ptr as *mut u8)
372 .ok_or_else(|| Error::new(ErrorCode::NoMem))?;
373 return Ok(OwnedBytes {
374 ptr: empty_ptr,
375 len: 0,
376 });
377 }
378 let rc = (self.fns.errcode)(db.as_ptr());
379 return Err(self.error_from_rc(rc, Some(db)));
380 }
381 let len = usize::try_from(len).map_err(|_| {
382 unsafe { (self.fns.free)(ptr as *mut c_void) };
383 Error::with_message(ErrorCode::TooBig, "serialized payload length out of range")
384 })?;
385 Ok(OwnedBytes {
386 ptr: NonNull::new_unchecked(ptr),
387 len,
388 })
389 }
390
391 unsafe fn deserialize(
392 &self,
393 db: NonNull<Self::Db>,
394 schema: Option<&str>,
395 data: &[u8],
396 flags: u32,
397 ) -> Result<()> {
398 let deserialize = match self.fns.deserialize {
399 Some(deserialize) => deserialize,
400 None => return Err(Error::feature_unavailable("deserialize not available")),
401 };
402 if data.len() > i32::MAX as usize {
403 return Err(Error::with_message(
404 ErrorCode::TooBig,
405 "deserialize payload too large",
406 ));
407 }
408 let schema = match schema {
409 Some(schema) => Some(
410 CString::new(schema)
411 .map_err(|_| Error::with_message(ErrorCode::Misuse, "schema contains NUL"))?,
412 ),
413 None => None,
414 };
415 let mut owned = null_mut::<c_uchar>();
416 if !data.is_empty() {
417 owned = (self.fns.malloc)(data.len() as c_int) as *mut c_uchar;
418 if owned.is_null() {
419 return Err(Error::new(ErrorCode::NoMem));
420 }
421 std::ptr::copy_nonoverlapping(data.as_ptr(), owned, data.len());
422 }
423 let mut deserialize_flags = flags;
424 if !owned.is_null() {
425 deserialize_flags |= SQLITE_DESERIALIZE_FREEONCLOSE;
426 }
427 let len = i64::try_from(data.len())
428 .map_err(|_| Error::with_message(ErrorCode::TooBig, "deserialize payload too large"))?;
429 let rc = deserialize(
430 db.as_ptr(),
431 schema.as_ref().map(|s| s.as_ptr()).unwrap_or(null()),
432 owned,
433 len,
434 len,
435 deserialize_flags,
436 );
437 if rc == SQLITE_OK {
438 Ok(())
439 } else {
440 if !owned.is_null() {
441 (self.fns.free)(owned as *mut c_void);
442 }
443 Err(self.error_from_rc(rc, Some(db)))
444 }
445 }
446
447 unsafe fn free(&self, bytes: OwnedBytes) {
448 (self.fns.free)(bytes.ptr.as_ptr() as *mut c_void);
449 }
450}
451
452#[allow(unsafe_op_in_unsafe_fn)]
453unsafe impl Sqlite3Wal for LibSqlite3 {
454 unsafe fn wal_checkpoint(&self, db: NonNull<Self::Db>, db_name: Option<&str>) -> Result<()> {
455 let wal_checkpoint = match self.fns.wal_checkpoint {
456 Some(wal_checkpoint) => wal_checkpoint,
457 None => return Err(Error::feature_unavailable("wal_checkpoint not available")),
458 };
459 let db_name = match db_name {
460 Some(db_name) => Some(
461 CString::new(db_name)
462 .map_err(|_| Error::with_message(ErrorCode::Misuse, "db name contains NUL"))?,
463 ),
464 None => None,
465 };
466 let rc = wal_checkpoint(
467 db.as_ptr(),
468 db_name.as_ref().map(|s| s.as_ptr()).unwrap_or(null()),
469 );
470 if rc == SQLITE_OK {
471 Ok(())
472 } else {
473 Err(self.error_from_rc(rc, Some(db)))
474 }
475 }
476
477 unsafe fn wal_checkpoint_v2(
478 &self,
479 db: NonNull<Self::Db>,
480 db_name: Option<&str>,
481 mode: i32,
482 ) -> Result<(i32, i32)> {
483 let wal_checkpoint_v2 = match self.fns.wal_checkpoint_v2 {
484 Some(wal_checkpoint_v2) => wal_checkpoint_v2,
485 None => {
486 return Err(Error::feature_unavailable(
487 "wal_checkpoint_v2 not available",
488 ));
489 }
490 };
491 let db_name = match db_name {
492 Some(db_name) => Some(
493 CString::new(db_name)
494 .map_err(|_| Error::with_message(ErrorCode::Misuse, "db name contains NUL"))?,
495 ),
496 None => None,
497 };
498 let mut log = 0;
499 let mut checkpointed = 0;
500 let rc = wal_checkpoint_v2(
501 db.as_ptr(),
502 db_name.as_ref().map(|s| s.as_ptr()).unwrap_or(null()),
503 mode,
504 &mut log,
505 &mut checkpointed,
506 );
507 if rc == SQLITE_OK {
508 Ok((log, checkpointed))
509 } else {
510 Err(self.error_from_rc(rc, Some(db)))
511 }
512 }
513
514 unsafe fn wal_frame_count(&self, db: NonNull<Self::Db>) -> Result<Option<u32>> {
515 let wal_frame_count = match self.fns.libsql_wal_frame_count {
516 Some(wal_frame_count) => wal_frame_count,
517 None => return Ok(None),
518 };
519 let mut count = 0_u32;
520 let rc = wal_frame_count(db.as_ptr(), &mut count);
521 if rc == SQLITE_OK {
522 Ok(Some(count))
523 } else {
524 Err(self.error_from_rc(rc, Some(db)))
525 }
526 }
527}