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::SqliteConnection;
9use super::authorizer::{AuthorizerContext, AuthorizerDecision};
10use super::collation_needed::{CollationNeededContext, SqliteTextRep};
11use super::functions::{build_sql_function_args, process_sql_function_result};
12use super::limits::SqliteLimit;
13use super::serialized_database::SerializedDatabase;
14use super::stmt::ensure_sqlite_ok;
15use super::trace::{SqliteTraceEvent, SqliteTraceFlags, TRACE_PROFILE, TRACE_ROW, TRACE_STMT};
16use super::update_hook::{SqliteChangeEvent, SqliteChangeOp};
17use super::{BusyDecision, CommitDecision, ProgressDecision};
18use super::{Sqlite, SqliteAggregateFunction};
19use crate::deserialize::FromSqlRow;
20use crate::result::Error::DatabaseError;
21use crate::result::*;
22use crate::serialize::ToSql;
23use crate::sql_types::HasSqlType;
24use crate::sqlite::{BorrowedSqliteConnection, SqliteFunctionBehavior};
25use alloc::borrow::{Cow, ToOwned};
26use alloc::boxed::Box;
27use alloc::ffi::{CString, NulError};
28use alloc::string::{String, ToString};
29use core::ffi as libc;
30use core::ffi::CStr;
31use core::num::NonZeroU32;
32use core::ptr::NonNull;
33use core::{mem, ptr, slice, str};
34
35// `sqlite3_db_config()` option codes controlling whether ATTACH may create new
36// database files (ATTACH_CREATE) or open them in write mode (ATTACH_WRITE).
37// Introduced in SQLite 3.49.0 / `libsqlite3-sys` 0.35.0, but Diesel supports
38// `libsqlite3-sys` >= 0.17.2, so we define them here to build against any
39// supported version. On an older linked SQLite the `sqlite3_db_config()` call
40// fails at runtime, which callers already handle.
41pub(super) const SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE: i32 = 1020;
42pub(super) const SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE: i32 = 1021;
43
44/// The numeric version of the linked SQLite library, `X * 1_000_000 + Y * 1_000 + Z`.
45pub(super) fn library_version_number() -> u32 {
46    // SAFETY: `sqlite3_libversion_number` takes no arguments and returns a constant of
47    // the linked library, so it is sound to call at any time from any thread.
48    let version = unsafe { ffi::sqlite3_libversion_number() };
49    version.cast_unsigned()
50}
51
52// Runtime extension loading (`sqlite3_load_extension`) is deliberately unsupported.
53// Platforms that build SQLite with `-DSQLITE_OMIT_LOAD_EXTENSION` (see #2180) drop
54// the symbol from the ABI, and the runtime `dlsym` workaround in #4954 proved too
55// fragile to ship. Use `declare_sql_function`, `register_auto_extension`, or
56// `SqliteConnection::with_raw_connection` instead.
57
58/// For use in FFI function, which cannot unwind.
59/// Print the message, ask to open an issue at Github and [`abort`](std::process::abort).
60macro_rules! assert_fail {
61    ($fmt:expr_2021 $(,$args:tt)*) => {
62        #[cfg(feature = "std")]
63        eprint!(concat!(
64            $fmt,
65            "If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\n",
66            "Source location: {}:{}\n",
67        ), $($args,)* file!(), line!());
68        crate::util::std_compat::abort()
69    };
70}
71
72// That's in its own struct to make it
73// easier to move them out in the destructor to
74// only drop them after freeing the underlying connection
75//
76// Otherwise a panic in any of the hook destructors would
77// leak the connection
78#[derive(#[automatically_derived]impl ::core::default::Default for Hooks {
    #[inline]
    fn default() -> Self {
        Hooks {
            update_hook: ::core::default::Default::default(),
            commit_hook: ::core::default::Default::default(),
            rollback_hook: ::core::default::Default::default(),
            progress_hook: ::core::default::Default::default(),
            wal_hook: ::core::default::Default::default(),
            busy_handler: ::core::default::Default::default(),
            authorizer_hook: ::core::default::Default::default(),
            trace_hook: ::core::default::Default::default(),
            collation_needed_hook: ::core::default::Default::default(),
        }
    }
}Default)]
79pub(super) struct Hooks {
80    /// Boxed closure kept alive while the update hook is registered.
81    update_hook: Option<Box<dyn FnMut(SqliteChangeEvent<'_>) + Send>>,
82    /// Boxed closure kept alive while the commit hook is registered.
83    commit_hook: Option<Box<dyn FnMut() -> CommitDecision + Send>>,
84    /// Boxed closure kept alive while the rollback hook is registered.
85    rollback_hook: Option<Box<dyn FnMut() + Send>>,
86    /// Boxed closure kept alive while the progress handler is registered.
87    progress_hook: Option<Box<dyn FnMut() -> ProgressDecision + Send>>,
88    /// Boxed closure kept alive while the WAL hook is registered.
89    wal_hook: Option<Box<dyn Fn(&'_ mut BorrowedSqliteConnection, &str, u32) + Send>>,
90    /// Boxed closure kept alive while the busy handler is registered.
91    busy_handler: Option<Box<dyn FnMut(i32) -> BusyDecision + Send>>,
92    /// Boxed closure kept alive while the authorizer is registered.
93    authorizer_hook: Option<Box<dyn FnMut(AuthorizerContext<'_>) -> AuthorizerDecision + Send>>,
94    /// Boxed closure kept alive while the trace callback is registered.
95    trace_hook: Option<Box<dyn FnMut(SqliteTraceEvent<'_>) + Send>>,
96    /// Boxed closure kept alive while the collation-needed callback is registered.
97    collation_needed_hook:
98        Option<Box<dyn Fn(CollationNeededContext<'_>) -> Option<Collation> + Send>>,
99}
100
101#[allow(missing_debug_implementations, missing_copy_implementations)]
102pub(super) struct RawConnection {
103    pub(super) internal_connection: NonNull<ffi::sqlite3>,
104    hooks: Hooks,
105}
106
107type Collation = Box<dyn Fn(&str, &str) -> core::cmp::Ordering + Send + core::panic::UnwindSafe>;
108
109impl RawConnection {
110    /// Wraps a borrowed `sqlite3` pointer this `RawConnection` does not own
111    /// (kept in a `ManuallyDrop` for SQL-function callbacks, so `Drop` never runs).
112    pub(super) fn from_ptr(conn: NonNull<ffi::sqlite3>) -> Self {
113        RawConnection {
114            internal_connection: conn,
115            hooks: Hooks::default(),
116        }
117    }
118
119    pub(super) fn establish(database_url: &str) -> ConnectionResult<Self> {
120        let mut conn_pointer = ptr::null_mut();
121
122        let database_url = if database_url.starts_with("sqlite://") {
123            CString::new(database_url.replacen("sqlite://", "file:", 1))?
124        } else {
125            CString::new(database_url)?
126        };
127        let flags = ffi::SQLITE_OPEN_READWRITE | ffi::SQLITE_OPEN_CREATE | ffi::SQLITE_OPEN_URI;
128        let connection_status = unsafe {
129            ffi::sqlite3_open_v2(database_url.as_ptr(), &mut conn_pointer, flags, ptr::null())
130        };
131
132        match connection_status {
133            ffi::SQLITE_OK => {
134                let conn_pointer = unsafe { NonNull::new_unchecked(conn_pointer) };
135                Ok(RawConnection {
136                    internal_connection: conn_pointer,
137                    hooks: Hooks::default(),
138                })
139            }
140            err_code => {
141                let message = super::error_message(err_code);
142                // sqlite3_open_v2() may allocate a database connection handle
143                // even on failure. To avoid a resource leak, it must be released
144                // with sqlite3_close(). Passing a null pointer to sqlite3_close()
145                // is a harmless no-op, so no null check is needed.
146                // See: https://www.sqlite.org/c3ref/open.html
147                unsafe { ffi::sqlite3_close(conn_pointer) };
148                Err(ConnectionError::BadConnection(message.into()))
149            }
150        }
151    }
152
153    pub(super) fn exec(&self, query: &str) -> QueryResult<()> {
154        let query = CString::new(query)?;
155        let callback_fn = None;
156        let callback_arg = ptr::null_mut();
157        let result = unsafe {
158            ffi::sqlite3_exec(
159                self.internal_connection.as_ptr(),
160                query.as_ptr(),
161                callback_fn,
162                callback_arg,
163                ptr::null_mut(),
164            )
165        };
166
167        ensure_sqlite_ok(result, self.internal_connection.as_ptr())
168    }
169
170    pub(super) fn rows_affected_by_last_query(
171        &self,
172    ) -> Result<usize, Box<dyn core::error::Error + Send + Sync>> {
173        let r = unsafe { ffi::sqlite3_changes(self.internal_connection.as_ptr()) };
174
175        Ok(r.try_into()?)
176    }
177
178    pub(super) fn last_insert_rowid(&self) -> i64 {
179        unsafe { ffi::sqlite3_last_insert_rowid(self.internal_connection.as_ptr()) }
180    }
181
182    pub(super) fn is_autocommit(&self) -> bool {
183        // SAFETY: `internal_connection` stays open until `Drop`.
184        unsafe { ffi::sqlite3_get_autocommit(self.internal_connection.as_ptr()) != 0 }
185    }
186
187    pub(super) fn register_sql_function<F, Ret, RetSqlType>(
188        &self,
189        fn_name: &str,
190        num_args: usize,
191        behavior: SqliteFunctionBehavior,
192        f: F,
193    ) -> QueryResult<()>
194    where
195        F: FnMut(&Self, &mut [*mut ffi::sqlite3_value]) -> QueryResult<Ret>
196            + core::panic::UnwindSafe
197            + Send
198            + 'static,
199        Ret: ToSql<RetSqlType, Sqlite>,
200        Sqlite: HasSqlType<RetSqlType>,
201    {
202        let c_fn_name = Self::get_fn_name(fn_name)?;
203        let flags = behavior.to_flags();
204        let num_args = num_args
205            .try_into()
206            .map_err(|e| Error::SerializationError(Box::new(e)))?;
207        // only create the pointer as last step here
208        // as we can otherwise leak memory
209        let callback_fn = Box::into_raw(Box::new(CustomFunctionUserPtr {
210            callback: f,
211            function_name: fn_name.to_owned(),
212        }));
213
214        let result = unsafe {
215            ffi::sqlite3_create_function_v2(
216                self.internal_connection.as_ptr(),
217                c_fn_name.as_ptr(),
218                num_args,
219                flags,
220                callback_fn as *mut _,
221                Some(run_custom_function::<F, Ret, RetSqlType>),
222                None,
223                None,
224                Some(destroy_boxed::<CustomFunctionUserPtr<F>>),
225            )
226        };
227
228        Self::process_sql_function_result(result)
229    }
230
231    pub(super) fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
232        &self,
233        fn_name: &str,
234        num_args: usize,
235        behavior: SqliteFunctionBehavior,
236    ) -> QueryResult<()>
237    where
238        A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
239        Args: FromSqlRow<ArgsSqlType, Sqlite>,
240        Ret: ToSql<RetSqlType, Sqlite>,
241        Sqlite: HasSqlType<RetSqlType>,
242    {
243        let fn_name = Self::get_fn_name(fn_name)?;
244        let flags = behavior.to_flags();
245        let num_args = num_args
246            .try_into()
247            .map_err(|e| Error::SerializationError(Box::new(e)))?;
248
249        let result = unsafe {
250            ffi::sqlite3_create_function_v2(
251                self.internal_connection.as_ptr(),
252                fn_name.as_ptr(),
253                num_args,
254                flags,
255                core::ptr::null_mut(),
256                None,
257                Some(run_aggregator_step_function::<_, _, _, _, A>),
258                Some(run_aggregator_final_function::<_, _, _, _, A>),
259                None,
260            )
261        };
262
263        Self::process_sql_function_result(result)
264    }
265
266    pub(super) fn register_collation_function<F>(
267        &self,
268        collation_name: &str,
269        collation: F,
270    ) -> QueryResult<()>
271    where
272        F: Fn(&str, &str) -> core::cmp::Ordering + core::panic::UnwindSafe + Send + 'static,
273    {
274        let c_collation_name = Self::get_fn_name(collation_name)?;
275        // only create the pointer as last step here as we otherwise could leak memory
276        let callback_fn = Box::into_raw(Box::new(CollationUserPtr {
277            callback: collation,
278            collation_name: collation_name.to_owned(),
279        }));
280
281        let result = unsafe {
282            ffi::sqlite3_create_collation_v2(
283                self.internal_connection.as_ptr(),
284                c_collation_name.as_ptr(),
285                ffi::SQLITE_UTF8,
286                callback_fn as *mut _,
287                Some(run_collation_function::<F>),
288                Some(destroy_boxed::<CollationUserPtr<F>>),
289            )
290        };
291
292        let result = Self::process_sql_function_result(result);
293        if result.is_err() {
294            destroy_boxed::<CollationUserPtr<F>>(callback_fn as *mut _);
295        }
296        result
297    }
298
299    pub(super) fn serialize(&mut self) -> SerializedDatabase {
300        let mut size: ffi::sqlite3_int64 = 0;
301        // SAFETY: The connection is live, a null schema selects `main`, and `size` is a writable out-parameter.
302        let data_ptr = unsafe {
303            ffi::sqlite3_serialize(
304                self.internal_connection.as_ptr(),
305                core::ptr::null(),
306                &mut size as *mut _,
307                0,
308            )
309        };
310        // SQLite returns null with size zero for a valid empty deserialized
311        // database and null with a nonzero size when the output allocation
312        // fails. `SerializedDatabase` reports the failure when accessed.
313        let data = match core::ptr::NonNull::new(data_ptr) {
314            Some(data) => data,
315            None if size == 0 => return SerializedDatabase::empty(),
316            None => return SerializedDatabase::allocation_failed(),
317        };
318        // SAFETY: SQLite transferred an exclusive allocation holding `size` initialized bytes.
319        unsafe { SerializedDatabase::new(data, size) }
320    }
321
322    // we copy the buffer into sqlite's memory, so there is nothing that
323    // the caller of this function needs to uphold
324    pub(super) fn deserialize(&mut self, data: &[u8]) -> QueryResult<()> {
325        let db_size = data
326            .len()
327            .try_into()
328            .map_err(|e| Error::DeserializationError(Box::new(e)))?;
329
330        // Starting from here until we called sqlite3_deserialize
331        // we need to take care not to return early to not leak
332        // this memory
333        let buffer = unsafe {
334            // SAFETY: That's malloc, so it's safe to call
335            ffi::sqlite3_malloc64(data.len() as u64).cast::<u8>()
336        };
337        if buffer.is_null() && !data.is_empty() {
338            return Err(Error::DeserializationError(
339                "Failed to allocate the memory for the database buffer".into(),
340            ));
341        }
342        if !data.is_empty() {
343            unsafe {
344                // SAFETY: we copy bytes, so buffer is always aligned correctly
345                // We allocated the right size above and checked for null pointers
346                // Data and buffer are different pointers, so they cannot overlap as long
347                // as nothing in sqlite/rustc/alloc broke
348                core::ptr::copy_nonoverlapping(data.as_ptr(), buffer, data.len());
349            }
350        }
351
352        // the cast for `ffi::SQLITE_DESERIALIZE_READONLY` is required for old libsqlite3-sys versions
353        #[allow(clippy::unnecessary_cast)]
354        unsafe {
355            let result = ffi::sqlite3_deserialize(
356                self.internal_connection.as_ptr(),
357                core::ptr::null(),
358                buffer,
359                db_size,
360                db_size,
361                ffi::SQLITE_DESERIALIZE_READONLY as u32
362                    | ffi::SQLITE_DESERIALIZE_FREEONCLOSE as u32,
363            );
364
365            // If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the SQLITE_DESERIALIZE_FREEONCLOSE bit is
366            // set in argument F, then sqlite3_free() is invoked on argument P prior to returning.
367            //
368            // -> There is no need to free the buffer here, sqlite takes care for us
369            ensure_sqlite_ok(result, self.internal_connection.as_ptr())
370        }
371    }
372
373    pub(super) fn set_limit(&self, limit: SqliteLimit, value: u32) -> u32 {
374        let value = i32::try_from(value).unwrap_or(i32::MAX);
375        let previous =
376            unsafe { ffi::sqlite3_limit(self.internal_connection.as_ptr(), limit.to_ffi(), value) };
377        // SQLite returns a negative value only for an unknown limit id, which `SqliteLimit` rules out.
378        u32::try_from(previous).unwrap_or(0)
379    }
380
381    pub(super) fn get_limit(&self, limit: SqliteLimit) -> u32 {
382        let current = unsafe {
383            // Passing -1 queries the current value without changing it
384            ffi::sqlite3_limit(self.internal_connection.as_ptr(), limit.to_ffi(), -1)
385        };
386        u32::try_from(current).unwrap_or(0)
387    }
388
389    /// Set a boolean db_config option.
390    pub(super) fn set_db_config_bool(&self, op: i32, value: bool) -> QueryResult<()> {
391        let mut result_value: libc::c_int = 0;
392        let new_value: libc::c_int = if value { 1 } else { 0 };
393
394        let result = unsafe {
395            ffi::sqlite3_db_config(
396                self.internal_connection.as_ptr(),
397                op,
398                new_value,
399                &mut result_value as *mut libc::c_int,
400            )
401        };
402
403        ensure_sqlite_ok(result, self.internal_connection.as_ptr())
404    }
405
406    /// Get a boolean db_config option.
407    pub(super) fn get_db_config_bool(&self, op: i32) -> QueryResult<bool> {
408        let mut current_value: libc::c_int = 0;
409
410        let result = unsafe {
411            ffi::sqlite3_db_config(
412                self.internal_connection.as_ptr(),
413                op,
414                -1_i32, // -1 queries without changing
415                &mut current_value as *mut libc::c_int,
416            )
417        };
418
419        ensure_sqlite_ok(result, self.internal_connection.as_ptr())?;
420        Ok(current_value != 0)
421    }
422
423    fn get_fn_name(fn_name: &str) -> Result<CString, NulError> {
424        CString::new(fn_name)
425    }
426
427    fn process_sql_function_result(result: i32) -> Result<(), Error> {
428        if result == ffi::SQLITE_OK {
429            Ok(())
430        } else {
431            let error_message = super::error_message(result);
432            Err(DatabaseError(
433                DatabaseErrorKind::Unknown,
434                Box::new(error_message.to_string()),
435            ))
436        }
437    }
438
439    pub(super) fn blob_open<'conn>(
440        &'conn self,
441        database_name: &str,
442        table_name: &str,
443        column_name: &str,
444        row_id: i64,
445    ) -> Result<super::sqlite_blob::SqliteReadOnlyBlob<'conn>, Error> {
446        let database_name = alloc::ffi::CString::new(database_name)?;
447        let column_name = alloc::ffi::CString::new(column_name)?;
448        let table_name = alloc::ffi::CString::new(table_name)?;
449
450        let mut blob: *mut ffi::sqlite3_blob = core::ptr::null_mut();
451
452        // SAFETY: All variables are properly initialized
453        let ret = unsafe {
454            ffi::sqlite3_blob_open(
455                self.internal_connection.as_ptr(),
456                database_name.as_c_str().as_ptr(),
457                table_name.as_c_str().as_ptr(),
458                column_name.as_c_str().as_ptr(),
459                row_id,
460                0,
461                &mut blob,
462            )
463        };
464
465        Self::process_sql_function_result(ret)?;
466
467        // SAFETY: `sqlite3_blob_open` initializes the `blob` variable IF the return value:
468        //
469        // > On success, SQLITE_OK is returned and the new BLOB handle is stored in *ppBlob.
470        // > Otherwise an error code is returned and, unless the error code is SQLITE_MISUSE,
471        // > *ppBlob is set to NULL.
472        //
473        // And we checked the `ret` value above
474        let blob = unsafe { core::ptr::NonNull::new_unchecked(blob) };
475
476        // SAFETY: According to the SQLite docs, this can only fail if an invalid pointer is passed
477        let blob_size = unsafe { ffi::sqlite3_blob_bytes(blob.as_ptr()) };
478        let blob_size = usize::try_from(blob_size).map_err(Error::IntegerConversion)?;
479
480        Ok(super::sqlite_blob::SqliteReadOnlyBlob {
481            blob: Some(blob),
482            read_index: 0,
483            blob_size,
484            _pd: core::marker::PhantomData,
485        })
486    }
487
488    /// Sets the update hook, replacing any previous one.
489    ///
490    /// # Safety
491    ///
492    /// `ptr` is derived from `&raw mut *boxed` and points to the heap
493    /// allocation of the closure. `update_hook_trampoline::<F>` matches the
494    /// signature `sqlite3_update_hook` expects. The pointer stays valid because
495    /// we store `boxed` in `self.update_hook` below, keeping it alive for the
496    /// lifetime of this `RawConnection`, and the hook is removed before
497    /// `sqlite3_close` (see `Drop`), so the pointer is never read after the box
498    /// is freed.
499    pub(super) fn set_update_hook<F>(&mut self, hook: F)
500    where
501        F: FnMut(SqliteChangeEvent<'_>) + Send + 'static,
502    {
503        let mut boxed: Box<dyn FnMut(SqliteChangeEvent<'_>) + Send> = Box::new(hook);
504        let ptr = &raw mut *boxed as *mut libc::c_void;
505
506        unsafe {
507            ffi::sqlite3_update_hook(
508                self.internal_connection.as_ptr(),
509                Some(update_hook_trampoline::<F>),
510                ptr,
511            );
512        }
513
514        // The old box (if any) is dropped here after SQLite has already
515        // switched to the new pointer, preventing use-after-free.
516        self.hooks.update_hook = Some(boxed);
517    }
518
519    /// Removes the update hook.
520    ///
521    /// # Safety
522    ///
523    /// `self.internal_connection` is a valid open SQLite connection. Passing
524    /// `None` and `null_mut()` clears any installed update hook. The hook is
525    /// unregistered before dropping `self.update_hook` so SQLite no longer
526    /// reads the pointer during cleanup.
527    pub(super) fn remove_update_hook(&mut self) {
528        unsafe {
529            ffi::sqlite3_update_hook(self.internal_connection.as_ptr(), None, ptr::null_mut());
530        }
531        self.hooks.update_hook = None;
532    }
533
534    /// Sets the commit hook, replacing any previous one.
535    ///
536    /// # Safety
537    ///
538    /// The `ptr` is derived from `&raw mut *boxed` and points to the heap
539    /// allocation of the closure. The `commit_hook_trampoline` function
540    /// matches the signature expected by `sqlite3_commit_hook`. The pointer
541    /// remains valid because we store `boxed` in `self.commit_hook` below,
542    /// keeping it alive for the lifetime of this `RawConnection`.
543    pub(super) fn set_commit_hook<F>(&mut self, hook: F)
544    where
545        F: FnMut() -> CommitDecision + Send + 'static,
546    {
547        let mut boxed: Box<dyn FnMut() -> CommitDecision + Send> = Box::new(hook);
548        let ptr = &raw mut *boxed as *mut libc::c_void;
549
550        unsafe {
551            ffi::sqlite3_commit_hook(
552                self.internal_connection.as_ptr(),
553                Some(commit_hook_trampoline::<F>),
554                ptr,
555            );
556        }
557
558        // The old Box (if any) is dropped here after SQLite has already
559        // switched to the new callback, preventing use-after-free.
560        self.hooks.commit_hook = Some(boxed);
561    }
562
563    /// Removes the commit hook.
564    ///
565    /// # Safety
566    ///
567    /// `self.internal_connection` is a valid pointer to an open SQLite
568    /// connection. Passing `None` as the hook and `null_mut()` as the user
569    /// data unregisters any existing commit hook. The hook is unregistered
570    /// before dropping `self.commit_hook` to prevent callbacks from firing
571    /// during cleanup.
572    pub(super) fn remove_commit_hook(&mut self) {
573        unsafe {
574            ffi::sqlite3_commit_hook(self.internal_connection.as_ptr(), None, ptr::null_mut());
575        }
576        self.hooks.commit_hook = None;
577    }
578
579    /// Sets the rollback hook, replacing any previous one.
580    ///
581    /// # Safety
582    ///
583    /// The `ptr` is derived from `&raw mut *boxed` and points to the heap
584    /// allocation of the closure. The `rollback_hook_trampoline` function
585    /// matches the signature expected by `sqlite3_rollback_hook`. The pointer
586    /// remains valid because we store `boxed` in `self.rollback_hook` below,
587    /// keeping it alive for the lifetime of this `RawConnection`.
588    pub(super) fn set_rollback_hook<F>(&mut self, hook: F)
589    where
590        F: FnMut() + Send + 'static,
591    {
592        let mut boxed: Box<dyn FnMut() + Send> = Box::new(hook);
593        let ptr = &raw mut *boxed as *mut libc::c_void;
594
595        unsafe {
596            ffi::sqlite3_rollback_hook(
597                self.internal_connection.as_ptr(),
598                Some(rollback_hook_trampoline::<F>),
599                ptr,
600            );
601        }
602
603        // The old Box (if any) is dropped here after SQLite has already
604        // switched to the new callback, preventing use-after-free.
605        self.hooks.rollback_hook = Some(boxed);
606    }
607
608    /// Removes the rollback hook.
609    ///
610    /// # Safety
611    ///
612    /// `self.internal_connection` is a valid pointer to an open SQLite
613    /// connection. Passing `None` as the hook and `null_mut()` as the user
614    /// data unregisters any existing rollback hook. The hook is unregistered
615    /// before dropping `self.rollback_hook` to prevent callbacks from firing
616    /// during cleanup.
617    pub(super) fn remove_rollback_hook(&mut self) {
618        unsafe {
619            ffi::sqlite3_rollback_hook(self.internal_connection.as_ptr(), None, ptr::null_mut());
620        }
621        self.hooks.rollback_hook = None;
622    }
623
624    /// Sets the progress handler, replacing any previous one.
625    ///
626    /// `n` is the approximate number of VM instructions between callbacks.
627    ///
628    /// # Safety
629    ///
630    /// The `ptr` is derived from `&raw mut *boxed` and points to the heap
631    /// allocation of the closure. The `progress_handler_trampoline` function
632    /// matches the signature expected by `sqlite3_progress_handler`. The
633    /// pointer remains valid because we store `boxed` in `self.progress_hook`
634    /// below, keeping it alive for the lifetime of this `RawConnection`.
635    pub(super) fn set_progress_handler<F>(&mut self, n: NonZeroU32, hook: F)
636    where
637        F: FnMut() -> ProgressDecision + Send + 'static,
638    {
639        let mut boxed: Box<dyn FnMut() -> ProgressDecision + Send> = Box::new(hook);
640        let ptr = &raw mut *boxed as *mut libc::c_void;
641
642        // `sqlite3_progress_handler` takes a c_int. A value above `i32::MAX`
643        // would wrap to a non-positive number and disable the handler, so clamp
644        // it to `i32::MAX` instead.
645        let n = i32::try_from(n.get()).unwrap_or(i32::MAX);
646
647        unsafe {
648            ffi::sqlite3_progress_handler(
649                self.internal_connection.as_ptr(),
650                n,
651                Some(progress_handler_trampoline::<F>),
652                ptr,
653            );
654        }
655
656        // The old Box (if any) is dropped here after SQLite has already
657        // switched to the new callback, preventing use-after-free.
658        self.hooks.progress_hook = Some(boxed);
659    }
660
661    /// Removes the progress handler.
662    ///
663    /// # Safety
664    ///
665    /// `self.internal_connection` is a valid pointer to an open SQLite
666    /// connection. Passing `None` as the handler and `null_mut()` as the user
667    /// data unregisters any existing progress handler. The handler is
668    /// unregistered before dropping `self.progress_hook` to prevent callbacks
669    /// from firing during cleanup.
670    pub(super) fn remove_progress_handler(&mut self) {
671        unsafe {
672            ffi::sqlite3_progress_handler(
673                self.internal_connection.as_ptr(),
674                0,
675                None,
676                ptr::null_mut(),
677            );
678        }
679        self.hooks.progress_hook = None;
680    }
681
682    /// Sets the WAL hook, replacing any previous one.
683    ///
684    /// The callback receives a borrowed `&mut SqliteConnection`, the database
685    /// name (e.g. `"main"`) and the number of pages currently in the WAL file.
686    ///
687    /// # Safety
688    ///
689    /// The `ptr` is derived from `&raw const *boxed` and points to the heap
690    /// allocation of the closure. The `wal_hook_trampoline` function matches the
691    /// signature expected by `sqlite3_wal_hook`. The pointer remains valid
692    /// because we store `boxed` in `self.wal_hook` below, keeping it alive for
693    /// the lifetime of this `RawConnection`.
694    pub(super) fn set_wal_hook<F>(&mut self, hook: F)
695    where
696        F: Fn(&'_ mut BorrowedSqliteConnection, &str, u32) + Send + 'static,
697    {
698        let boxed: Box<dyn Fn(&'_ mut BorrowedSqliteConnection, &str, u32) + Send> = Box::new(hook);
699        let ptr = &raw const *boxed as *mut libc::c_void;
700
701        unsafe {
702            ffi::sqlite3_wal_hook(
703                self.internal_connection.as_ptr(),
704                Some(wal_hook_trampoline::<F>),
705                ptr,
706            );
707        }
708
709        // The old Box (if any) is dropped here after SQLite has already
710        // switched to the new callback, preventing use-after-free.
711        self.hooks.wal_hook = Some(boxed);
712    }
713
714    /// Removes the WAL hook.
715    ///
716    /// # Safety
717    ///
718    /// `self.internal_connection` is a valid pointer to an open SQLite
719    /// connection. Passing `None` as the hook and `null_mut()` as the user
720    /// data unregisters any existing WAL hook. The hook is unregistered before
721    /// dropping `self.wal_hook` to prevent callbacks from firing during
722    /// cleanup.
723    pub(super) fn remove_wal_hook(&mut self) {
724        unsafe {
725            ffi::sqlite3_wal_hook(self.internal_connection.as_ptr(), None, ptr::null_mut());
726        }
727        self.hooks.wal_hook = None;
728    }
729
730    /// Sets the busy handler, replacing any previous one.
731    ///
732    /// Only one busy handler can be active at a time. Setting this clears any
733    /// busy timeout previously set with `set_busy_timeout`.
734    ///
735    /// # Safety
736    ///
737    /// The `ptr` is derived from `&raw mut *boxed` and points to the heap
738    /// allocation of the closure. The `busy_handler_trampoline` function
739    /// matches the signature expected by `sqlite3_busy_handler`. The pointer
740    /// remains valid because we store `boxed` in `self.busy_handler` below,
741    /// keeping it alive for the lifetime of this `RawConnection`.
742    pub(super) fn set_busy_handler<F>(&mut self, hook: F)
743    where
744        F: FnMut(i32) -> BusyDecision + Send + 'static,
745    {
746        let mut boxed: Box<dyn FnMut(i32) -> BusyDecision + Send> = Box::new(hook);
747        let ptr = &raw mut *boxed as *mut libc::c_void;
748
749        unsafe {
750            ffi::sqlite3_busy_handler(
751                self.internal_connection.as_ptr(),
752                Some(busy_handler_trampoline::<F>),
753                ptr,
754            );
755        }
756
757        // The old Box (if any) is dropped here after SQLite has already
758        // switched to the new callback, preventing use-after-free.
759        self.hooks.busy_handler = Some(boxed);
760    }
761
762    /// Removes the busy handler.
763    ///
764    /// # Safety
765    ///
766    /// `self.internal_connection` is a valid pointer to an open SQLite
767    /// connection. Passing `None` as the hook and `null_mut()` as the user
768    /// data unregisters any existing busy handler. The hook is unregistered
769    /// before dropping `self.busy_handler` to prevent callbacks from firing
770    /// during cleanup.
771    pub(super) fn remove_busy_handler(&mut self) {
772        unsafe {
773            ffi::sqlite3_busy_handler(self.internal_connection.as_ptr(), None, ptr::null_mut());
774        }
775        self.hooks.busy_handler = None;
776    }
777
778    /// Sets a simple timeout-based busy handler.
779    ///
780    /// SQLite will sleep and retry until `ms` milliseconds have elapsed.
781    /// Setting this clears any custom busy handler.
782    ///
783    /// # Safety
784    ///
785    /// `self.internal_connection` is a valid pointer to an open SQLite
786    /// connection. `sqlite3_busy_timeout` installs its own internal busy
787    /// handler, so the stored `busy_handler` is dropped afterwards to release
788    /// the now-unused closure.
789    pub(super) fn set_busy_timeout(&mut self, timeout: core::time::Duration) {
790        // Round up so a positive sub-millisecond timeout does not become 0, which disables the handler.
791        let ms = i32::try_from(timeout.as_nanos().div_ceil(1_000_000)).unwrap_or(i32::MAX);
792        unsafe {
793            ffi::sqlite3_busy_timeout(self.internal_connection.as_ptr(), ms);
794        }
795        self.hooks.busy_handler = None;
796    }
797
798    /// Sets the authorizer callback, replacing any previous one. Only one
799    /// can be active at a time per connection.
800    ///
801    /// # Safety
802    ///
803    /// The `ptr` is derived from `&raw mut *boxed` and points to the heap
804    /// allocation of the closure. The `authorizer_trampoline` function
805    /// matches the signature expected by `sqlite3_set_authorizer`. The pointer
806    /// remains valid because we store `boxed` in `self.authorizer_hook` below,
807    /// keeping it alive for the lifetime of this `RawConnection`.
808    pub(super) fn set_authorizer<F>(&mut self, hook: F)
809    where
810        F: FnMut(AuthorizerContext<'_>) -> AuthorizerDecision + Send + 'static,
811    {
812        let mut boxed: Box<dyn FnMut(AuthorizerContext<'_>) -> AuthorizerDecision + Send> =
813            Box::new(hook);
814        let ptr = &raw mut *boxed as *mut libc::c_void;
815
816        unsafe {
817            ffi::sqlite3_set_authorizer(
818                self.internal_connection.as_ptr(),
819                Some(authorizer_trampoline::<F>),
820                ptr,
821            );
822        }
823
824        // The old Box (if any) is dropped here after SQLite has already
825        // switched to the new callback, preventing use-after-free.
826        self.hooks.authorizer_hook = Some(boxed);
827    }
828
829    /// Removes the authorizer callback.
830    ///
831    /// # Safety
832    ///
833    /// `self.internal_connection` is a valid pointer to an open SQLite
834    /// connection. Passing `None` as the callback and `null_mut()` as the
835    /// user data unregisters any existing authorizer. The authorizer is
836    /// unregistered before dropping `self.authorizer_hook` to prevent
837    /// callbacks from firing during cleanup.
838    pub(super) fn remove_authorizer(&mut self) {
839        unsafe {
840            ffi::sqlite3_set_authorizer(self.internal_connection.as_ptr(), None, ptr::null_mut());
841        }
842        self.hooks.authorizer_hook = None;
843    }
844
845    /// Sets a trace callback, replacing any previous one.
846    ///
847    /// The callback is invoked for SQL execution tracing based on the
848    /// provided event mask.
849    ///
850    /// # Safety
851    ///
852    /// The `ptr` is derived from `&raw mut *boxed` and points to the heap
853    /// allocation of the closure. The `trace_trampoline` function matches the
854    /// signature expected by `sqlite3_trace_v2`. The pointer remains valid
855    /// because we store `boxed` in `self.trace_hook` below, keeping it alive
856    /// for the lifetime of this `RawConnection`.
857    pub(super) fn set_trace<F>(&mut self, mask: SqliteTraceFlags, hook: F)
858    where
859        F: FnMut(SqliteTraceEvent<'_>) + Send + 'static,
860    {
861        let mut boxed: Box<dyn FnMut(SqliteTraceEvent<'_>) + Send> = Box::new(hook);
862        let ptr = &raw mut *boxed as *mut libc::c_void;
863
864        unsafe {
865            ffi::sqlite3_trace_v2(
866                self.internal_connection.as_ptr(),
867                // An undeclared bit such as 0x40 switches SQLite to the legacy callback ABI.
868                SqliteTraceFlags::from_bits_truncate(mask.bits()).bits(),
869                Some(trace_trampoline::<F>),
870                ptr,
871            );
872        }
873
874        // The old Box (if any) is dropped here after SQLite has already
875        // switched to the new callback, preventing use-after-free.
876        self.hooks.trace_hook = Some(boxed);
877    }
878
879    /// Removes the trace callback.
880    ///
881    /// # Safety
882    ///
883    /// `self.internal_connection` is a valid pointer to an open SQLite
884    /// connection. Passing a mask of `0`, `None` as the callback, and
885    /// `null_mut()` as the user data unregisters any existing trace callback.
886    /// The callback is unregistered before dropping `self.trace_hook` to
887    /// prevent callbacks from firing during cleanup.
888    pub(super) fn remove_trace(&mut self) {
889        unsafe {
890            ffi::sqlite3_trace_v2(self.internal_connection.as_ptr(), 0, None, ptr::null_mut());
891        }
892        self.hooks.trace_hook = None;
893    }
894
895    /// Sets the collation-needed callback, replacing any previous one.
896    ///
897    /// # Safety
898    ///
899    /// `ptr` points to the heap allocation of `boxed`, stored in
900    /// `self.collation_needed_hook` below so it outlives the C-side
901    /// registration.
902    pub(super) fn set_collation_needed_hook<F>(&mut self, hook: F)
903    where
904        F: Fn(CollationNeededContext<'_>) -> Option<Collation> + Send + 'static,
905    {
906        let boxed: Box<dyn Fn(CollationNeededContext<'_>) -> Option<Collation> + Send> =
907            Box::new(hook);
908        let ptr = &raw const *boxed as *mut libc::c_void;
909
910        unsafe {
911            ffi::sqlite3_collation_needed(
912                self.internal_connection.as_ptr(),
913                ptr,
914                Some(collation_needed_trampoline::<F>),
915            );
916        }
917
918        // The old Box (if any) is dropped here after SQLite has already
919        // switched to the new callback, preventing use-after-free.
920        self.hooks.collation_needed_hook = Some(boxed);
921    }
922
923    /// Removes the collation-needed callback.
924    ///
925    /// # Safety
926    ///
927    /// Unregisters via `sqlite3_collation_needed(db, null, None)` before
928    /// dropping `self.collation_needed_hook`, so no callback can fire during
929    /// cleanup.
930    pub(super) fn remove_collation_needed_hook(&mut self) {
931        unsafe {
932            ffi::sqlite3_collation_needed(self.internal_connection.as_ptr(), ptr::null_mut(), None);
933        }
934        self.hooks.collation_needed_hook = None;
935    }
936
937    pub(crate) fn reset_registered_hooks(&mut self) -> Hooks {
938        // explicit destruct to make sure we don't miss a future field
939        let Self {
940            internal_connection,
941            hooks,
942        } = self;
943        let db = internal_connection.as_ptr();
944        let hooks = core::mem::take(hooks);
945
946        // specifically make sure to first deregister all the hooks
947        // and only then drop them
948
949        // SAFETY: db is a valid database, clearing hooks is otherwise always safe
950        unsafe {
951            if hooks.update_hook.is_some() {
952                ffi::sqlite3_update_hook(db, None, ptr::null_mut());
953            }
954            if hooks.commit_hook.is_some() {
955                ffi::sqlite3_commit_hook(db, None, ptr::null_mut());
956            }
957            if hooks.rollback_hook.is_some() {
958                ffi::sqlite3_rollback_hook(db, None, ptr::null_mut());
959            }
960            if hooks.progress_hook.is_some() {
961                ffi::sqlite3_progress_handler(db, 0, None, ptr::null_mut());
962            }
963            if hooks.wal_hook.is_some() {
964                ffi::sqlite3_wal_hook(db, None, ptr::null_mut());
965            }
966            if hooks.busy_handler.is_some() {
967                ffi::sqlite3_busy_handler(db, None, ptr::null_mut());
968            }
969            if hooks.authorizer_hook.is_some() {
970                ffi::sqlite3_set_authorizer(db, None, ptr::null_mut());
971            }
972            if hooks.trace_hook.is_some() {
973                ffi::sqlite3_trace_v2(db, 0, None, ptr::null_mut());
974            }
975            if hooks.collation_needed_hook.is_some() {
976                ffi::sqlite3_collation_needed(db, ptr::null_mut(), None);
977            }
978        }
979        hooks
980    }
981}
982
983impl Drop for RawConnection {
984    fn drop(&mut self) {
985        use crate::util::std_compat::panicking;
986
987        // we bind the hooks to the scope here to only drop them after
988        // freeing the connection handle as any of these destructors might panic
989        let _hooks = self.reset_registered_hooks();
990
991        let close_result = unsafe { ffi::sqlite3_close(self.internal_connection.as_ptr()) };
992        if close_result != ffi::SQLITE_OK {
993            let error_message = super::error_message(close_result);
994            if panicking() {
995                #[cfg(feature = "std")]
996                {
    ::std::io::_eprint(format_args!("Error closing SQLite connection: {0}\n",
            error_message));
};eprintln!("Error closing SQLite connection: {error_message}");
997            } else {
998                {
    ::core::panicking::panic_fmt(format_args!("Error closing SQLite connection: {0}",
            error_message));
};panic!("Error closing SQLite connection: {error_message}");
999            }
1000        }
1001    }
1002}
1003
1004enum SqliteCallbackError {
1005    Abort(&'static str),
1006    DieselError(crate::result::Error),
1007    Panic(String),
1008}
1009
1010impl SqliteCallbackError {
1011    fn emit(&self, ctx: *mut ffi::sqlite3_context) {
1012        let s;
1013        let msg = match self {
1014            SqliteCallbackError::Abort(msg) => *msg,
1015            SqliteCallbackError::DieselError(e) => {
1016                s = e.to_string();
1017                &s
1018            }
1019            SqliteCallbackError::Panic(msg) => msg,
1020        };
1021        unsafe {
1022            context_error_str(ctx, msg);
1023        }
1024    }
1025}
1026
1027impl From<crate::result::Error> for SqliteCallbackError {
1028    fn from(e: crate::result::Error) -> Self {
1029        Self::DieselError(e)
1030    }
1031}
1032
1033struct CustomFunctionUserPtr<F> {
1034    callback: F,
1035    function_name: String,
1036}
1037
1038#[allow(warnings)]
1039extern "C" fn run_custom_function<F, Ret, RetSqlType>(
1040    ctx: *mut ffi::sqlite3_context,
1041    num_args: libc::c_int,
1042    value_ptr: *mut *mut ffi::sqlite3_value,
1043) where
1044    F: FnMut(&RawConnection, &mut [*mut ffi::sqlite3_value]) -> QueryResult<Ret>
1045        + core::panic::UnwindSafe
1046        + Send
1047        + 'static,
1048    Ret: ToSql<RetSqlType, Sqlite>,
1049    Sqlite: HasSqlType<RetSqlType>,
1050{
1051    use core::ops::Deref;
1052    static NULL_DATA_ERR: &str = "An unknown error occurred. sqlite3_user_data returned a null pointer. This should never happen.";
1053    static NULL_CONN_ERR: &str = "An unknown error occurred. sqlite3_context_db_handle returned a null pointer. This should never happen.";
1054
1055    let conn = match unsafe { NonNull::new(ffi::sqlite3_context_db_handle(ctx)) } {
1056        // We use `ManuallyDrop` here because we do not want to run the
1057        // Drop impl of `RawConnection` as this would close the connection
1058        Some(conn) => mem::ManuallyDrop::new(RawConnection::from_ptr(conn)),
1059        None => {
1060            unsafe { context_error_str(ctx, NULL_CONN_ERR) };
1061            return;
1062        }
1063    };
1064
1065    let data_ptr = unsafe { ffi::sqlite3_user_data(ctx) };
1066
1067    let mut data_ptr = match NonNull::new(data_ptr as *mut CustomFunctionUserPtr<F>) {
1068        None => unsafe {
1069            context_error_str(ctx, NULL_DATA_ERR);
1070            return;
1071        },
1072        Some(mut f) => f,
1073    };
1074    let data_ptr = unsafe { data_ptr.as_mut() };
1075
1076    // We need this to move the reference into the catch_unwind part
1077    // this is sound as `F` itself and the stored string is `UnwindSafe`
1078    let callback = core::panic::AssertUnwindSafe(&mut data_ptr.callback);
1079    // conn holds non-UnwindSafe fields: the boxed commit hook and the boxed
1080    // update hook. The ManuallyDrop wrapper ensures we never run RawConnection's Drop.
1081    let conn = core::panic::AssertUnwindSafe(conn);
1082
1083    let result = crate::util::std_compat::catch_unwind(move || {
1084        let _ = &callback;
1085        let args = unsafe { slice::from_raw_parts_mut(value_ptr, num_args as _) };
1086        let res = (callback.0)(&*conn, args)?;
1087        let value = process_sql_function_result(&res)?;
1088        // We've checked already that ctx is not null
1089        unsafe {
1090            value.result_of(&mut *ctx);
1091        }
1092        Ok(())
1093    })
1094    .unwrap_or_else(|p| Err(SqliteCallbackError::Panic(data_ptr.function_name.clone())));
1095    if let Err(e) = result {
1096        e.emit(ctx);
1097    }
1098}
1099
1100#[allow(warnings)]
1101extern "C" fn run_aggregator_step_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
1102    ctx: *mut ffi::sqlite3_context,
1103    num_args: libc::c_int,
1104    value_ptr: *mut *mut ffi::sqlite3_value,
1105) where
1106    A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
1107    Args: FromSqlRow<ArgsSqlType, Sqlite>,
1108    Ret: ToSql<RetSqlType, Sqlite>,
1109    Sqlite: HasSqlType<RetSqlType>,
1110{
1111    let result = crate::util::std_compat::catch_unwind(move || {
1112        let args = unsafe { slice::from_raw_parts_mut(value_ptr, num_args as _) };
1113        run_aggregator_step::<A, Args, ArgsSqlType>(ctx, args)
1114    })
1115    .unwrap_or_else(|e| {
1116        Err(SqliteCallbackError::Panic(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::step() panicked",
                core::any::type_name::<A>()))
    })alloc::format!(
1117            "{}::step() panicked",
1118            core::any::type_name::<A>()
1119        )))
1120    });
1121
1122    match result {
1123        Ok(()) => {}
1124        Err(e) => e.emit(ctx),
1125    }
1126}
1127
1128fn run_aggregator_step<A, Args, ArgsSqlType>(
1129    ctx: *mut ffi::sqlite3_context,
1130    args: &mut [*mut ffi::sqlite3_value],
1131) -> Result<(), SqliteCallbackError>
1132where
1133    A: SqliteAggregateFunction<Args>,
1134    Args: FromSqlRow<ArgsSqlType, Sqlite>,
1135{
1136    let aggregator = unsafe {
1137        const {
1138            if core::mem::size_of::<*mut A>() == 0 {
1139                {
    ::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!(
1140                    "The pointer size is zero, that's unexpected.\
1141                        If you ever see this error message open a issue\
1142                        describing your environment"
1143                );
1144            }
1145        }
1146        // sqlite3_aggregate_context will return a memory allocation of the requested
1147        // size. For the first call this will be zeroed, for any future call in the same execution
1148        // this will contain the value we wrote into it.
1149        //
1150        // We write just a pointer to rust allocated memory in there to
1151        // have the rust side deal with layout and alignment of our aggregator
1152        let ctx = ffi::sqlite3_aggregate_context(
1153            ctx,
1154            core::mem::size_of::<*mut A>()
1155                .try_into()
1156                .expect("Memory size of a pointer is smaller than i32::MAX"),
1157        )
1158        // we cast the returned memory here to be a pointer to the aggregate instance
1159        .cast::<*mut A>();
1160        // sqlite3_aggregate_context returns a null pointer if the allocation fails
1161        if ctx.is_null() {
1162            return Err(SqliteCallbackError::Abort(
1163                "sqlite3_aggregate_context failed to allocate memory for the aggregate state",
1164            ));
1165        }
1166        // we are interested in the inner pointer
1167        let inner = &mut *ctx;
1168        // if the inner pointer is null we the aggregate_step
1169        // function is executed the first time and we need to create the actual
1170        // aggregator
1171        if inner.is_null() {
1172            // for that we allocate a box and turn it into a raw pointer
1173            // by leaking the memory
1174            let obj = Box::into_raw(Box::new(A::default()));
1175            *inner = obj;
1176        }
1177        // at this point the inner value is never null
1178        // as we initialised in in the null branch above,
1179        // therefore it's sound to dereference the pointer here
1180        &mut **inner
1181    };
1182
1183    // SAFETY: SQLite passes a live context for the duration of this callback.
1184    let connection = unsafe { NonNull::new(ffi::sqlite3_context_db_handle(ctx)) };
1185    let connection = connection.ok_or(SqliteCallbackError::Abort(
1186        "sqlite3_context_db_handle returned a null pointer. This should never happen",
1187    ))?;
1188    let args = build_sql_function_args::<ArgsSqlType, Args>(args, connection)?;
1189
1190    aggregator.step(args);
1191    Ok(())
1192}
1193
1194extern "C" fn run_aggregator_final_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
1195    ctx: *mut ffi::sqlite3_context,
1196) where
1197    A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send,
1198    Args: FromSqlRow<ArgsSqlType, Sqlite>,
1199    Ret: ToSql<RetSqlType, Sqlite>,
1200    Sqlite: HasSqlType<RetSqlType>,
1201{
1202    let result = crate::util::std_compat::catch_unwind(|| {
1203        let aggregator = unsafe {
1204            // Get back the aggregated context
1205            // This might be null
1206            let ctx = ffi::sqlite3_aggregate_context(
1207                ctx,
1208                // use zero sized allocation here to not allocate if this is the first call to `sqlite3_aggregate_context`
1209                0,
1210            )
1211            // the allocation contains a pointer to the actual aggregator
1212            .cast::<*mut A>();
1213            // if the context was not allocated yet
1214            // we get back a null pointer here due to
1215            // the requested zero sized allocation
1216            if ctx.is_null() {
1217                None
1218            } else {
1219                // from this point we are interested in the inner pointer
1220                // we checked above that this pointer is not null
1221                // so it's sound to dereference it
1222                let inner = &mut *ctx;
1223                if inner.is_null() {
1224                    // if the inner pointer is null the aggregator has not been initialized
1225                    None
1226                } else {
1227                    // if it's not null
1228                    // we need to construct back the box and move out the
1229                    // value to correctly deallocate the allocation
1230                    let value = Box::from_raw(*inner);
1231                    let value = Some(*value);
1232                    // we also want to write a null pointer back to the
1233                    // context to make sure that there is no dangling pointer left
1234                    *inner = core::ptr::null_mut();
1235                    value
1236                }
1237            }
1238        };
1239
1240        let res = A::finalize(aggregator);
1241        let value = process_sql_function_result(&res)?;
1242        // We've checked already that ctx is not null
1243        let r = unsafe { value.result_of(&mut *ctx) };
1244        r.map_err(|e| {
1245            SqliteCallbackError::DieselError(crate::result::Error::SerializationError(Box::new(e)))
1246        })?;
1247        Ok(())
1248    })
1249    .unwrap_or_else(|_e| {
1250        Err(SqliteCallbackError::Panic(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::finalize() panicked",
                core::any::type_name::<A>()))
    })alloc::format!(
1251            "{}::finalize() panicked",
1252            core::any::type_name::<A>()
1253        )))
1254    });
1255    if let Err(e) = result {
1256        e.emit(ctx);
1257    }
1258}
1259
1260unsafe fn context_error_str(ctx: *mut ffi::sqlite3_context, error: &str) {
1261    let len: i32 = error.len().try_into().unwrap_or(i32::MAX);
1262    unsafe {
1263        ffi::sqlite3_result_error(ctx, error.as_ptr() as *const _, len);
1264    }
1265}
1266
1267struct CollationUserPtr<F> {
1268    callback: F,
1269    collation_name: String,
1270}
1271
1272#[allow(warnings)]
1273extern "C" fn run_collation_function<F>(
1274    user_ptr: *mut libc::c_void,
1275    lhs_len: libc::c_int,
1276    lhs_ptr: *const libc::c_void,
1277    rhs_len: libc::c_int,
1278    rhs_ptr: *const libc::c_void,
1279) -> libc::c_int
1280where
1281    F: Fn(&str, &str) -> core::cmp::Ordering + Send + core::panic::UnwindSafe + 'static,
1282{
1283    let user_ptr = user_ptr as *const CollationUserPtr<F>;
1284    let user_ptr = core::panic::AssertUnwindSafe(unsafe { user_ptr.as_ref() });
1285
1286    let result = crate::util::std_compat::catch_unwind(|| {
1287        let user_ptr = user_ptr.ok_or_else(|| {
1288            SqliteCallbackError::Abort(
1289                "Got a null pointer as data pointer. This should never happen",
1290            )
1291        })?;
1292        for (ptr, len, side) in &[(rhs_ptr, rhs_len, "rhs"), (lhs_ptr, lhs_len, "lhs")] {
1293            if *len < 0 {
1294                {
    ::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", 1294u32));
};
crate::util::std_compat::abort();assert_fail!(
1295                    "An unknown error occurred. {}_len is negative. This should never happen.",
1296                    side
1297                );
1298            }
1299            if ptr.is_null() {
1300                {
    ::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", 1300u32));
};
crate::util::std_compat::abort();assert_fail!(
1301                "An unknown error occurred. {}_ptr is a null pointer. This should never happen.",
1302                side
1303            );
1304            }
1305        }
1306
1307        let (rhs, lhs) = unsafe {
1308            // Depending on the eTextRep-parameter to sqlite3_create_collation_v2() the strings can
1309            // have various encodings. register_collation_function() always selects SQLITE_UTF8, so the
1310            // pointers point to valid UTF-8 strings (assuming correct behavior of libsqlite3).
1311            (
1312                str::from_utf8(slice::from_raw_parts(rhs_ptr as *const u8, rhs_len as _)),
1313                str::from_utf8(slice::from_raw_parts(lhs_ptr as *const u8, lhs_len as _)),
1314            )
1315        };
1316
1317        let rhs =
1318            rhs.map_err(|_| SqliteCallbackError::Abort("Got an invalid UTF-8 string for rhs"))?;
1319        let lhs =
1320            lhs.map_err(|_| SqliteCallbackError::Abort("Got an invalid UTF-8 string for lhs"))?;
1321
1322        Ok((user_ptr.callback)(rhs, lhs))
1323    })
1324    .unwrap_or_else(|p| {
1325        Err(SqliteCallbackError::Panic(
1326            user_ptr
1327                .map(|u| u.collation_name.clone())
1328                .unwrap_or_default(),
1329        ))
1330    });
1331
1332    match result {
1333        Ok(core::cmp::Ordering::Less) => -1,
1334        Ok(core::cmp::Ordering::Equal) => 0,
1335        Ok(core::cmp::Ordering::Greater) => 1,
1336        Err(SqliteCallbackError::Abort(a)) => {
1337            #[cfg(feature = "std")]
1338            {
    ::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!(
1339                "Collation function {} failed with: {}",
1340                user_ptr
1341                    .map(|c| &c.collation_name as &str)
1342                    .unwrap_or_default(),
1343                a
1344            );
1345            crate::util::std_compat::abort()
1346        }
1347        Err(SqliteCallbackError::DieselError(e)) => {
1348            #[cfg(feature = "std")]
1349            {
    ::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!(
1350                "Collation function {} failed with: {}",
1351                user_ptr
1352                    .map(|c| &c.collation_name as &str)
1353                    .unwrap_or_default(),
1354                e
1355            );
1356            crate::util::std_compat::abort()
1357        }
1358        Err(SqliteCallbackError::Panic(msg)) => {
1359            #[cfg(feature = "std")]
1360            {
    ::std::io::_eprint(format_args!("Collation function {0} panicked\n",
            msg));
};eprintln!("Collation function {} panicked", msg);
1361            crate::util::std_compat::abort()
1362        }
1363    }
1364}
1365
1366extern "C" fn destroy_boxed<F>(data: *mut libc::c_void) {
1367    let ptr = data as *mut F;
1368    unsafe { core::mem::drop(Box::from_raw(ptr)) };
1369}
1370
1371/// C trampoline for `sqlite3_update_hook`.
1372///
1373/// # Safety
1374///
1375/// `user_data` must point to a live `F` stored in `RawConnection::update_hook`.
1376/// This is guaranteed because the box is kept alive there and the hook is
1377/// unregistered before the connection is dropped. SQLite forbids the callback
1378/// from modifying the connection, so it cannot re-enter this trampoline, and
1379/// the `&mut` borrow is never aliased (the same contract the commit hook
1380/// relies on).
1381unsafe extern "C" fn update_hook_trampoline<F>(
1382    user_data: *mut libc::c_void,
1383    op: libc::c_int,
1384    db_name: *const libc::c_char,
1385    table_name: *const libc::c_char,
1386    rowid: ffi::sqlite3_int64,
1387) where
1388    F: FnMut(SqliteChangeEvent<'_>),
1389{
1390    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1391        // SAFETY: `user_data` points to a live `F` in `RawConnection::update_hook`.
1392        let hook = unsafe { &mut *(user_data as *mut F) };
1393
1394        // SAFETY: SQLite passes valid C strings. Decode lossily so a non-UTF-8
1395        // name cannot abort the process (matching the trace and wal hooks).
1396        let db_name = unsafe { CStr::from_ptr(db_name) }.to_string_lossy();
1397        let table_name = unsafe { CStr::from_ptr(table_name) }.to_string_lossy();
1398
1399        hook(SqliteChangeEvent {
1400            op: SqliteChangeOp::from_ffi(op),
1401            db_name: &db_name,
1402            table_name: &table_name,
1403            rowid,
1404        });
1405    }));
1406
1407    if result.is_err() {
1408        {
    ::std::io::_eprint(format_args!("Panic in sqlite3_update_hook trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1408u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_update_hook trampoline. ");
1409    }
1410}
1411
1412/// C trampoline for `sqlite3_commit_hook`.
1413///
1414/// # Safety
1415///
1416/// `user_data` must point to a live `F` stored in `RawConnection::commit_hook`.
1417unsafe extern "C" fn commit_hook_trampoline<F>(user_data: *mut libc::c_void) -> libc::c_int
1418where
1419    F: FnMut() -> CommitDecision,
1420{
1421    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1422        // SAFETY: `user_data` points to a live `F` in `RawConnection::commit_hook`.
1423        let f = unsafe { &mut *(user_data as *mut F) };
1424        f()
1425    }));
1426
1427    match result {
1428        Ok(CommitDecision::Rollback) => 1,
1429        Ok(CommitDecision::Proceed) => 0,
1430        Err(_) => {
1431            {
    ::std::io::_eprint(format_args!("Panic in sqlite3_commit_hook trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1431u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_commit_hook trampoline. ");
1432        }
1433    }
1434}
1435
1436/// C trampoline for `sqlite3_rollback_hook`.
1437///
1438/// # Safety
1439///
1440/// `user_data` must point to a live `F` stored in `RawConnection::rollback_hook`.
1441unsafe extern "C" fn rollback_hook_trampoline<F>(user_data: *mut libc::c_void)
1442where
1443    F: FnMut(),
1444{
1445    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1446        // SAFETY: `user_data` points to a live `F` in `RawConnection::rollback_hook`.
1447        let f = unsafe { &mut *(user_data as *mut F) };
1448        f();
1449    }));
1450
1451    if result.is_err() {
1452        {
    ::std::io::_eprint(format_args!("Panic in sqlite3_rollback_hook trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1452u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_rollback_hook trampoline. ");
1453    }
1454}
1455
1456/// C trampoline for `sqlite3_progress_handler`.
1457///
1458/// # Safety
1459///
1460/// `user_data` must point to a live `F` stored in `RawConnection::progress_hook`.
1461unsafe extern "C" fn progress_handler_trampoline<F>(user_data: *mut libc::c_void) -> libc::c_int
1462where
1463    F: FnMut() -> ProgressDecision,
1464{
1465    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1466        // SAFETY: `user_data` points to a live `F` in `RawConnection::progress_hook`.
1467        let f = unsafe { &mut *(user_data as *mut F) };
1468        f()
1469    }));
1470
1471    match result {
1472        Ok(ProgressDecision::Interrupt) => 1,
1473        Ok(ProgressDecision::Continue) => 0,
1474        Err(_) => {
1475            {
    ::std::io::_eprint(format_args!("Panic in sqlite3_progress_handler trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1475u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_progress_handler trampoline. ");
1476        }
1477    }
1478}
1479
1480/// C trampoline for `sqlite3_wal_hook`.
1481///
1482/// # Safety
1483///
1484/// `user_data` must point to a live `F` in `RawConnection::wal_hook`. `db` is
1485/// the `sqlite3` handle that fired the hook, open and unlocked for the duration
1486/// of the call.
1487unsafe extern "C" fn wal_hook_trampoline<F>(
1488    user_data: *mut libc::c_void,
1489    db: *mut ffi::sqlite3,
1490    db_name: *const libc::c_char,
1491    n_pages: libc::c_int,
1492) -> libc::c_int
1493where
1494    F: Fn(&'_ mut BorrowedSqliteConnection, &str, u32),
1495{
1496    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1497        // SAFETY: `user_data` points to a live `F` in `RawConnection::wal_hook`.
1498        let f = unsafe { &*(user_data as *const F) };
1499
1500        // SAFETY: `db_name` is null or a valid C string from SQLite, copied because a DETACH in the hook frees it.
1501        let db_name: String = if db_name.is_null() {
1502            String::new()
1503        } else {
1504            unsafe { CStr::from_ptr(db_name) }
1505                .to_string_lossy()
1506                .into_owned()
1507        };
1508        // SQLite always reports a non-negative page count. Clamp defensively.
1509        let n_pages = u32::try_from(n_pages).unwrap_or(0);
1510
1511        let Some(db) = NonNull::new(db) else {
1512            return;
1513        };
1514
1515        // SAFETY: per the `sqlite3_wal_hook` docs the commit is complete and the
1516        // write-lock released, so `db` may be used. `with_borrowed_connection`
1517        // finalizes statements on return and never closes `db`. The callback is
1518        // `Fn`, so a re-entrant call (a committing write inside it) is sound.
1519        unsafe {
1520            SqliteConnection::with_borrowed_connection(db, |conn| f(conn, &db_name, n_pages));
1521        }
1522    }));
1523
1524    if result.is_err() {
1525        {
    ::std::io::_eprint(format_args!("Panic in sqlite3_wal_hook trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1525u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_wal_hook trampoline. ");
1526    }
1527
1528    ffi::SQLITE_OK
1529}
1530
1531/// C trampoline for `sqlite3_busy_handler`.
1532///
1533/// # Safety
1534///
1535/// `user_data` must point to a live `F` stored in `RawConnection::busy_handler`.
1536unsafe extern "C" fn busy_handler_trampoline<F>(
1537    user_data: *mut libc::c_void,
1538    retry_count: libc::c_int,
1539) -> libc::c_int
1540where
1541    F: FnMut(i32) -> BusyDecision,
1542{
1543    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1544        // SAFETY: `user_data` points to a live `F` in `RawConnection::busy_handler`.
1545        let f = unsafe { &mut *(user_data as *mut F) };
1546        f(retry_count)
1547    }));
1548
1549    match result {
1550        Ok(BusyDecision::Retry) => 1,
1551        Ok(BusyDecision::GiveUp) => 0,
1552        Err(_) => {
1553            {
    ::std::io::_eprint(format_args!("Panic in sqlite3_busy_handler trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1553u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_busy_handler trampoline. ");
1554        }
1555    }
1556}
1557
1558/// C trampoline for `sqlite3_set_authorizer`.
1559///
1560/// # Safety
1561///
1562/// `user_data` must point to a live `F` stored in `RawConnection::authorizer_hook`.
1563unsafe extern "C" fn authorizer_trampoline<F>(
1564    user_data: *mut libc::c_void,
1565    action_code: libc::c_int,
1566    arg1: *const libc::c_char,
1567    arg2: *const libc::c_char,
1568    db_name: *const libc::c_char,
1569    accessor: *const libc::c_char,
1570) -> libc::c_int
1571where
1572    F: FnMut(AuthorizerContext<'_>) -> AuthorizerDecision,
1573{
1574    // A null pointer is `None`, and the borrow only lives inside the `AuthorizerContext` passed to the callback.
1575    fn to_str<'a>(ptr: *const libc::c_char) -> Result<Option<&'a str>, core::str::Utf8Error> {
1576        if ptr.is_null() {
1577            Ok(None)
1578        } else {
1579            // SAFETY: per the `sqlite3_set_authorizer` contract a non-null
1580            // pointer is a valid C string for the duration of the call.
1581            unsafe { CStr::from_ptr(ptr) }.to_str().map(Some)
1582        }
1583    }
1584
1585    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1586        // A name that is not UTF-8 is denied, since mapping it to `None` would read as top-level SQL.
1587        let (Ok(arg1), Ok(arg2), Ok(db_name), Ok(accessor)) = (
1588            to_str(arg1),
1589            to_str(arg2),
1590            to_str(db_name),
1591            to_str(accessor),
1592        ) else {
1593            return AuthorizerDecision::Deny;
1594        };
1595
1596        // SAFETY: `user_data` points to a live `F` in `RawConnection::authorizer_hook`.
1597        let f = unsafe { &mut *(user_data as *mut F) };
1598
1599        f(AuthorizerContext::from_ffi(
1600            action_code,
1601            arg1,
1602            arg2,
1603            db_name,
1604            accessor,
1605        ))
1606    }));
1607
1608    match result {
1609        Ok(decision) => decision.to_ffi(),
1610        Err(_) => {
1611            {
    ::std::io::_eprint(format_args!("Panic in sqlite3_set_authorizer trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1611u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_set_authorizer trampoline. ");
1612        }
1613    }
1614}
1615
1616/// C trampoline for `sqlite3_trace_v2`.
1617///
1618/// # Safety
1619///
1620/// `user_data` must point to a live `F` stored in `RawConnection::trace_hook`.
1621unsafe extern "C" fn trace_trampoline<F>(
1622    event_code: libc::c_uint,
1623    user_data: *mut libc::c_void,
1624    p: *mut libc::c_void,
1625    x: *mut libc::c_void,
1626) -> libc::c_int
1627where
1628    F: FnMut(SqliteTraceEvent<'_>) + Send + 'static,
1629{
1630    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1631        // SAFETY: `user_data` points to a live `F` in `RawConnection::trace_hook`.
1632        let f = unsafe { &mut *(user_data as *mut F) };
1633
1634        // The callback is invoked inside each arm so the lossy `Cow` holding the
1635        // SQL text outlives the `&str` borrow handed to it. `TRACE_STMT`,
1636        // `TRACE_PROFILE`, and `TRACE_ROW` are the `u32`-normalized event codes
1637        // from the `trace` module, so they match `event_code` directly.
1638        match event_code {
1639            TRACE_STMT => {
1640                // p = sqlite3_stmt*, x = const char* (unexpanded SQL).
1641                let stmt_ptr = p as *mut ffi::sqlite3_stmt;
1642                let sql_ptr = x as *const libc::c_char;
1643                if sql_ptr.is_null() {
1644                    return;
1645                }
1646                // SAFETY: a non-null `x` is a valid C string from SQLite. Use a
1647                // lossy conversion so non-UTF-8 SQL cannot abort the process.
1648                let sql = unsafe { CStr::from_ptr(sql_ptr) }.to_string_lossy();
1649                let readonly =
1650                    !stmt_ptr.is_null() && unsafe { ffi::sqlite3_stmt_readonly(stmt_ptr) != 0 };
1651                f(SqliteTraceEvent::Statement {
1652                    sql: &sql,
1653                    readonly,
1654                });
1655            }
1656            TRACE_PROFILE => {
1657                // p = sqlite3_stmt*, x = sqlite3_int64* (nanoseconds).
1658                let stmt_ptr = p as *mut ffi::sqlite3_stmt;
1659                let duration_ns = unsafe {
1660                    // x points to a sqlite3_int64. The duration is non-negative.
1661                    (x as *const ffi::sqlite3_int64).as_ref()
1662                }
1663                .copied()
1664                .unwrap_or_default()
1665                .cast_unsigned();
1666
1667                let readonly =
1668                    !stmt_ptr.is_null() && unsafe { ffi::sqlite3_stmt_readonly(stmt_ptr) != 0 };
1669                let sql_ptr = if stmt_ptr.is_null() {
1670                    core::ptr::null()
1671                } else {
1672                    unsafe { ffi::sqlite3_sql(stmt_ptr) }
1673                };
1674                // SAFETY: when non-null, `sqlite3_sql` returns a valid C string.
1675                let sql = if sql_ptr.is_null() {
1676                    Cow::Borrowed("")
1677                } else {
1678                    unsafe { CStr::from_ptr(sql_ptr) }.to_string_lossy()
1679                };
1680                f(SqliteTraceEvent::Profile {
1681                    sql: &sql,
1682                    duration_ns,
1683                    readonly,
1684                });
1685            }
1686            TRACE_ROW => f(SqliteTraceEvent::Row),
1687            // Unknown or unhandled events are ignored. CLOSE is intentionally
1688            // not handled: diesel removes the trace before closing the
1689            // connection, so it never fires.
1690            _ => {}
1691        }
1692    }));
1693
1694    if result.is_err() {
1695        {
    ::std::io::_eprint(format_args!("Panic in sqlite3_trace_v2 trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1695u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_trace_v2 trampoline. ");
1696    }
1697
1698    0 // Return value is currently unused by SQLite
1699}
1700
1701/// C trampoline for `sqlite3_collation_needed`.
1702///
1703/// # Safety
1704///
1705/// `user_data` must point to a live `F` in
1706/// `RawConnection::collation_needed_hook`. `db` is the connection that fired
1707/// the callback and is open for the duration of the call.
1708unsafe extern "C" fn collation_needed_trampoline<F>(
1709    user_data: *mut libc::c_void,
1710    db: *mut ffi::sqlite3,
1711    e_text_rep: libc::c_int,
1712    name: *const libc::c_char,
1713) where
1714    F: Fn(CollationNeededContext<'_>) -> Option<Collation>,
1715{
1716    let result = crate::util::std_compat::catch_unwind(core::panic::AssertUnwindSafe(|| {
1717        // SAFETY: `user_data` points to a live `F` in
1718        // `RawConnection::collation_needed_hook`.
1719        let f = unsafe { &*(user_data as *const F) };
1720
1721        // SAFETY: when non-null, `name` is a valid C string from SQLite. Use a
1722        // lossy conversion so a pathological name cannot abort the process, and
1723        // map null to "".
1724        let name: Cow<'_, str> = if name.is_null() {
1725            Cow::Borrowed("")
1726        } else {
1727            unsafe { CStr::from_ptr(name) }.to_string_lossy()
1728        };
1729
1730        let Some(db) = NonNull::new(db) else {
1731            return;
1732        };
1733
1734        let ctx = CollationNeededContext {
1735            name: &name,
1736            text_rep: SqliteTextRep::from_ffi(e_text_rep),
1737        };
1738
1739        // SAFETY: `db` is the connection that fired the callback (per
1740        // `sqlite3_collation_needed` contract), and only Diesel uses the borrowed connection.
1741        unsafe {
1742            SqliteConnection::with_borrowed_connection(db, |conn| {
1743                if let Some(collation) = f(ctx) {
1744                    // A failed registration leaves the collation missing, so the statement fails to prepare.
1745                    let _ = conn.inner_mut().register_collation(ctx.name, collation);
1746                }
1747            });
1748        }
1749    }));
1750
1751    if result.is_err() {
1752        {
    ::std::io::_eprint(format_args!("Panic in sqlite3_collation_needed trampoline. If you see this message, please open an issue at https://github.com/diesel-rs/diesel/issues/new.\nSource location: {0}:{1}\n",
            "diesel/src/sqlite/connection/raw.rs", 1752u32));
};
crate::util::std_compat::abort();assert_fail!("Panic in sqlite3_collation_needed trampoline. ");
1753    }
1754}
1755
1756// The update hook tests rely on sqlite calling the registered hook, i.e. on
1757// native code calling back into Rust. That is not supported when running under
1758// miri with a native libsqlite3 (`-Zmiri-native-lib`), so the whole module is
1759// compiled out in that case.
1760#[cfg(all(test, not(miri)))]
1761mod tests {
1762    use super::super::update_hook::SqliteChangeOp;
1763    use super::*;
1764    use std::sync::{Arc, Mutex};
1765
1766    fn test_connection() -> RawConnection {
1767        RawConnection::establish(":memory:").expect("failed to establish :memory: connection")
1768    }
1769
1770    #[test]
1771    fn insert_event_dispatched_directly() {
1772        let mut conn = test_connection();
1773        conn.exec("CREATE TABLE t (id INTEGER PRIMARY KEY)")
1774            .unwrap();
1775
1776        let fired = Arc::new(Mutex::new(Vec::new()));
1777        let f2 = fired.clone();
1778        conn.set_update_hook(move |e| {
1779            f2.lock().unwrap().push((e.op, e.rowid));
1780        });
1781
1782        conn.exec("INSERT INTO t VALUES (1)").unwrap();
1783
1784        let events = fired.lock().unwrap();
1785        assert_eq!(events.len(), 1);
1786        assert_eq!(events[0].0, SqliteChangeOp::Insert);
1787        assert_eq!(events[0].1, 1);
1788    }
1789
1790    #[test]
1791    fn consecutive_inserts_dispatch_immediately() {
1792        let mut conn = test_connection();
1793        conn.exec("CREATE TABLE t (id INTEGER PRIMARY KEY)")
1794            .unwrap();
1795
1796        let fired = Arc::new(Mutex::new(Vec::new()));
1797        let f2 = fired.clone();
1798        conn.set_update_hook(move |e| {
1799            f2.lock().unwrap().push(e.rowid);
1800        });
1801
1802        conn.exec("INSERT INTO t VALUES (2); INSERT INTO t VALUES (3)")
1803            .unwrap();
1804
1805        let events = fired.lock().unwrap();
1806        assert_eq!(events.len(), 2);
1807        assert_eq!(events[0], 2);
1808        assert_eq!(events[1], 3);
1809    }
1810
1811    #[test]
1812    fn update_event() {
1813        let mut conn = test_connection();
1814        conn.exec("CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)")
1815            .unwrap();
1816        conn.exec("INSERT INTO t VALUES (1, 'a')").unwrap();
1817
1818        let fired = Arc::new(Mutex::new(Vec::new()));
1819        let f2 = fired.clone();
1820        conn.set_update_hook(move |e| {
1821            f2.lock().unwrap().push((e.op, e.rowid));
1822        });
1823
1824        conn.exec("UPDATE t SET v = 'b' WHERE id = 1").unwrap();
1825
1826        let events = fired.lock().unwrap();
1827        assert_eq!(events.len(), 1);
1828        assert_eq!(events[0].0, SqliteChangeOp::Update);
1829        assert_eq!(events[0].1, 1);
1830    }
1831
1832    #[test]
1833    fn delete_event() {
1834        let mut conn = test_connection();
1835        conn.exec("CREATE TABLE t (id INTEGER PRIMARY KEY)")
1836            .unwrap();
1837        conn.exec("INSERT INTO t VALUES (1)").unwrap();
1838
1839        let fired = Arc::new(Mutex::new(Vec::new()));
1840        let f2 = fired.clone();
1841        conn.set_update_hook(move |e| {
1842            f2.lock().unwrap().push((e.op, e.rowid));
1843        });
1844
1845        conn.exec("DELETE FROM t WHERE id = 1").unwrap();
1846
1847        let events = fired.lock().unwrap();
1848        assert_eq!(events.len(), 1);
1849        assert_eq!(events[0].0, SqliteChangeOp::Delete);
1850        assert_eq!(events[0].1, 1);
1851    }
1852
1853    #[test]
1854    fn remove_stops_events() {
1855        let mut conn = test_connection();
1856        conn.exec("CREATE TABLE t (id INTEGER PRIMARY KEY)")
1857            .unwrap();
1858
1859        let fired = Arc::new(Mutex::new(Vec::new()));
1860        let f2 = fired.clone();
1861        conn.set_update_hook(move |e| {
1862            f2.lock().unwrap().push(e.rowid);
1863        });
1864
1865        conn.exec("INSERT INTO t VALUES (1)").unwrap();
1866        assert_eq!(fired.lock().unwrap().len(), 1);
1867
1868        conn.remove_update_hook();
1869        conn.exec("INSERT INTO t VALUES (2)").unwrap();
1870        assert_eq!(fired.lock().unwrap().len(), 1); // still 1
1871    }
1872
1873    #[test]
1874    fn replacing_hook_drops_old() {
1875        let mut conn = test_connection();
1876        conn.exec("CREATE TABLE t (id INTEGER PRIMARY KEY)")
1877            .unwrap();
1878
1879        let first = Arc::new(Mutex::new(Vec::new()));
1880        let f1 = first.clone();
1881        conn.set_update_hook(move |e| {
1882            f1.lock().unwrap().push(e.rowid);
1883        });
1884
1885        conn.exec("INSERT INTO t VALUES (1)").unwrap();
1886        assert_eq!(first.lock().unwrap().len(), 1);
1887
1888        // Replacing the hook installs the second closure and drops the first.
1889        let second = Arc::new(Mutex::new(Vec::new()));
1890        let f2 = second.clone();
1891        conn.set_update_hook(move |e| {
1892            f2.lock().unwrap().push(e.rowid);
1893        });
1894
1895        conn.exec("INSERT INTO t VALUES (2)").unwrap();
1896        assert_eq!(first.lock().unwrap().len(), 1); // first no longer fires
1897        assert_eq!(*second.lock().unwrap(), vec![2]);
1898    }
1899
1900    #[test]
1901    fn drop_does_not_panic() {
1902        let mut conn = test_connection();
1903        conn.exec("CREATE TABLE t (id INTEGER PRIMARY KEY)")
1904            .unwrap();
1905
1906        conn.set_update_hook(|_| {});
1907        conn.exec("INSERT INTO t VALUES (1)").unwrap();
1908        drop(conn);
1909        // If we get here, drop succeeded without panic.
1910    }
1911}