Skip to main content

diesel/sqlite/connection/
raw.rs

1#![allow(unsafe_code)] // ffi calls
2#[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::serialized_database::SerializedDatabase;
10use super::stmt::ensure_sqlite_ok;
11use super::{Sqlite, SqliteAggregateFunction};
12use crate::deserialize::FromSqlRow;
13use crate::result::Error::DatabaseError;
14use crate::result::*;
15use crate::serialize::ToSql;
16use crate::sql_types::HasSqlType;
17use alloc::borrow::ToOwned;
18use alloc::boxed::Box;
19use alloc::ffi::{CString, NulError};
20use alloc::string::{String, ToString};
21use core::ffi as libc;
22use core::ptr::NonNull;
23use core::{mem, ptr, slice, str};
24
25/// For use in FFI function, which cannot unwind.
26/// Print the message, ask to open an issue at Github and [`abort`](std::process::abort).
27macro_rules! assert_fail {
28    ($fmt:expr_2021 $(,$args:tt)*) => {
29        #[cfg(feature = "std")]
30        eprint!(concat!(
31            $fmt,
32            "If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\n",
33            "Source location: {}:{}\n",
34        ), $($args,)* file!(), line!());
35        crate::util::std_compat::abort()
36    };
37}
38
39#[allow(missing_debug_implementations, missing_copy_implementations)]
40pub(super) struct RawConnection {
41    pub(super) internal_connection: NonNull<ffi::sqlite3>,
42}
43
44impl RawConnection {
45    pub(super) fn establish(database_url: &str) -> ConnectionResult<Self> {
46        let mut conn_pointer = ptr::null_mut();
47
48        let database_url = if database_url.starts_with("sqlite://") {
49            CString::new(database_url.replacen("sqlite://", "file:", 1))?
50        } else {
51            CString::new(database_url)?
52        };
53        let flags = ffi::SQLITE_OPEN_READWRITE | ffi::SQLITE_OPEN_CREATE | ffi::SQLITE_OPEN_URI;
54        let connection_status = unsafe {
55            ffi::sqlite3_open_v2(database_url.as_ptr(), &mut conn_pointer, flags, ptr::null())
56        };
57
58        match connection_status {
59            ffi::SQLITE_OK => {
60                let conn_pointer = unsafe { NonNull::new_unchecked(conn_pointer) };
61                Ok(RawConnection {
62                    internal_connection: conn_pointer,
63                })
64            }
65            err_code => {
66                let message = super::error_message(err_code);
67                Err(ConnectionError::BadConnection(message.into()))
68            }
69        }
70    }
71
72    pub(super) fn exec(&self, query: &str) -> QueryResult<()> {
73        let query = CString::new(query)?;
74        let callback_fn = None;
75        let callback_arg = ptr::null_mut();
76        let result = unsafe {
77            ffi::sqlite3_exec(
78                self.internal_connection.as_ptr(),
79                query.as_ptr(),
80                callback_fn,
81                callback_arg,
82                ptr::null_mut(),
83            )
84        };
85
86        ensure_sqlite_ok(result, self.internal_connection.as_ptr())
87    }
88
89    pub(super) fn rows_affected_by_last_query(
90        &self,
91    ) -> Result<usize, Box<dyn core::error::Error + Send + Sync>> {
92        let r = unsafe { ffi::sqlite3_changes(self.internal_connection.as_ptr()) };
93
94        Ok(r.try_into()?)
95    }
96
97    pub(super) fn register_sql_function<F, Ret, RetSqlType>(
98        &self,
99        fn_name: &str,
100        num_args: usize,
101        deterministic: bool,
102        f: F,
103    ) -> QueryResult<()>
104    where
105        F: FnMut(&Self, &mut [*mut ffi::sqlite3_value]) -> QueryResult<Ret>
106            + core::panic::UnwindSafe
107            + Send
108            + 'static,
109        Ret: ToSql<RetSqlType, Sqlite>,
110        Sqlite: HasSqlType<RetSqlType>,
111    {
112        let callback_fn = Box::into_raw(Box::new(CustomFunctionUserPtr {
113            callback: f,
114            function_name: fn_name.to_owned(),
115        }));
116        let fn_name = Self::get_fn_name(fn_name)?;
117        let flags = Self::get_flags(deterministic);
118        let num_args = num_args
119            .try_into()
120            .map_err(|e| Error::SerializationError(Box::new(e)))?;
121
122        let result = unsafe {
123            ffi::sqlite3_create_function_v2(
124                self.internal_connection.as_ptr(),
125                fn_name.as_ptr(),
126                num_args,
127                flags,
128                callback_fn as *mut _,
129                Some(run_custom_function::<F, Ret, RetSqlType>),
130                None,
131                None,
132                Some(destroy_boxed::<CustomFunctionUserPtr<F>>),
133            )
134        };
135
136        Self::process_sql_function_result(result)
137    }
138
139    pub(super) fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
140        &self,
141        fn_name: &str,
142        num_args: usize,
143    ) -> QueryResult<()>
144    where
145        A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
146        Args: FromSqlRow<ArgsSqlType, Sqlite>,
147        Ret: ToSql<RetSqlType, Sqlite>,
148        Sqlite: HasSqlType<RetSqlType>,
149    {
150        let fn_name = Self::get_fn_name(fn_name)?;
151        let flags = Self::get_flags(false);
152        let num_args = num_args
153            .try_into()
154            .map_err(|e| Error::SerializationError(Box::new(e)))?;
155
156        let result = unsafe {
157            ffi::sqlite3_create_function_v2(
158                self.internal_connection.as_ptr(),
159                fn_name.as_ptr(),
160                num_args,
161                flags,
162                ptr::null_mut(),
163                None,
164                Some(run_aggregator_step_function::<_, _, _, _, A>),
165                Some(run_aggregator_final_function::<_, _, _, _, A>),
166                None,
167            )
168        };
169
170        Self::process_sql_function_result(result)
171    }
172
173    pub(super) fn register_collation_function<F>(
174        &self,
175        collation_name: &str,
176        collation: F,
177    ) -> QueryResult<()>
178    where
179        F: Fn(&str, &str) -> core::cmp::Ordering + core::panic::UnwindSafe + Send + 'static,
180    {
181        let callback_fn = Box::into_raw(Box::new(CollationUserPtr {
182            callback: collation,
183            collation_name: collation_name.to_owned(),
184        }));
185        let collation_name = Self::get_fn_name(collation_name)?;
186
187        let result = unsafe {
188            ffi::sqlite3_create_collation_v2(
189                self.internal_connection.as_ptr(),
190                collation_name.as_ptr(),
191                ffi::SQLITE_UTF8,
192                callback_fn as *mut _,
193                Some(run_collation_function::<F>),
194                Some(destroy_boxed::<CollationUserPtr<F>>),
195            )
196        };
197
198        let result = Self::process_sql_function_result(result);
199        if result.is_err() {
200            destroy_boxed::<CollationUserPtr<F>>(callback_fn as *mut _);
201        }
202        result
203    }
204
205    pub(super) fn serialize(&mut self) -> SerializedDatabase {
206        unsafe {
207            let mut size: ffi::sqlite3_int64 = 0;
208            let data_ptr = ffi::sqlite3_serialize(
209                self.internal_connection.as_ptr(),
210                core::ptr::null(),
211                &mut size as *mut _,
212                0,
213            );
214            SerializedDatabase::new(
215                data_ptr,
216                size.try_into()
217                    .expect("Cannot fit the serialized database into memory"),
218            )
219        }
220    }
221
222    pub(super) fn deserialize(&mut self, data: &[u8]) -> QueryResult<()> {
223        let db_size = data
224            .len()
225            .try_into()
226            .map_err(|e| Error::DeserializationError(Box::new(e)))?;
227        // the cast for `ffi::SQLITE_DESERIALIZE_READONLY` is required for old libsqlite3-sys versions
228        #[allow(clippy::unnecessary_cast)]
229        unsafe {
230            let result = ffi::sqlite3_deserialize(
231                self.internal_connection.as_ptr(),
232                core::ptr::null(),
233                data.as_ptr() as *mut u8,
234                db_size,
235                db_size,
236                ffi::SQLITE_DESERIALIZE_READONLY as u32,
237            );
238
239            ensure_sqlite_ok(result, self.internal_connection.as_ptr())
240        }
241    }
242
243    fn get_fn_name(fn_name: &str) -> Result<CString, NulError> {
244        CString::new(fn_name)
245    }
246
247    fn get_flags(deterministic: bool) -> i32 {
248        let mut flags = ffi::SQLITE_UTF8;
249        if deterministic {
250            flags |= ffi::SQLITE_DETERMINISTIC;
251        }
252        flags
253    }
254
255    fn process_sql_function_result(result: i32) -> Result<(), Error> {
256        if result == ffi::SQLITE_OK {
257            Ok(())
258        } else {
259            let error_message = super::error_message(result);
260            Err(DatabaseError(
261                DatabaseErrorKind::Unknown,
262                Box::new(error_message.to_string()),
263            ))
264        }
265    }
266}
267
268impl Drop for RawConnection {
269    fn drop(&mut self) {
270        use crate::util::std_compat::panicking;
271
272        let close_result = unsafe { ffi::sqlite3_close(self.internal_connection.as_ptr()) };
273        if close_result != ffi::SQLITE_OK {
274            let error_message = super::error_message(close_result);
275            if panicking() {
276                #[cfg(feature = "std")]
277                {
    ::std::io::_eprint(format_args!("Error closing SQLite connection: {0}\n",
            error_message));
};eprintln!("Error closing SQLite connection: {error_message}");
278            } else {
279                {
    ::core::panicking::panic_fmt(format_args!("Error closing SQLite connection: {0}",
            error_message));
};panic!("Error closing SQLite connection: {error_message}");
280            }
281        }
282    }
283}
284
285enum SqliteCallbackError {
286    Abort(&'static str),
287    DieselError(crate::result::Error),
288    Panic(String),
289}
290
291impl SqliteCallbackError {
292    fn emit(&self, ctx: *mut ffi::sqlite3_context) {
293        let s;
294        let msg = match self {
295            SqliteCallbackError::Abort(msg) => *msg,
296            SqliteCallbackError::DieselError(e) => {
297                s = e.to_string();
298                &s
299            }
300            SqliteCallbackError::Panic(msg) => msg,
301        };
302        unsafe {
303            context_error_str(ctx, msg);
304        }
305    }
306}
307
308impl From<crate::result::Error> for SqliteCallbackError {
309    fn from(e: crate::result::Error) -> Self {
310        Self::DieselError(e)
311    }
312}
313
314struct CustomFunctionUserPtr<F> {
315    callback: F,
316    function_name: String,
317}
318
319#[allow(warnings)]
320extern "C" fn run_custom_function<F, Ret, RetSqlType>(
321    ctx: *mut ffi::sqlite3_context,
322    num_args: libc::c_int,
323    value_ptr: *mut *mut ffi::sqlite3_value,
324) where
325    F: FnMut(&RawConnection, &mut [*mut ffi::sqlite3_value]) -> QueryResult<Ret>
326        + core::panic::UnwindSafe
327        + Send
328        + 'static,
329    Ret: ToSql<RetSqlType, Sqlite>,
330    Sqlite: HasSqlType<RetSqlType>,
331{
332    use core::ops::Deref;
333    static NULL_DATA_ERR: &str = "An unknown error occurred. sqlite3_user_data returned a null pointer. This should never happen.";
334    static NULL_CONN_ERR: &str = "An unknown error occurred. sqlite3_context_db_handle returned a null pointer. This should never happen.";
335
336    let conn = match unsafe { NonNull::new(ffi::sqlite3_context_db_handle(ctx)) } {
337        // We use `ManuallyDrop` here because we do not want to run the
338        // Drop impl of `RawConnection` as this would close the connection
339        Some(conn) => mem::ManuallyDrop::new(RawConnection {
340            internal_connection: conn,
341        }),
342        None => {
343            unsafe { context_error_str(ctx, NULL_CONN_ERR) };
344            return;
345        }
346    };
347
348    let data_ptr = unsafe { ffi::sqlite3_user_data(ctx) };
349
350    let mut data_ptr = match NonNull::new(data_ptr as *mut CustomFunctionUserPtr<F>) {
351        None => unsafe {
352            context_error_str(ctx, NULL_DATA_ERR);
353            return;
354        },
355        Some(mut f) => f,
356    };
357    let data_ptr = unsafe { data_ptr.as_mut() };
358
359    // We need this to move the reference into the catch_unwind part
360    // this is sound as `F` itself and the stored string is `UnwindSafe`
361    let callback = core::panic::AssertUnwindSafe(&mut data_ptr.callback);
362
363    let result = crate::util::std_compat::catch_unwind(move || {
364        let _ = &callback;
365        let args = unsafe { slice::from_raw_parts_mut(value_ptr, num_args as _) };
366        let res = (callback.0)(&*conn, args)?;
367        let value = process_sql_function_result(&res)?;
368        // We've checked already that ctx is not null
369        unsafe {
370            value.result_of(&mut *ctx);
371        }
372        Ok(())
373    })
374    .unwrap_or_else(|p| Err(SqliteCallbackError::Panic(data_ptr.function_name.clone())));
375    if let Err(e) = result {
376        e.emit(ctx);
377    }
378}
379
380// Need a custom option type here, because the std lib one does not have guarantees about the discriminate values
381// See: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md#opaque-tags
382#[repr(u8)]
383enum OptionalAggregator<A> {
384    // Discriminant is 0
385    None,
386    Some(A),
387}
388
389#[allow(warnings)]
390extern "C" fn run_aggregator_step_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
391    ctx: *mut ffi::sqlite3_context,
392    num_args: libc::c_int,
393    value_ptr: *mut *mut ffi::sqlite3_value,
394) where
395    A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
396    Args: FromSqlRow<ArgsSqlType, Sqlite>,
397    Ret: ToSql<RetSqlType, Sqlite>,
398    Sqlite: HasSqlType<RetSqlType>,
399{
400    let result = crate::util::std_compat::catch_unwind(move || {
401        let args = unsafe { slice::from_raw_parts_mut(value_ptr, num_args as _) };
402        run_aggregator_step::<A, Args, ArgsSqlType>(ctx, args)
403    })
404    .unwrap_or_else(|e| {
405        Err(SqliteCallbackError::Panic(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::step() panicked",
                core::any::type_name::<A>()))
    })alloc::format!(
406            "{}::step() panicked",
407            core::any::type_name::<A>()
408        )))
409    });
410
411    match result {
412        Ok(()) => {}
413        Err(e) => e.emit(ctx),
414    }
415}
416
417fn run_aggregator_step<A, Args, ArgsSqlType>(
418    ctx: *mut ffi::sqlite3_context,
419    args: &mut [*mut ffi::sqlite3_value],
420) -> Result<(), SqliteCallbackError>
421where
422    A: SqliteAggregateFunction<Args>,
423    Args: FromSqlRow<ArgsSqlType, Sqlite>,
424{
425    static NULL_AG_CTX_ERR: &str = "An unknown error occurred. sqlite3_aggregate_context returned a null pointer. This should never happen.";
426    static NULL_CTX_ERR: &str =
427        "We've written the aggregator to the aggregate context, but it could not be retrieved.";
428
429    let n_bytes: i32 = core::mem::size_of::<OptionalAggregator<A>>()
430        .try_into()
431        .expect("Aggregate context should be larger than 2^32");
432    let aggregate_context = unsafe {
433        // This block of unsafe code makes the following assumptions:
434        //
435        // * sqlite3_aggregate_context allocates sizeof::<OptionalAggregator<A>>
436        //   bytes of zeroed memory as documented here:
437        //   https://www.sqlite.org/c3ref/aggregate_context.html
438        //   A null pointer is returned for negative or zero sized types,
439        //   which should be impossible in theory. We check that nevertheless
440        //
441        // * OptionalAggregator::None has a discriminant of 0 as specified by
442        //   #[repr(u8)] + RFC 2195
443        //
444        // * If all bytes are zero, the discriminant is also zero, so we can
445        //   assume that we get OptionalAggregator::None in this case. This is
446        //   not UB as we only access the discriminant here, so we do not try
447        //   to read any other zeroed memory. After that we initialize our enum
448        //   by writing a correct value at this location via ptr::write_unaligned
449        //
450        // * We use ptr::write_unaligned as we did not found any guarantees that
451        //   the memory will have a correct alignment.
452        //   (Note I(weiznich): would assume that it is aligned correctly, but we
453        //    we cannot guarantee it, so better be safe than sorry)
454        ffi::sqlite3_aggregate_context(ctx, n_bytes)
455    };
456    let aggregate_context = NonNull::new(aggregate_context as *mut OptionalAggregator<A>);
457    let aggregator = unsafe {
458        match aggregate_context.map(|a| &mut *a.as_ptr()) {
459            Some(&mut OptionalAggregator::Some(ref mut agg)) => agg,
460            Some(a_ptr @ &mut OptionalAggregator::None) => {
461                ptr::write_unaligned(a_ptr as *mut _, OptionalAggregator::Some(A::default()));
462                if let OptionalAggregator::Some(agg) = a_ptr {
463                    agg
464                } else {
465                    return Err(SqliteCallbackError::Abort(NULL_CTX_ERR));
466                }
467            }
468            None => {
469                return Err(SqliteCallbackError::Abort(NULL_AG_CTX_ERR));
470            }
471        }
472    };
473    let args = build_sql_function_args::<ArgsSqlType, Args>(args)?;
474
475    aggregator.step(args);
476    Ok(())
477}
478
479extern "C" fn run_aggregator_final_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
480    ctx: *mut ffi::sqlite3_context,
481) where
482    A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send,
483    Args: FromSqlRow<ArgsSqlType, Sqlite>,
484    Ret: ToSql<RetSqlType, Sqlite>,
485    Sqlite: HasSqlType<RetSqlType>,
486{
487    static NO_AGGREGATOR_FOUND: &str = "We've written to the aggregator in the xStep callback. If xStep was never called, then ffi::sqlite_aggregate_context() would have returned a NULL pointer.";
488    let aggregate_context = unsafe {
489        // Within the xFinal callback, it is customary to set nBytes to 0 so no pointless memory
490        // allocations occur, a null pointer is returned in this case
491        // See: https://www.sqlite.org/c3ref/aggregate_context.html
492        //
493        // For the reasoning about the safety of the OptionalAggregator handling
494        // see the comment in run_aggregator_step_function.
495        ffi::sqlite3_aggregate_context(ctx, 0)
496    };
497
498    let result = crate::util::std_compat::catch_unwind(|| {
499        let mut aggregate_context = NonNull::new(aggregate_context as *mut OptionalAggregator<A>);
500
501        let aggregator = if let Some(a) = aggregate_context.as_mut() {
502            let a = unsafe { a.as_mut() };
503            match core::mem::replace(a, OptionalAggregator::None) {
504                OptionalAggregator::None => {
505                    return Err(SqliteCallbackError::Abort(NO_AGGREGATOR_FOUND));
506                }
507                OptionalAggregator::Some(a) => Some(a),
508            }
509        } else {
510            None
511        };
512
513        let res = A::finalize(aggregator);
514        let value = process_sql_function_result(&res)?;
515        // We've checked already that ctx is not null
516        let r = unsafe { value.result_of(&mut *ctx) };
517        r.map_err(|e| {
518            SqliteCallbackError::DieselError(crate::result::Error::SerializationError(Box::new(e)))
519        })?;
520        Ok(())
521    })
522    .unwrap_or_else(|_e| {
523        Err(SqliteCallbackError::Panic(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::finalize() panicked",
                core::any::type_name::<A>()))
    })alloc::format!(
524            "{}::finalize() panicked",
525            core::any::type_name::<A>()
526        )))
527    });
528    if let Err(e) = result {
529        e.emit(ctx);
530    }
531}
532
533unsafe fn context_error_str(ctx: *mut ffi::sqlite3_context, error: &str) {
534    let len: i32 = error
535        .len()
536        .try_into()
537        .expect("Trying to set a error message with more than 2^32 byte is not supported");
538    unsafe {
539        ffi::sqlite3_result_error(ctx, error.as_ptr() as *const _, len);
540    }
541}
542
543struct CollationUserPtr<F> {
544    callback: F,
545    collation_name: String,
546}
547
548#[allow(warnings)]
549extern "C" fn run_collation_function<F>(
550    user_ptr: *mut libc::c_void,
551    lhs_len: libc::c_int,
552    lhs_ptr: *const libc::c_void,
553    rhs_len: libc::c_int,
554    rhs_ptr: *const libc::c_void,
555) -> libc::c_int
556where
557    F: Fn(&str, &str) -> core::cmp::Ordering + Send + core::panic::UnwindSafe + 'static,
558{
559    let user_ptr = user_ptr as *const CollationUserPtr<F>;
560    let user_ptr = core::panic::AssertUnwindSafe(unsafe { user_ptr.as_ref() });
561
562    let result = crate::util::std_compat::catch_unwind(|| {
563        let user_ptr = user_ptr.ok_or_else(|| {
564            SqliteCallbackError::Abort(
565                "Got a null pointer as data pointer. This should never happen",
566            )
567        })?;
568        for (ptr, len, side) in &[(rhs_ptr, rhs_len, "rhs"), (lhs_ptr, lhs_len, "lhs")] {
569            if *len < 0 {
570                {
    ::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", 570u32));
};
crate::util::std_compat::abort();assert_fail!(
571                    "An unknown error occurred. {}_len is negative. This should never happen.",
572                    side
573                );
574            }
575            if ptr.is_null() {
576                {
    ::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", 576u32));
};
crate::util::std_compat::abort();assert_fail!(
577                "An unknown error occurred. {}_ptr is a null pointer. This should never happen.",
578                side
579            );
580            }
581        }
582
583        let (rhs, lhs) = unsafe {
584            // Depending on the eTextRep-parameter to sqlite3_create_collation_v2() the strings can
585            // have various encodings. register_collation_function() always selects SQLITE_UTF8, so the
586            // pointers point to valid UTF-8 strings (assuming correct behavior of libsqlite3).
587            (
588                str::from_utf8(slice::from_raw_parts(rhs_ptr as *const u8, rhs_len as _)),
589                str::from_utf8(slice::from_raw_parts(lhs_ptr as *const u8, lhs_len as _)),
590            )
591        };
592
593        let rhs =
594            rhs.map_err(|_| SqliteCallbackError::Abort("Got an invalid UTF-8 string for rhs"))?;
595        let lhs =
596            lhs.map_err(|_| SqliteCallbackError::Abort("Got an invalid UTF-8 string for lhs"))?;
597
598        Ok((user_ptr.callback)(rhs, lhs))
599    })
600    .unwrap_or_else(|p| {
601        Err(SqliteCallbackError::Panic(
602            user_ptr
603                .map(|u| u.collation_name.clone())
604                .unwrap_or_default(),
605        ))
606    });
607
608    match result {
609        Ok(core::cmp::Ordering::Less) => -1,
610        Ok(core::cmp::Ordering::Equal) => 0,
611        Ok(core::cmp::Ordering::Greater) => 1,
612        Err(SqliteCallbackError::Abort(a)) => {
613            #[cfg(feature = "std")]
614            {
    ::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!(
615                "Collation function {} failed with: {}",
616                user_ptr
617                    .map(|c| &c.collation_name as &str)
618                    .unwrap_or_default(),
619                a
620            );
621            crate::util::std_compat::abort()
622        }
623        Err(SqliteCallbackError::DieselError(e)) => {
624            #[cfg(feature = "std")]
625            {
    ::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!(
626                "Collation function {} failed with: {}",
627                user_ptr
628                    .map(|c| &c.collation_name as &str)
629                    .unwrap_or_default(),
630                e
631            );
632            crate::util::std_compat::abort()
633        }
634        Err(SqliteCallbackError::Panic(msg)) => {
635            #[cfg(feature = "std")]
636            {
    ::std::io::_eprint(format_args!("Collation function {0} panicked\n",
            msg));
};eprintln!("Collation function {} panicked", msg);
637            crate::util::std_compat::abort()
638        }
639    }
640}
641
642extern "C" fn destroy_boxed<F>(data: *mut libc::c_void) {
643    let ptr = data as *mut F;
644    unsafe { core::mem::drop(Box::from_raw(ptr)) };
645}