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