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