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