1#![allow(unsafe_code)] #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3extern crate libsqlite3_sys as ffi;
4
5#[cfg(all(target_family = "wasm", target_os = "unknown"))]
6use sqlite_wasm_rs as ffi;
7
8use super::functions::{build_sql_function_args, process_sql_function_result};
9use super::limits::SqliteLimit;
10use super::serialized_database::SerializedDatabase;
11use super::stmt::ensure_sqlite_ok;
12use super::{CommitDecision, ProgressDecision};
13use super::{Sqlite, SqliteAggregateFunction};
14use crate::deserialize::FromSqlRow;
15use crate::result::Error::DatabaseError;
16use crate::result::*;
17use crate::serialize::ToSql;
18use crate::sql_types::HasSqlType;
19use crate::sqlite::SqliteFunctionBehavior;
20use alloc::borrow::ToOwned;
21use alloc::boxed::Box;
22use alloc::ffi::{CString, NulError};
23use alloc::string::{String, ToString};
24use core::ffi as libc;
25use core::num::NonZeroU32;
26use core::ptr::NonNull;
27use core::{mem, ptr, slice, str};
28
29pub(super) const SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE: i32 = 1020;
36pub(super) const SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE: i32 = 1021;
37
38macro_rules! assert_fail {
41 ($fmt:expr_2021 $(,$args:tt)*) => {
42 #[cfg(feature = "std")]
43 eprint!(concat!(
44 $fmt,
45 "If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\n",
46 "Source location: {}:{}\n",
47 ), $($args,)* file!(), line!());
48 crate::util::std_compat::abort()
49 };
50}
51
52#[allow(missing_debug_implementations, missing_copy_implementations)]
53pub(super) struct RawConnection {
54 pub(super) internal_connection: NonNull<ffi::sqlite3>,
55 commit_hook: Option<Box<dyn FnMut() -> CommitDecision + Send>>,
57 rollback_hook: Option<Box<dyn FnMut() + Send>>,
59 progress_hook: Option<Box<dyn FnMut() -> ProgressDecision + Send>>,
61}
62
63impl RawConnection {
64 pub(super) fn from_ptr(conn: NonNull<ffi::sqlite3>) -> Self {
67 RawConnection {
68 internal_connection: conn,
69 commit_hook: None,
70 rollback_hook: None,
71 progress_hook: None,
72 }
73 }
74
75 pub(super) fn establish(database_url: &str) -> ConnectionResult<Self> {
76 let mut conn_pointer = ptr::null_mut();
77
78 let database_url = if database_url.starts_with("sqlite://") {
79 CString::new(database_url.replacen("sqlite://", "file:", 1))?
80 } else {
81 CString::new(database_url)?
82 };
83 let flags = ffi::SQLITE_OPEN_READWRITE | ffi::SQLITE_OPEN_CREATE | ffi::SQLITE_OPEN_URI;
84 let connection_status = unsafe {
85 ffi::sqlite3_open_v2(database_url.as_ptr(), &mut conn_pointer, flags, ptr::null())
86 };
87
88 match connection_status {
89 ffi::SQLITE_OK => {
90 let conn_pointer = unsafe { NonNull::new_unchecked(conn_pointer) };
91 Ok(RawConnection {
92 internal_connection: conn_pointer,
93 commit_hook: None,
94 rollback_hook: None,
95 progress_hook: None,
96 })
97 }
98 err_code => {
99 let message = super::error_message(err_code);
100 unsafe { ffi::sqlite3_close(conn_pointer) };
106 Err(ConnectionError::BadConnection(message.into()))
107 }
108 }
109 }
110
111 pub(super) fn exec(&self, query: &str) -> QueryResult<()> {
112 let query = CString::new(query)?;
113 let callback_fn = None;
114 let callback_arg = ptr::null_mut();
115 let result = unsafe {
116 ffi::sqlite3_exec(
117 self.internal_connection.as_ptr(),
118 query.as_ptr(),
119 callback_fn,
120 callback_arg,
121 ptr::null_mut(),
122 )
123 };
124
125 ensure_sqlite_ok(result, self.internal_connection.as_ptr())
126 }
127
128 pub(super) fn rows_affected_by_last_query(
129 &self,
130 ) -> Result<usize, Box<dyn core::error::Error + Send + Sync>> {
131 let r = unsafe { ffi::sqlite3_changes(self.internal_connection.as_ptr()) };
132
133 Ok(r.try_into()?)
134 }
135
136 pub(super) fn last_insert_rowid(&self) -> i64 {
137 unsafe { ffi::sqlite3_last_insert_rowid(self.internal_connection.as_ptr()) }
138 }
139
140 pub(super) fn register_sql_function<F, Ret, RetSqlType>(
141 &self,
142 fn_name: &str,
143 num_args: usize,
144 behavior: SqliteFunctionBehavior,
145 f: F,
146 ) -> QueryResult<()>
147 where
148 F: FnMut(&Self, &mut [*mut ffi::sqlite3_value]) -> QueryResult<Ret>
149 + core::panic::UnwindSafe
150 + Send
151 + 'static,
152 Ret: ToSql<RetSqlType, Sqlite>,
153 Sqlite: HasSqlType<RetSqlType>,
154 {
155 let c_fn_name = Self::get_fn_name(fn_name)?;
156 let flags = behavior.to_flags();
157 let num_args = num_args
158 .try_into()
159 .map_err(|e| Error::SerializationError(Box::new(e)))?;
160 let callback_fn = Box::into_raw(Box::new(CustomFunctionUserPtr {
163 callback: f,
164 function_name: fn_name.to_owned(),
165 }));
166
167 let result = unsafe {
168 ffi::sqlite3_create_function_v2(
169 self.internal_connection.as_ptr(),
170 c_fn_name.as_ptr(),
171 num_args,
172 flags,
173 callback_fn as *mut _,
174 Some(run_custom_function::<F, Ret, RetSqlType>),
175 None,
176 None,
177 Some(destroy_boxed::<CustomFunctionUserPtr<F>>),
178 )
179 };
180
181 Self::process_sql_function_result(result)
182 }
183
184 pub(super) fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
185 &self,
186 fn_name: &str,
187 num_args: usize,
188 behavior: SqliteFunctionBehavior,
189 ) -> QueryResult<()>
190 where
191 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
192 Args: FromSqlRow<ArgsSqlType, Sqlite>,
193 Ret: ToSql<RetSqlType, Sqlite>,
194 Sqlite: HasSqlType<RetSqlType>,
195 {
196 let fn_name = Self::get_fn_name(fn_name)?;
197 let flags = behavior.to_flags();
198 let num_args = num_args
199 .try_into()
200 .map_err(|e| Error::SerializationError(Box::new(e)))?;
201
202 let result = unsafe {
203 ffi::sqlite3_create_function_v2(
204 self.internal_connection.as_ptr(),
205 fn_name.as_ptr(),
206 num_args,
207 flags,
208 core::ptr::null_mut(),
209 None,
210 Some(run_aggregator_step_function::<_, _, _, _, A>),
211 Some(run_aggregator_final_function::<_, _, _, _, A>),
212 None,
213 )
214 };
215
216 Self::process_sql_function_result(result)
217 }
218
219 pub(super) fn register_collation_function<F>(
220 &self,
221 collation_name: &str,
222 collation: F,
223 ) -> QueryResult<()>
224 where
225 F: Fn(&str, &str) -> core::cmp::Ordering + core::panic::UnwindSafe + Send + 'static,
226 {
227 let c_collation_name = Self::get_fn_name(collation_name)?;
228 let callback_fn = Box::into_raw(Box::new(CollationUserPtr {
230 callback: collation,
231 collation_name: collation_name.to_owned(),
232 }));
233
234 let result = unsafe {
235 ffi::sqlite3_create_collation_v2(
236 self.internal_connection.as_ptr(),
237 c_collation_name.as_ptr(),
238 ffi::SQLITE_UTF8,
239 callback_fn as *mut _,
240 Some(run_collation_function::<F>),
241 Some(destroy_boxed::<CollationUserPtr<F>>),
242 )
243 };
244
245 let result = Self::process_sql_function_result(result);
246 if result.is_err() {
247 destroy_boxed::<CollationUserPtr<F>>(callback_fn as *mut _);
248 }
249 result
250 }
251
252 pub(super) fn serialize(&mut self) -> SerializedDatabase {
253 unsafe {
254 let mut size: ffi::sqlite3_int64 = 0;
255 let data_ptr = ffi::sqlite3_serialize(
256 self.internal_connection.as_ptr(),
257 core::ptr::null(),
258 &mut size as *mut _,
259 0,
260 );
261 SerializedDatabase::new(
262 data_ptr,
263 size.try_into()
264 .expect("Cannot fit the serialized database into memory"),
265 )
266 }
267 }
268
269 pub(super) unsafe fn deserialize(&mut self, data: &[u8]) -> QueryResult<()> {
274 let db_size = data
275 .len()
276 .try_into()
277 .map_err(|e| Error::DeserializationError(Box::new(e)))?;
278 #[allow(clippy::unnecessary_cast)]
280 unsafe {
281 let result = ffi::sqlite3_deserialize(
282 self.internal_connection.as_ptr(),
283 core::ptr::null(),
284 data.as_ptr() as *mut u8,
285 db_size,
286 db_size,
287 ffi::SQLITE_DESERIALIZE_READONLY as u32,
288 );
289
290 ensure_sqlite_ok(result, self.internal_connection.as_ptr())
291 }
292 }
293
294 pub(super) fn set_limit(&self, limit: SqliteLimit, value: i32) -> i32 {
295 unsafe { ffi::sqlite3_limit(self.internal_connection.as_ptr(), limit.to_ffi(), value) }
296 }
297
298 pub(super) fn get_limit(&self, limit: SqliteLimit) -> i32 {
299 unsafe {
300 ffi::sqlite3_limit(self.internal_connection.as_ptr(), limit.to_ffi(), -1)
302 }
303 }
304
305 pub(super) fn set_db_config_bool(&self, op: i32, value: bool) -> QueryResult<()> {
307 let mut result_value: libc::c_int = 0;
308 let new_value: libc::c_int = if value { 1 } else { 0 };
309
310 let result = unsafe {
311 ffi::sqlite3_db_config(
312 self.internal_connection.as_ptr(),
313 op,
314 new_value,
315 &mut result_value as *mut libc::c_int,
316 )
317 };
318
319 ensure_sqlite_ok(result, self.internal_connection.as_ptr())
320 }
321
322 pub(super) fn get_db_config_bool(&self, op: i32) -> QueryResult<bool> {
324 let mut current_value: libc::c_int = 0;
325
326 let result = unsafe {
327 ffi::sqlite3_db_config(
328 self.internal_connection.as_ptr(),
329 op,
330 -1_i32, &mut current_value as *mut libc::c_int,
332 )
333 };
334
335 ensure_sqlite_ok(result, self.internal_connection.as_ptr())?;
336 Ok(current_value != 0)
337 }
338
339 fn get_fn_name(fn_name: &str) -> Result<CString, NulError> {
340 CString::new(fn_name)
341 }
342
343 fn process_sql_function_result(result: i32) -> Result<(), Error> {
344 if result == ffi::SQLITE_OK {
345 Ok(())
346 } else {
347 let error_message = super::error_message(result);
348 Err(DatabaseError(
349 DatabaseErrorKind::Unknown,
350 Box::new(error_message.to_string()),
351 ))
352 }
353 }
354
355 pub(super) fn blob_open<'conn>(
356 &'conn self,
357 database_name: &str,
358 table_name: &str,
359 column_name: &str,
360 row_id: i64,
361 ) -> Result<super::sqlite_blob::SqliteReadOnlyBlob<'conn>, Error> {
362 let database_name = alloc::ffi::CString::new(database_name)?;
363 let column_name = alloc::ffi::CString::new(column_name)?;
364 let table_name = alloc::ffi::CString::new(table_name)?;
365
366 let mut blob: *mut ffi::sqlite3_blob = core::ptr::null_mut();
367
368 let ret = unsafe {
370 ffi::sqlite3_blob_open(
371 self.internal_connection.as_ptr(),
372 database_name.as_c_str().as_ptr(),
373 table_name.as_c_str().as_ptr(),
374 column_name.as_c_str().as_ptr(),
375 row_id,
376 0,
377 &mut blob,
378 )
379 };
380
381 Self::process_sql_function_result(ret)?;
382
383 let blob = unsafe { core::ptr::NonNull::new_unchecked(blob) };
391
392 let blob_size = unsafe { ffi::sqlite3_blob_bytes(blob.as_ptr()) };
394 let blob_size = usize::try_from(blob_size).map_err(Error::IntegerConversion)?;
395
396 Ok(super::sqlite_blob::SqliteReadOnlyBlob {
397 blob,
398 read_index: 0,
399 blob_size,
400 _pd: core::marker::PhantomData,
401 })
402 }
403
404 pub(super) fn set_commit_hook<F>(&mut self, hook: F)
414 where
415 F: FnMut() -> CommitDecision + Send + 'static,
416 {
417 let mut boxed: Box<dyn FnMut() -> CommitDecision + Send> = Box::new(hook);
418 let ptr = &raw mut *boxed as *mut libc::c_void;
419
420 unsafe {
421 ffi::sqlite3_commit_hook(
422 self.internal_connection.as_ptr(),
423 Some(commit_hook_trampoline::<F>),
424 ptr,
425 );
426 }
427
428 self.commit_hook = Some(boxed);
431 }
432
433 pub(super) fn remove_commit_hook(&mut self) {
443 unsafe {
444 ffi::sqlite3_commit_hook(self.internal_connection.as_ptr(), None, ptr::null_mut());
445 }
446 self.commit_hook = None;
447 }
448
449 pub(super) fn set_rollback_hook<F>(&mut self, hook: F)
459 where
460 F: FnMut() + Send + 'static,
461 {
462 let mut boxed: Box<dyn FnMut() + Send> = Box::new(hook);
463 let ptr = &raw mut *boxed as *mut libc::c_void;
464
465 unsafe {
466 ffi::sqlite3_rollback_hook(
467 self.internal_connection.as_ptr(),
468 Some(rollback_hook_trampoline::<F>),
469 ptr,
470 );
471 }
472
473 self.rollback_hook = Some(boxed);
476 }
477
478 pub(super) fn remove_rollback_hook(&mut self) {
488 unsafe {
489 ffi::sqlite3_rollback_hook(self.internal_connection.as_ptr(), None, ptr::null_mut());
490 }
491 self.rollback_hook = None;
492 }
493
494 pub(super) fn set_progress_handler<F>(&mut self, n: NonZeroU32, hook: F)
506 where
507 F: FnMut() -> ProgressDecision + Send + 'static,
508 {
509 let mut boxed: Box<dyn FnMut() -> ProgressDecision + Send> = Box::new(hook);
510 let ptr = &raw mut *boxed as *mut libc::c_void;
511
512 let n = i32::try_from(n.get()).unwrap_or(i32::MAX);
516
517 unsafe {
518 ffi::sqlite3_progress_handler(
519 self.internal_connection.as_ptr(),
520 n,
521 Some(progress_handler_trampoline::<F>),
522 ptr,
523 );
524 }
525
526 self.progress_hook = Some(boxed);
529 }
530
531 pub(super) fn remove_progress_handler(&mut self) {
541 unsafe {
542 ffi::sqlite3_progress_handler(
543 self.internal_connection.as_ptr(),
544 0,
545 None,
546 ptr::null_mut(),
547 );
548 }
549 self.progress_hook = None;
550 }
551}
552
553impl Drop for RawConnection {
554 fn drop(&mut self) {
555 use crate::util::std_compat::panicking;
556
557 self.remove_commit_hook();
559 self.remove_rollback_hook();
560 self.remove_progress_handler();
561
562 let close_result = unsafe { ffi::sqlite3_close(self.internal_connection.as_ptr()) };
563 if close_result != ffi::SQLITE_OK {
564 let error_message = super::error_message(close_result);
565 if panicking() {
566 #[cfg(feature = "std")]
567 {
::std::io::_eprint(format_args!("Error closing SQLite connection: {0}\n",
error_message));
};eprintln!("Error closing SQLite connection: {error_message}");
568 } else {
569 {
::core::panicking::panic_fmt(format_args!("Error closing SQLite connection: {0}",
error_message));
};panic!("Error closing SQLite connection: {error_message}");
570 }
571 }
572 }
573}
574
575enum SqliteCallbackError {
576 Abort(&'static str),
577 DieselError(crate::result::Error),
578 Panic(String),
579}
580
581impl SqliteCallbackError {
582 fn emit(&self, ctx: *mut ffi::sqlite3_context) {
583 let s;
584 let msg = match self {
585 SqliteCallbackError::Abort(msg) => *msg,
586 SqliteCallbackError::DieselError(e) => {
587 s = e.to_string();
588 &s
589 }
590 SqliteCallbackError::Panic(msg) => msg,
591 };
592 unsafe {
593 context_error_str(ctx, msg);
594 }
595 }
596}
597
598impl From<crate::result::Error> for SqliteCallbackError {
599 fn from(e: crate::result::Error) -> Self {
600 Self::DieselError(e)
601 }
602}
603
604struct CustomFunctionUserPtr<F> {
605 callback: F,
606 function_name: String,
607}
608
609#[allow(warnings)]
610extern "C" fn run_custom_function<F, Ret, RetSqlType>(
611 ctx: *mut ffi::sqlite3_context,
612 num_args: libc::c_int,
613 value_ptr: *mut *mut ffi::sqlite3_value,
614) where
615 F: FnMut(&RawConnection, &mut [*mut ffi::sqlite3_value]) -> QueryResult<Ret>
616 + core::panic::UnwindSafe
617 + Send
618 + 'static,
619 Ret: ToSql<RetSqlType, Sqlite>,
620 Sqlite: HasSqlType<RetSqlType>,
621{
622 use core::ops::Deref;
623 static NULL_DATA_ERR: &str = "An unknown error occurred. sqlite3_user_data returned a null pointer. This should never happen.";
624 static NULL_CONN_ERR: &str = "An unknown error occurred. sqlite3_context_db_handle returned a null pointer. This should never happen.";
625
626 let conn = match unsafe { NonNull::new(ffi::sqlite3_context_db_handle(ctx)) } {
627 Some(conn) => mem::ManuallyDrop::new(RawConnection::from_ptr(conn)),
630 None => {
631 unsafe { context_error_str(ctx, NULL_CONN_ERR) };
632 return;
633 }
634 };
635
636 let data_ptr = unsafe { ffi::sqlite3_user_data(ctx) };
637
638 let mut data_ptr = match NonNull::new(data_ptr as *mut CustomFunctionUserPtr<F>) {
639 None => unsafe {
640 context_error_str(ctx, NULL_DATA_ERR);
641 return;
642 },
643 Some(mut f) => f,
644 };
645 let data_ptr = unsafe { data_ptr.as_mut() };
646
647 let callback = core::panic::AssertUnwindSafe(&mut data_ptr.callback);
650 let conn = core::panic::AssertUnwindSafe(conn);
653
654 let result = crate::util::std_compat::catch_unwind(move || {
655 let _ = &callback;
656 let args = unsafe { slice::from_raw_parts_mut(value_ptr, num_args as _) };
657 let res = (callback.0)(&*conn, args)?;
658 let value = process_sql_function_result(&res)?;
659 unsafe {
661 value.result_of(&mut *ctx);
662 }
663 Ok(())
664 })
665 .unwrap_or_else(|p| Err(SqliteCallbackError::Panic(data_ptr.function_name.clone())));
666 if let Err(e) = result {
667 e.emit(ctx);
668 }
669}
670
671#[allow(warnings)]
672extern "C" fn run_aggregator_step_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
673 ctx: *mut ffi::sqlite3_context,
674 num_args: libc::c_int,
675 value_ptr: *mut *mut ffi::sqlite3_value,
676) where
677 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
678 Args: FromSqlRow<ArgsSqlType, Sqlite>,
679 Ret: ToSql<RetSqlType, Sqlite>,
680 Sqlite: HasSqlType<RetSqlType>,
681{
682 let result = crate::util::std_compat::catch_unwind(move || {
683 let args = unsafe { slice::from_raw_parts_mut(value_ptr, num_args as _) };
684 run_aggregator_step::<A, Args, ArgsSqlType>(ctx, args)
685 })
686 .unwrap_or_else(|e| {
687 Err(SqliteCallbackError::Panic(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::step() panicked",
core::any::type_name::<A>()))
})alloc::format!(
688 "{}::step() panicked",
689 core::any::type_name::<A>()
690 )))
691 });
692
693 match result {
694 Ok(()) => {}
695 Err(e) => e.emit(ctx),
696 }
697}
698
699fn run_aggregator_step<A, Args, ArgsSqlType>(
700 ctx: *mut ffi::sqlite3_context,
701 args: &mut [*mut ffi::sqlite3_value],
702) -> Result<(), SqliteCallbackError>
703where
704 A: SqliteAggregateFunction<Args>,
705 Args: FromSqlRow<ArgsSqlType, Sqlite>,
706{
707 let aggregator = unsafe {
708 const {
709 if core::mem::size_of::<*mut A>() == 0 {
710 {
::core::panicking::panic_fmt(format_args!("The pointer size is zero, that\'s unexpected.If you ever see this error message open a issuedescribing your environment"));
};panic!(
711 "The pointer size is zero, that's unexpected.\
712 If you ever see this error message open a issue\
713 describing your environment"
714 );
715 }
716 }
717 let ctx = ffi::sqlite3_aggregate_context(
724 ctx,
725 core::mem::size_of::<*mut A>()
726 .try_into()
727 .expect("Memory size of a pointer is smaller than i32::MAX"),
728 )
729 .cast::<*mut A>();
731 let inner = &mut *ctx;
733 if inner.is_null() {
737 let obj = Box::into_raw(Box::new(A::default()));
740 *inner = obj;
741 }
742 &mut **inner
746 };
747
748 let args = build_sql_function_args::<ArgsSqlType, Args>(args)?;
749
750 aggregator.step(args);
751 Ok(())
752}
753
754extern "C" fn run_aggregator_final_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
755 ctx: *mut ffi::sqlite3_context,
756) where
757 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send,
758 Args: FromSqlRow<ArgsSqlType, Sqlite>,
759 Ret: ToSql<RetSqlType, Sqlite>,
760 Sqlite: HasSqlType<RetSqlType>,
761{
762 let result = crate::util::std_compat::catch_unwind(|| {
763 let aggregator = unsafe {
764 let ctx = ffi::sqlite3_aggregate_context(
767 ctx,
768 0,
770 )
771 .cast::<*mut A>();
773 if ctx.is_null() {
777 None
778 } else {
779 let inner = &mut *ctx;
783 if inner.is_null() {
784 None
786 } else {
787 let value = Box::from_raw(*inner);
791 let value = Some(*value);
792 *inner = core::ptr::null_mut();
795 value
796 }
797 }
798 };
799
800 let res = A::finalize(aggregator);
801 let value = process_sql_function_result(&res)?;
802 let r = unsafe { value.result_of(&mut *ctx) };
804 r.map_err(|e| {
805 SqliteCallbackError::DieselError(crate::result::Error::SerializationError(Box::new(e)))
806 })?;
807 Ok(())
808 })
809 .unwrap_or_else(|_e| {
810 Err(SqliteCallbackError::Panic(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::finalize() panicked",
core::any::type_name::<A>()))
})alloc::format!(
811 "{}::finalize() panicked",
812 core::any::type_name::<A>()
813 )))
814 });
815 if let Err(e) = result {
816 e.emit(ctx);
817 }
818}
819
820unsafe fn context_error_str(ctx: *mut ffi::sqlite3_context, error: &str) {
821 let len: i32 = error.len().try_into().unwrap_or(i32::MAX);
822 unsafe {
823 ffi::sqlite3_result_error(ctx, error.as_ptr() as *const _, len);
824 }
825}
826
827struct CollationUserPtr<F> {
828 callback: F,
829 collation_name: String,
830}
831
832#[allow(warnings)]
833extern "C" fn run_collation_function<F>(
834 user_ptr: *mut libc::c_void,
835 lhs_len: libc::c_int,
836 lhs_ptr: *const libc::c_void,
837 rhs_len: libc::c_int,
838 rhs_ptr: *const libc::c_void,
839) -> libc::c_int
840where
841 F: Fn(&str, &str) -> core::cmp::Ordering + Send + core::panic::UnwindSafe + 'static,
842{
843 let user_ptr = user_ptr as *const CollationUserPtr<F>;
844 let user_ptr = core::panic::AssertUnwindSafe(unsafe { user_ptr.as_ref() });
845
846 let result = crate::util::std_compat::catch_unwind(|| {
847 let user_ptr = user_ptr.ok_or_else(|| {
848 SqliteCallbackError::Abort(
849 "Got a null pointer as data pointer. This should never happen",
850 )
851 })?;
852 for (ptr, len, side) in &[(rhs_ptr, rhs_len, "rhs"), (lhs_ptr, lhs_len, "lhs")] {
853 if *len < 0 {
854 {
::std::io::_eprint(format_args!("An unknown error occurred. {0}_len is negative. This should never happen.If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {1}:{2}\n",
side, "diesel/src/sqlite/connection/raw.rs", 854u32));
};
crate::util::std_compat::abort();assert_fail!(
855 "An unknown error occurred. {}_len is negative. This should never happen.",
856 side
857 );
858 }
859 if ptr.is_null() {
860 {
::std::io::_eprint(format_args!("An unknown error occurred. {0}_ptr is a null pointer. This should never happen.If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {1}:{2}\n",
side, "diesel/src/sqlite/connection/raw.rs", 860u32));
};
crate::util::std_compat::abort();assert_fail!(
861 "An unknown error occurred. {}_ptr is a null pointer. This should never happen.",
862 side
863 );
864 }
865 }
866
867 let (rhs, lhs) = unsafe {
868 (
872 str::from_utf8(slice::from_raw_parts(rhs_ptr as *const u8, rhs_len as _)),
873 str::from_utf8(slice::from_raw_parts(lhs_ptr as *const u8, lhs_len as _)),
874 )
875 };
876
877 let rhs =
878 rhs.map_err(|_| SqliteCallbackError::Abort("Got an invalid UTF-8 string for rhs"))?;
879 let lhs =
880 lhs.map_err(|_| SqliteCallbackError::Abort("Got an invalid UTF-8 string for lhs"))?;
881
882 Ok((user_ptr.callback)(rhs, lhs))
883 })
884 .unwrap_or_else(|p| {
885 Err(SqliteCallbackError::Panic(
886 user_ptr
887 .map(|u| u.collation_name.clone())
888 .unwrap_or_default(),
889 ))
890 });
891
892 match result {
893 Ok(core::cmp::Ordering::Less) => -1,
894 Ok(core::cmp::Ordering::Equal) => 0,
895 Ok(core::cmp::Ordering::Greater) => 1,
896 Err(SqliteCallbackError::Abort(a)) => {
897 #[cfg(feature = "std")]
898 {
::std::io::_eprint(format_args!("Collation function {0} failed with: {1}\n",
user_ptr.map(|c| &c.collation_name as &str).unwrap_or_default(),
a));
};eprintln!(
899 "Collation function {} failed with: {}",
900 user_ptr
901 .map(|c| &c.collation_name as &str)
902 .unwrap_or_default(),
903 a
904 );
905 crate::util::std_compat::abort()
906 }
907 Err(SqliteCallbackError::DieselError(e)) => {
908 #[cfg(feature = "std")]
909 {
::std::io::_eprint(format_args!("Collation function {0} failed with: {1}\n",
user_ptr.map(|c| &c.collation_name as &str).unwrap_or_default(),
e));
};eprintln!(
910 "Collation function {} failed with: {}",
911 user_ptr
912 .map(|c| &c.collation_name as &str)
913 .unwrap_or_default(),
914 e
915 );
916 crate::util::std_compat::abort()
917 }
918 Err(SqliteCallbackError::Panic(msg)) => {
919 #[cfg(feature = "std")]
920 {
::std::io::_eprint(format_args!("Collation function {0} panicked\n",
msg));
};eprintln!("Collation function {} panicked", msg);
921 crate::util::std_compat::abort()
922 }
923 }
924}
925
926extern "C" fn destroy_boxed<F>(data: *mut libc::c_void) {
927 let ptr = data as *mut F;
928 unsafe { core::mem::drop(Box::from_raw(ptr)) };
929}
930
931unsafe extern "C" fn commit_hook_trampoline<F>(user_data: *mut libc::c_void) -> libc::c_int
937where
938 F: FnMut() -> CommitDecision,
939{
940 let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
941 let f = unsafe { &mut *(user_data as *mut F) };
943 f()
944 }));
945
946 match result {
947 Ok(CommitDecision::Rollback) => 1,
948 Ok(CommitDecision::Proceed) => 0,
949 Err(_) => {
950 {
::std::io::_eprint(format_args!("Panic in sqlite3_commit_hook trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
"diesel/src/sqlite/connection/raw.rs", 950u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_commit_hook trampoline. ");
951 }
952 }
953}
954
955unsafe extern "C" fn rollback_hook_trampoline<F>(user_data: *mut libc::c_void)
961where
962 F: FnMut(),
963{
964 let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
965 let f = unsafe { &mut *(user_data as *mut F) };
967 f();
968 }));
969
970 if result.is_err() {
971 {
::std::io::_eprint(format_args!("Panic in sqlite3_rollback_hook trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
"diesel/src/sqlite/connection/raw.rs", 971u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_rollback_hook trampoline. ");
972 }
973}
974
975unsafe extern "C" fn progress_handler_trampoline<F>(user_data: *mut libc::c_void) -> libc::c_int
981where
982 F: FnMut() -> ProgressDecision,
983{
984 let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
985 let f = unsafe { &mut *(user_data as *mut F) };
987 f()
988 }));
989
990 match result {
991 Ok(ProgressDecision::Interrupt) => 1,
992 Ok(ProgressDecision::Continue) => 0,
993 Err(_) => {
994 {
::std::io::_eprint(format_args!("Panic in sqlite3_progress_handler trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
"diesel/src/sqlite/connection/raw.rs", 994u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_progress_handler trampoline. ");
995 }
996 }
997}