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