Skip to main content

diesel/sqlite/connection/
mod.rs

1#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2extern crate libsqlite3_sys as ffi;
3
4#[cfg(all(target_family = "wasm", target_os = "unknown"))]
5use sqlite_wasm_rs as ffi;
6
7mod attach;
8pub mod authorizer;
9mod bind_collector;
10pub(super) mod borrowed_connection;
11mod collation_needed;
12mod db_config;
13mod functions;
14mod hooks;
15mod limits;
16#[cfg(all(
17    test,
18    feature = "std",
19    not(all(target_family = "wasm", target_os = "unknown")),
20    not(miri)
21))]
22#[allow(unsafe_code)]
23mod oom_test_support;
24mod owned_row;
25mod pragmas;
26mod raw;
27mod row;
28mod serialized_database;
29pub(in crate::sqlite) mod sqlite_blob;
30mod sqlite_value;
31mod statement_iterator;
32mod stmt;
33mod trace;
34mod update_hook;
35
36pub use self::authorizer::{AuthorizerContext, AuthorizerDecision};
37pub use self::bind_collector::SqliteBindCollector;#[diesel_derives::__diesel_public_if(
38    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
39)]
40pub(in crate::sqlite) use self::bind_collector::SqliteBindCollector;
41pub use self::bind_collector::SqliteBindValue;
42#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
43pub use self::bind_collector::{OwnedSqliteBindValue, SqliteBindCollectorData, SqliteBindValueRef};
44pub use self::collation_needed::{CollationNeededContext, SqliteTextRep};
45pub use self::limits::SqliteLimit;
46pub use self::pragmas::{AutoVacuumMode, WalCheckpointMode, WalCheckpointOutcome};
47use self::raw::RawConnection;
48pub use self::serialized_database::SerializedDatabase;
49pub use self::sqlite_value::SqliteValue;
50use self::statement_iterator::*;
51use self::stmt::{Statement, StatementUse};
52pub use self::trace::{SqliteTraceEvent, SqliteTraceFlags};
53pub use self::update_hook::{
54    SqliteChangeEvent, SqliteChangeOp, SqliteChangeOps, SqliteUpdateRouter,
55};
56use super::{BorrowedSqliteConnection, SqliteAggregateFunction};
57use crate::connection::instrumentation::{DynInstrumentation, StrQueryHelper};
58use crate::connection::statement_cache::StatementCache;
59use crate::connection::*;
60use crate::expression::QueryMetadata;
61use crate::query_builder::*;
62use crate::result::*;
63use crate::sql_types::TypeMetadata;
64use crate::sqlite::Sqlite;
65#[cfg(not(miri))]
66use alloc::string::String;
67use core::ffi as libc;
68use core::num::NonZeroI64;
69
70/// Connections for the SQLite backend. Unlike other backends, SQLite supported
71/// connection URLs are:
72///
73/// - File paths (`test.db`)
74/// - [URIs](https://sqlite.org/uri.html) (`file://test.db`)
75/// - Special identifiers (`:memory:`)
76///
77/// SQLite has no SQLSTATE codes, so
78/// [`DatabaseErrorInformation::sqlstate`] always returns `None`.
79///
80/// # Supported loading model implementations
81///
82/// * [`DefaultLoadingMode`]
83///
84/// As `SqliteConnection` only supports a single loading mode implementation,
85/// it is **not required** to explicitly specify a loading mode
86/// when calling [`RunQueryDsl::load_iter()`] or [`LoadConnection::load`]
87///
88/// [`RunQueryDsl::load_iter()`]: crate::query_dsl::RunQueryDsl::load_iter
89///
90/// ## DefaultLoadingMode
91///
92/// `SqliteConnection` only supports a single loading mode, which loads
93/// values row by row from the result set.
94///
95/// ```rust,dejadoc
96/// # include!("../../doctest_setup.rs");
97/// #
98/// # // Reading the query result requires reading memory allocated by the
99/// # // native sqlite library, which miri cannot track provenance for.
100/// # #[cfg(miri)]
101/// # fn main() {}
102/// # #[cfg(not(miri))]
103/// # fn main() {
104/// #     run_test().unwrap();
105/// # }
106/// #
107/// # fn run_test() -> QueryResult<()> {
108/// #     use schema::users;
109/// #     let connection = &mut establish_connection();
110/// use diesel::connection::DefaultLoadingMode;
111/// {
112///     // scope to restrict the lifetime of the iterator
113///     let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
114///
115///     for r in iter1 {
116///         let (id, name) = r?;
117///         println!("Id: {} Name: {}", id, name);
118///     }
119/// }
120///
121/// // works without specifying the loading mode
122/// let iter2 = users::table.load_iter::<(i32, String), _>(connection)?;
123///
124/// for r in iter2 {
125///     let (id, name) = r?;
126///     println!("Id: {} Name: {}", id, name);
127/// }
128/// #   Ok(())
129/// # }
130/// ```
131///
132/// This mode does **not support** creating
133/// multiple iterators using the same connection.
134///
135/// ```compile_fail,dejadoc
136/// # include!("../../doctest_setup.rs");
137/// #
138/// # fn main() {
139/// #     run_test().unwrap();
140/// # }
141/// #
142/// # fn run_test() -> QueryResult<()> {
143/// #     use schema::users;
144/// #     let connection = &mut establish_connection();
145/// use diesel::connection::DefaultLoadingMode;
146///
147/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
148/// let iter2 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
149///
150/// for r in iter1 {
151///     let (id, name) = r?;
152///     println!("Id: {} Name: {}", id, name);
153/// }
154///
155/// for r in iter2 {
156///     let (id, name) = r?;
157///     println!("Id: {} Name: {}", id, name);
158/// }
159/// #   Ok(())
160/// # }
161/// ```
162///
163/// # Concurrency
164///
165/// By default, when running into a database lock, the operation will abort with a
166/// `Database locked` error. However, it's possible to configure it for greater concurrency,
167/// trading latency for not having to deal with retries yourself.
168///
169/// You can use this example as blue-print for which statements to run after establishing a connection.
170/// It is **important** to run each `PRAGMA` in a single statement to make sure all of them apply
171/// correctly. In addition the order of the `PRAGMA` statements is relevant to prevent timeout
172/// issues for the later `PRAGMA` statements.
173///
174/// ```rust
175/// # include!("../../doctest_setup.rs");
176/// #
177/// # fn main() {
178/// #     run_test().unwrap();
179/// # }
180/// #
181/// # fn run_test() -> QueryResult<()> {
182/// #     use schema::users;
183/// use diesel::connection::SimpleConnection;
184/// use diesel::sqlite::WalCheckpointMode;
185/// let conn = &mut establish_connection();
186/// // see https://fractaledmind.github.io/2023/09/07/enhancing-rails-sqlite-fine-tuning/
187/// // sleep if the database is busy, this corresponds to up to 2 seconds sleeping time.
188/// conn.batch_execute("PRAGMA busy_timeout = 2000;")?;
189/// // better write-concurrency
190/// conn.batch_execute("PRAGMA journal_mode = WAL;")?;
191/// // fsync only in critical moments
192/// conn.batch_execute("PRAGMA synchronous = NORMAL;")?;
193/// // write WAL changes back every 1000 pages, for an in average 1MB WAL file.
194/// // May affect readers if number is increased
195/// conn.batch_execute("PRAGMA wal_autocheckpoint = 1000;")?;
196/// // free some space by truncating possibly massive WAL files from the last run
197/// conn.wal_checkpoint(None, WalCheckpointMode::Truncate)?;
198/// #   Ok(())
199/// # }
200/// ```
201#[allow(missing_debug_implementations)]
202#[cfg(feature = "__sqlite-shared")]
203pub struct SqliteConnection {
204    // statement_cache needs to be before raw_connection
205    // otherwise we will get errors about open statements before closing the
206    // connection itself
207    statement_cache: StatementCache<Sqlite, Statement>,
208    raw_connection: RawConnection,
209    transaction_state: AnsiTransactionManager,
210    // this exists for the sole purpose of implementing `WithMetadataLookup` trait
211    // and avoiding static mut which will be deprecated in 2024 edition
212    metadata_lookup: (),
213    instrumentation: DynInstrumentation,
214}
215
216// This relies on the invariant that RawConnection or Statement are never
217// leaked. If a reference to one of those was held on a different thread, this
218// would not be thread safe.
219#[allow(unsafe_code)]
220unsafe impl Send for SqliteConnection {}
221
222impl SimpleConnection for SqliteConnection {
223    fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
224        self.instrumentation
225            .on_connection_event(InstrumentationEvent::StartQuery {
226                query: &StrQueryHelper::new(query),
227            });
228        let resp = self.raw_connection.exec(query);
229        self.instrumentation
230            .on_connection_event(InstrumentationEvent::FinishQuery {
231                query: &StrQueryHelper::new(query),
232                error: resp.as_ref().err(),
233            });
234        if resp.is_err() && self.raw_connection.is_autocommit() {
235            // SQLite ends the transaction on some failures, e.g. an aborting commit hook.
236            self.transaction_state.status = TransactionManagerStatus::Valid(Default::default());
237        }
238        resp
239    }
240}
241
242impl ConnectionSealed for SqliteConnection {}
243
244impl Connection for SqliteConnection {
245    type Backend = Sqlite;
246    type TransactionManager = AnsiTransactionManager;
247
248    /// Establish a connection to the database specified by `database_url`.
249    ///
250    /// See [SqliteConnection] for supported `database_url`.
251    ///
252    /// If the database does not exist, this method will try to
253    /// create a new database and then establish a connection to it.
254    ///
255    /// ## WASM support
256    ///
257    /// If you plan to use this connection type on the `wasm32-unknown-unknown` target please
258    /// make sure to read the following notes:
259    ///
260    /// * The database is stored in memory by default.
261    /// * With `sqlite-wasm-rs` 0.6, enable its `wasm-bindgen` feature to use the
262    ///   built-in host functions, or provide your own.
263    /// * Persistent VFS (Virtual File Systems) is optional,
264    ///   see <https://github.com/Spxg/sqlite-wasm-rs> for details
265    fn establish(database_url: &str) -> ConnectionResult<Self> {
266        let mut instrumentation = DynInstrumentation::default_instrumentation();
267        instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
268            url: database_url,
269        });
270
271        let establish_result = Self::establish_inner(database_url);
272        instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
273            url: database_url,
274            error: establish_result.as_ref().err(),
275        });
276        let mut conn = establish_result?;
277        conn.instrumentation = instrumentation;
278        Ok(conn)
279    }
280
281    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
282    where
283        T: QueryFragment<Self::Backend> + QueryId,
284    {
285        let statement_use = self.prepared_query(source)?;
286        statement_use.run().and_then(|_| {
287            self.raw_connection
288                .rows_affected_by_last_query()
289                .map_err(Error::DeserializationError)
290        })
291    }
292
293    fn transaction_state(&mut self) -> &mut AnsiTransactionManager
294    where
295        Self: Sized,
296    {
297        &mut self.transaction_state
298    }
299
300    fn instrumentation(&mut self) -> &mut dyn Instrumentation {
301        &mut *self.instrumentation
302    }
303
304    fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
305        self.instrumentation = instrumentation.into();
306    }
307
308    fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
309        self.statement_cache.set_cache_size(size);
310    }
311}
312
313impl LoadConnection<DefaultLoadingMode> for SqliteConnection {
314    type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>;
315    type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>;
316
317    fn load<'conn, 'query, T>(
318        &'conn mut self,
319        source: T,
320    ) -> QueryResult<Self::Cursor<'conn, 'query>>
321    where
322        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
323        Self::Backend: QueryMetadata<T::SqlType>,
324    {
325        let statement = self.prepared_query(source)?;
326
327        Ok(StatementIterator::new(statement))
328    }
329}
330
331impl WithMetadataLookup for SqliteConnection {
332    fn metadata_lookup(&mut self) -> &mut <Sqlite as TypeMetadata>::MetadataLookup {
333        &mut self.metadata_lookup
334    }
335}
336
337#[cfg(feature = "r2d2")]
338impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
339    fn ping(&mut self) -> QueryResult<()> {
340        use crate::RunQueryDsl;
341
342        crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
343    }
344
345    fn is_broken(&mut self) -> bool {
346        AnsiTransactionManager::is_broken_transaction_manager(self)
347    }
348}
349
350impl MultiConnectionHelper for SqliteConnection {
351    fn to_any<'a>(
352        lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
353    ) -> &mut (dyn core::any::Any + 'a) {
354        lookup
355    }
356
357    fn from_any(
358        lookup: &mut dyn core::any::Any,
359    ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
360        lookup.downcast_mut()
361    }
362}
363
364/// The decision returned by an [`on_commit`](SqliteConnection::on_commit)
365/// callback, controlling whether a pending commit completes.
366#[derive(#[automatically_derived]impl ::core::fmt::Debug for CommitDecision {
    #[inline]
    #[rustc_trivial_field_reads]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                CommitDecision::Proceed => "Proceed",
                CommitDecision::Rollback => "Rollback",
            })
    }
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for CommitDecision {
}
#[automatically_derived]impl ::core::clone::Clone for CommitDecision {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for CommitDecision { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    CommitDecision {
}
#[automatically_derived]impl ::core::cmp::PartialEq for CommitDecision {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for CommitDecision { }Eq)]
367pub enum CommitDecision {
368    /// Let the commit proceed normally.
369    Proceed,
370    /// Convert the commit into a rollback.
371    Rollback,
372}
373
374/// The decision returned by an [`on_progress`](SqliteConnection::on_progress)
375/// callback, controlling whether a long-running query keeps executing.
376#[derive(#[automatically_derived]impl ::core::fmt::Debug for ProgressDecision {
    #[inline]
    #[rustc_trivial_field_reads]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                ProgressDecision::Continue => "Continue",
                ProgressDecision::Interrupt => "Interrupt",
            })
    }
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for ProgressDecision {
}
#[automatically_derived]impl ::core::clone::Clone for ProgressDecision {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for ProgressDecision { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    ProgressDecision {
}
#[automatically_derived]impl ::core::cmp::PartialEq for ProgressDecision {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for ProgressDecision { }Eq)]
377pub enum ProgressDecision {
378    /// Let the query continue executing.
379    Continue,
380    /// Interrupt the query (causes `SQLITE_INTERRUPT`).
381    Interrupt,
382}
383
384/// The decision returned by an [`on_busy`](SqliteConnection::on_busy)
385/// callback when the database is locked.
386#[derive(#[automatically_derived]impl ::core::fmt::Debug for BusyDecision {
    #[inline]
    #[rustc_trivial_field_reads]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                BusyDecision::Retry => "Retry",
                BusyDecision::GiveUp => "GiveUp",
            })
    }
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for BusyDecision {
}
#[automatically_derived]impl ::core::clone::Clone for BusyDecision {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for BusyDecision { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    BusyDecision {
}
#[automatically_derived]impl ::core::cmp::PartialEq for BusyDecision {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for BusyDecision { }Eq)]
387pub enum BusyDecision {
388    /// Retry the locked operation.
389    Retry,
390    /// Give up, returning `SQLITE_BUSY` to the caller.
391    GiveUp,
392}
393
394impl SqliteConnection {
395    /// Returns the version of the SQLite library this connection runs on.
396    ///
397    /// # Example
398    ///
399    /// ```rust
400    /// # include!("../../doctest_setup.rs");
401    /// use diesel::connection::DatabaseVersion;
402    /// #
403    /// # fn main() {
404    /// #     let conn = &mut establish_connection();
405    /// let supports_jsonb = conn.version() >= DatabaseVersion::new(3, 45, 0);
406    /// # }
407    /// ```
408    pub fn version(&self) -> DatabaseVersion {
409        let version = raw::library_version_number();
410        DatabaseVersion::new(
411            version / 1_000_000,
412            version / 1_000 % 1_000,
413            version % 1_000,
414        )
415    }
416
417    /// Run a transaction with `BEGIN IMMEDIATE`
418    ///
419    /// This method will return an error if a transaction is already open.
420    ///
421    /// # Example
422    ///
423    /// ```rust
424    /// # include!("../../doctest_setup.rs");
425    /// #
426    /// # fn main() {
427    /// #     run_test().unwrap();
428    /// # }
429    /// #
430    /// # fn run_test() -> QueryResult<()> {
431    /// #     let mut conn = SqliteConnection::establish(":memory:").unwrap();
432    /// conn.immediate_transaction(|conn| {
433    ///     // Do stuff in a transaction
434    ///     Ok(())
435    /// })
436    /// # }
437    /// ```
438    pub fn immediate_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
439    where
440        F: FnOnce(&mut Self) -> Result<T, E>,
441        E: From<Error>,
442    {
443        self.transaction_sql(f, "BEGIN IMMEDIATE")
444    }
445
446    /// Run a transaction with `BEGIN EXCLUSIVE`
447    ///
448    /// This method will return an error if a transaction is already open.
449    ///
450    /// # Example
451    ///
452    /// ```rust
453    /// # include!("../../doctest_setup.rs");
454    /// #
455    /// # fn main() {
456    /// #     run_test().unwrap();
457    /// # }
458    /// #
459    /// # fn run_test() -> QueryResult<()> {
460    /// #     let mut conn = SqliteConnection::establish(":memory:").unwrap();
461    /// conn.exclusive_transaction(|conn| {
462    ///     // Do stuff in a transaction
463    ///     Ok(())
464    /// })
465    /// # }
466    /// ```
467    pub fn exclusive_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
468    where
469        F: FnOnce(&mut Self) -> Result<T, E>,
470        E: From<Error>,
471    {
472        self.transaction_sql(f, "BEGIN EXCLUSIVE")
473    }
474
475    /// Returns the rowid of the most recent successful INSERT on this connection.
476    ///
477    /// Returns `None` if no successful INSERT into a rowid table has been performed
478    /// on this connection, and `Some(rowid)` otherwise.
479    ///
480    /// See [the SQLite documentation](https://www.sqlite.org/c3ref/last_insert_rowid.html)
481    /// for details.
482    ///
483    /// # Caveats
484    /// - Inserts into `WITHOUT ROWID` tables are not recorded
485    /// - Failed `INSERT` (constraint violations) do not change the value
486    /// - `INSERT OR REPLACE` always updates the value
487    /// - Within triggers, returns the rowid of the trigger's INSERT;
488    ///   reverts after the trigger completes
489    ///
490    /// # Example
491    /// ```rust
492    /// # include!("../../doctest_setup.rs");
493    /// # fn main() {
494    /// #     run_test().unwrap();
495    /// # }
496    /// # fn run_test() -> QueryResult<()> {
497    /// use core::num::NonZeroI64;
498    /// use diesel::connection::SimpleConnection;
499    /// let conn = &mut SqliteConnection::establish(":memory:").unwrap();
500    /// conn.batch_execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")?;
501    /// conn.batch_execute("INSERT INTO users (name) VALUES ('Sean')")?;
502    /// let rowid = conn.last_insert_rowid();
503    /// assert_eq!(rowid, NonZeroI64::new(1));
504    /// conn.batch_execute("INSERT INTO users (name) VALUES ('Tess')")?;
505    /// let rowid = conn.last_insert_rowid();
506    /// assert_eq!(rowid, NonZeroI64::new(2));
507    /// # Ok(())
508    /// # }
509    /// ```
510    pub fn last_insert_rowid(&self) -> Option<NonZeroI64> {
511        NonZeroI64::new(self.raw_connection.last_insert_rowid())
512    }
513
514    fn transaction_sql<T, E, F>(&mut self, f: F, sql: &str) -> Result<T, E>
515    where
516        F: FnOnce(&mut Self) -> Result<T, E>,
517        E: From<Error>,
518    {
519        AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?;
520        match f(&mut *self) {
521            Ok(value) => {
522                AnsiTransactionManager::commit_transaction(&mut *self)?;
523                Ok(value)
524            }
525            Err(e) => {
526                AnsiTransactionManager::rollback_transaction(&mut *self)?;
527                Err(e)
528            }
529        }
530    }
531
532    fn prepared_query<'conn, 'query, T>(
533        &'conn mut self,
534        source: T,
535    ) -> QueryResult<StatementUse<'conn, 'query>>
536    where
537        T: QueryFragment<Sqlite> + QueryId + 'query,
538    {
539        self.instrumentation
540            .on_connection_event(InstrumentationEvent::StartQuery {
541                query: &crate::debug_query(&source),
542            });
543        let raw_connection = &self.raw_connection;
544        let cache = &mut self.statement_cache;
545        let statement = match cache.cached_statement(
546            &source,
547            &Sqlite,
548            &[],
549            raw_connection,
550            Statement::prepare,
551            &mut *self.instrumentation,
552        ) {
553            Ok(statement) => statement,
554            Err(e) => {
555                self.instrumentation
556                    .on_connection_event(InstrumentationEvent::FinishQuery {
557                        query: &crate::debug_query(&source),
558                        error: Some(&e),
559                    });
560
561                return Err(e);
562            }
563        };
564
565        StatementUse::bind(statement, source, &mut *self.instrumentation)
566    }
567
568    /// Serialize the current SQLite database into a byte buffer.
569    ///
570    /// The serialized data is identical to the data that would be written to disk if the database
571    /// was saved in a file.
572    ///
573    /// # Returns
574    ///
575    /// This function returns a [`SerializedDatabase`] wrapping the serialized
576    /// bytes. If SQLite fails to allocate the buffer holding them, the failure
577    /// is reported by [`SerializedDatabase::try_as_slice`].
578    pub fn serialize_database_to_buffer(&mut self) -> SerializedDatabase {
579        self.raw_connection.serialize()
580    }
581
582    /// Deserialize an SQLite database from a byte buffer.
583    ///
584    /// This function takes a byte slice and attempts to deserialize it into a SQLite database.
585    /// If successful, the database is loaded into the connection. If the deserialization fails,
586    /// an error is returned.
587    ///
588    /// The database is opened in READONLY mode.
589    ///
590    /// # Example
591    ///
592    /// ```no_run
593    /// # use diesel::sqlite::SerializedDatabase;
594    /// # use diesel::sqlite::SqliteConnection;
595    /// # use diesel::result::QueryResult;
596    /// # use diesel::sql_query;
597    /// # use diesel::Connection;
598    /// # use diesel::RunQueryDsl;
599    /// # fn main() {
600    /// let connection = &mut SqliteConnection::establish(":memory:").unwrap();
601    ///
602    /// sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
603    ///     .execute(connection).unwrap();
604    /// sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
605    ///     .execute(connection).unwrap();
606    ///
607    /// // Serialize the database to a byte vector
608    /// let serialized_db: SerializedDatabase = connection.serialize_database_to_buffer();
609    ///
610    /// // Create a new in-memory SQLite database
611    /// let connection = &mut SqliteConnection::establish(":memory:").unwrap();
612    ///
613    /// // Deserialize the byte vector into the new database
614    /// connection.deserialize_readonly_database_from_buffer(serialized_db.try_as_slice().unwrap()).unwrap();
615    /// #
616    /// # }
617    /// ```
618    // TODO: Diesel 3.0 This signature needs to change, we want to expose more options (schema name, readonly)
619    // and also ensure that this is not as unsafe as the current construct anymore. Maybe just accept a owned buffer or static pointer
620    // only instead? (So `Cow<'static, [u8]>`?)
621    #[allow(unsafe_code)]
622    pub fn deserialize_readonly_database_from_buffer(&mut self, data: &[u8]) -> QueryResult<()> {
623        self.raw_connection.deserialize(data)
624    }
625
626    /// Provides temporary access to the raw SQLite database connection handle.
627    ///
628    /// This method provides a way to access the underlying `sqlite3` pointer,
629    /// enabling direct use of the SQLite C API for advanced features that
630    /// Diesel does not wrap, such as the [session extension](https://www.sqlite.org/sessionintro.html),
631    /// [hooks](https://www.sqlite.org/c3ref/update_hook.html), or other advanced APIs.
632    ///
633    /// # Why Diesel Doesn't Wrap These APIs
634    ///
635    /// Certain SQLite features, such as the session extension, are **optional** and only
636    /// available when SQLite is compiled with specific flags (e.g., `-DSQLITE_ENABLE_SESSION`
637    /// and `-DSQLITE_ENABLE_PREUPDATE_HOOK` for sessions). These compile-time options determine
638    /// whether the corresponding C API functions exist in the SQLite library's ABI.
639    ///
640    /// Because Diesel must work with any SQLite library at runtime—including system-provided
641    /// libraries that may lack these optional features—it **cannot safely provide wrappers**
642    /// for APIs that may or may not exist. Doing so would either:
643    ///
644    /// - Cause **linker errors** at compile time if the user's `libsqlite3-sys` wasn't compiled
645    ///   with the required flags, or
646    /// - Cause **undefined behavior** at runtime if Diesel called functions that don't exist
647    ///   in the linked library.
648    ///
649    /// While feature gates could theoretically solve this problem, Diesel already has an
650    /// extensive API surface with many existing feature combinations. Each new feature gate
651    /// adds a **combinatorial explosion** of test configurations that must be validated,
652    /// making the library increasingly difficult to maintain. Therefore, exposing the raw
653    /// connection is the preferred approach for niche SQLite features.
654    ///
655    /// By exposing the raw connection handle, Diesel allows users who **know** they have
656    /// access to a properly configured SQLite build to use these advanced features directly
657    /// through their own FFI bindings.
658    ///
659    /// # Safety
660    ///
661    /// This method is marked `unsafe` because improper use of the raw connection handle
662    /// can lead to undefined behavior. The caller must ensure that:
663    ///
664    /// - The connection handle is **not closed** during the callback.
665    /// - The connection handle is **not stored** beyond the callback's scope.
666    /// - Concurrent access rules are respected (SQLite connections are not thread-safe
667    ///   unless using serialized threading mode).
668    /// - **Transaction state is not modified** — do not execute `BEGIN`, `COMMIT`,
669    ///   `ROLLBACK`, or `SAVEPOINT` statements via the raw handle. Diesel's
670    ///   [`AnsiTransactionManager`] tracks transaction nesting internally, and
671    ///   bypassing it will cause Diesel's view of the transaction state to diverge
672    ///   from SQLite's actual state.
673    /// - **Diesel's prepared statements are not disturbed** — do not call
674    ///   `sqlite3_finalize()` or `sqlite3_reset()` on statements that belong to
675    ///   Diesel's `StatementCache`. Doing so will cause use-after-free or
676    ///   double-free when Diesel later accesses those statements.
677    ///
678    /// [`AnsiTransactionManager`]: crate::connection::AnsiTransactionManager
679    ///
680    /// # Example
681    ///
682    /// ```rust
683    /// use diesel::sqlite::SqliteConnection;
684    /// use diesel::Connection;
685    ///
686    /// let mut conn = SqliteConnection::establish(":memory:").unwrap();
687    ///
688    /// // SAFETY: We do not close or store the connection handle,
689    /// // and we do not modify Diesel-managed state (transactions, cached statements).
690    /// let is_valid = unsafe {
691    ///     conn.with_raw_connection(|raw_conn| {
692    ///         // The raw connection pointer can be passed to SQLite C API functions
693    ///         // from your own `libsqlite3-sys` (native) or `sqlite-wasm-rs` (WASM)
694    ///         // dependency — for example, `sqlite3_get_autocommit(raw_conn)` or
695    ///         // `sqlite3session_create(raw_conn, ...)`.
696    ///         !raw_conn.is_null()
697    ///     })
698    /// };
699    /// assert!(is_valid);
700    /// ```
701    ///
702    /// # Platform Notes
703    ///
704    /// This method works identically on both native and WASM targets. However,
705    /// you must depend on the appropriate FFI crate for your target:
706    ///
707    /// - **Native**: Add `libsqlite3-sys` as a dependency
708    /// - **WASM** (`wasm32-unknown-unknown`): Add `sqlite-wasm-rs` as a dependency
709    ///
710    /// Both crates expose a compatible `sqlite3` type that can be used with the
711    /// pointer returned by this method.
712    #[allow(unsafe_code)]
713    pub unsafe fn with_raw_connection<R, F>(&mut self, f: F) -> R
714    where
715        F: FnOnce(*mut ffi::sqlite3) -> R,
716    {
717        f(self.raw_connection.internal_connection.as_ptr())
718    }
719
720    /// Runs `f` with a borrowed `SqliteConnection` wrapping `db`, giving SQLite
721    /// callbacks the full connection API. Statements prepared during `f` are
722    /// finalized on return, but `db` is left open, since SQLite owns it.
723    ///
724    /// # Safety
725    ///
726    /// `db` must be a valid `sqlite3` handle that stays open for the duration
727    /// of the call.
728    #[allow(unsafe_code)]
729    pub(crate) unsafe fn with_borrowed_connection<R>(
730        db: core::ptr::NonNull<ffi::sqlite3>,
731        f: impl FnOnce(&'_ mut BorrowedSqliteConnection) -> R,
732    ) -> R {
733        let mut conn = BorrowedSqliteConnection::new(RawConnection::from_ptr(db));
734
735        let result = f(&mut conn);
736
737        unsafe {
738            // SAFETY: We don't move out the connection, we only call a function
739            // that accesses the underlying state
740
741            // The borrowed connection is discarded without committing or rolling
742            // back, so a transaction left open by `f` would leak onto the handle.
743            if !#[allow(non_exhaustive_omitted_patterns)] match AnsiTransactionManager::transaction_manager_status_mut(conn.inner_mut()).transaction_depth()
            {
            Ok(None) => true,
            _ => false,
        } {
    {
        ::core::panicking::panic_fmt(format_args!("callback must not leave an open transaction on the borrowed connection"));
    }
};assert!(
744                matches!(
745                    AnsiTransactionManager::transaction_manager_status_mut(conn.inner_mut())
746                        .transaction_depth(),
747                    Ok(None)
748                ),
749                "callback must not leave an open transaction on the borrowed connection"
750            );
751        }
752
753        result
754    }
755
756    fn register_diesel_sql_functions(&self) -> QueryResult<()> {
757        // When running under miri with a native libsqlite3 (see
758        // `-Zmiri-native-lib`), native code is not allowed to call back into
759        // Rust. Registering `diesel_manage_updated_at` hands a Rust function
760        // pointer to sqlite, whose `xDestroy` callback is invoked by native
761        // code when the connection is closed, which miri rejects. As miri is
762        // only used to run a subset of the test suite, we skip the registration
763        // entirely in that case.
764        #[cfg(miri)]
765        return Ok(());
766
767        #[cfg(not(miri))]
768        {
769            use crate::sql_types::{Integer, Text};
770
771            // This function has side effects (creates triggers), so it should not
772            // be deterministic. We use DIRECTONLY to prevent it from being called
773            // from malicious schema objects in untrusted databases.
774            self.raw_connection
775                .register_sql_function::<_, i32, Integer>(
776                    "diesel_manage_updated_at",
777                    1,
778                    crate::sqlite::SqliteFunctionBehavior::DIRECTONLY,
779                    |conn, args| {
780                        let table_name: String = functions::build_sql_function_args::<Text, _>(
781                            args,
782                            conn.internal_connection,
783                        )?;
784                        // The template wraps every use in `"`, so doubling embedded
785                        // quotes keeps the argument a single identifier.
786                        let sql = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("CREATE TRIGGER \"__diesel_manage_updated_at_{0}\"\nAFTER UPDATE ON \"{0}\"\nFOR EACH ROW WHEN\n  old.updated_at IS NULL AND\n  new.updated_at IS NULL OR\n  old.updated_at == new.updated_at\nBEGIN\n  UPDATE \"{0}\"\n  SET updated_at = CURRENT_TIMESTAMP\n  WHERE ROWID = new.ROWID;\nEND\n",
                table_name.replace('"', "\"\"")))
    })alloc::format!(
787                            include_str!("diesel_manage_updated_at.sql"),
788                            table_name = table_name.replace('"', "\"\"")
789                        );
790                        Statement::prepare(
791                            conn,
792                            &sql,
793                            crate::connection::statement_cache::PrepareForCache::No,
794                            &[],
795                        )?
796                        .run()?;
797                        Ok(0) // have to return *something*
798                    },
799                )
800        }
801    }
802
803    fn establish_inner(database_url: &str) -> Result<SqliteConnection, ConnectionError> {
804        use crate::result::ConnectionError::CouldntSetupConfiguration;
805        let raw_connection = RawConnection::establish(database_url)?;
806        let conn = Self {
807            statement_cache: StatementCache::new(),
808            raw_connection,
809            transaction_state: AnsiTransactionManager::default(),
810            metadata_lookup: (),
811            instrumentation: DynInstrumentation::none(),
812        };
813        conn.register_diesel_sql_functions()
814            .map_err(CouldntSetupConfiguration)?;
815        // Builds with `SQLITE_ENABLE_FTS3_TOKENIZER` let SQL text pass `fts3_tokenizer()` a pointer to call, and SQLite before 3.12 has no switch.
816        let _ = conn
817            .raw_connection
818            .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, false);
819        Ok(conn)
820    }
821}
822
823fn error_message(err_code: libc::c_int) -> &'static str {
824    ffi::code_to_str(err_code)
825}
826
827/// Leaves a cached statement unreset after a failed step, so finalizing it fails.
828#[cfg(all(test, not(miri)))]
829#[allow(unsafe_code)]
830pub(in crate::sqlite) fn leak_failed_cursor(conn: &mut SqliteConnection) {
831    use crate::connection::SimpleConnection;
832    use crate::query_builder::{AstPass, QueryFragment, QueryId};
833
834    /// Overflows `abs` on its second row. Zero-sized, so the statement owns no heap memory.
835    struct OverflowQuery;
836
837    impl QueryId for OverflowQuery {
838        type QueryId = Self;
839        const HAS_STATIC_QUERY_ID: bool = true;
840    }
841
842    impl QueryFragment<Sqlite> for OverflowQuery {
843        fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
844            pass.push_sql("SELECT abs(n) FROM overflow_numbers ORDER BY id");
845            Ok(())
846        }
847    }
848
849    // `Box::new` doesn't allocate for a zero-sized query, so `mem::forget` below leaks nothing.
850    const _: () = assert!(core::mem::size_of::<OverflowQuery>() == 0);
851
852    conn.batch_execute(
853        "CREATE TEMP TABLE IF NOT EXISTS overflow_numbers (id INTEGER PRIMARY KEY, n BIGINT);
854         INSERT OR IGNORE INTO overflow_numbers VALUES (1, 1), (2, -9223372036854775808);",
855    )
856    .unwrap();
857    let mut stmt = conn.prepared_query(OverflowQuery).unwrap();
858    // SAFETY: `first_step = true` clears the cached column names, so no stale pointer survives.
859    let first = unsafe { stmt.step(true) };
860    assert!(matches!(first, Ok(true)));
861    // A failed first step resets the statement, so the overflow is on the second row.
862    // SAFETY: `first_step = true` clears the cached column names, so no stale pointer survives.
863    let second = unsafe { stmt.step(true) };
864    assert!(second.is_err());
865    // The query is cached (static query id) and binds nothing, so skipping the drop only
866    // skips the reset: the cache keeps the failed statement and no memory is leaked.
867    core::mem::forget(stmt);
868}
869
870#[cfg(test)]
871mod tests {
872    use super::*;
873    use crate::dsl::sql;
874    use crate::prelude::*;
875    use crate::sql_types::{Integer, Text};
876    #[cfg(not(miri))]
877    use crate::test_helpers::format_error;
878
879    fn connection() -> SqliteConnection {
880        SqliteConnection::establish(":memory:").unwrap()
881    }
882
883    #[diesel_test_helper::test]
884    #[allow(unsafe_code)]
885    fn with_raw_connection_can_return_values() {
886        let connection = &mut connection();
887
888        // SAFETY: We only read connection status, which doesn't modify state.
889        let autocommit_status = unsafe {
890            connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
891        };
892
893        // Outside a transaction, autocommit should be enabled (returns non-zero)
894        assert_ne!(autocommit_status, 0, "Expected autocommit to be enabled");
895    }
896
897    #[diesel_test_helper::test]
898    #[allow(unsafe_code)]
899    fn with_raw_connection_works_after_diesel_operations() {
900        let connection = &mut connection();
901
902        // First, do some Diesel operations
903        crate::sql_query("CREATE TABLE test_table (id INTEGER PRIMARY KEY, value TEXT)")
904            .execute(connection)
905            .unwrap();
906        crate::sql_query("INSERT INTO test_table (value) VALUES ('hello')")
907            .execute(connection)
908            .unwrap();
909
910        // SAFETY: We only read the last insert rowid, which is a read-only operation.
911        let last_rowid = unsafe {
912            connection.with_raw_connection(|raw_conn| ffi::sqlite3_last_insert_rowid(raw_conn))
913        };
914
915        assert_eq!(last_rowid, 1, "Last insert rowid should be 1");
916
917        // Verify Diesel still works after using raw connection
918        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM test_table")
919            .get_result(connection)
920            .unwrap();
921        assert_eq!(count, 1);
922    }
923
924    #[diesel_test_helper::test]
925    // Registers a callback that is invoked by the native library, or reads memory
926    // allocated by it, which is not supported when running under miri with a native
927    // libsqlite3 (`-Zmiri-native-lib`).
928    #[cfg(not(miri))] // ffi call
929    #[allow(unsafe_code)]
930    fn with_raw_connection_can_execute_raw_sql() {
931        let connection = &mut connection();
932
933        // Create a table using Diesel first
934        crate::sql_query("CREATE TABLE raw_test (id INTEGER PRIMARY KEY, name TEXT)")
935            .execute(connection)
936            .unwrap();
937
938        // SAFETY: We execute a simple INSERT via raw SQLite API.
939        // This modifies the database but in a way compatible with Diesel.
940        let result = unsafe {
941            connection.with_raw_connection(|raw_conn| {
942                let sql = c"INSERT INTO raw_test (name) VALUES ('from_raw')";
943                let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
944                let rc = ffi::sqlite3_exec(
945                    raw_conn,
946                    sql.as_ptr(),
947                    None,
948                    core::ptr::null_mut(),
949                    &mut err_msg,
950                );
951                if rc != ffi::SQLITE_OK && !err_msg.is_null() {
952                    ffi::sqlite3_free(err_msg as *mut libc::c_void);
953                }
954                rc
955            })
956        };
957
958        assert_eq!(result, ffi::SQLITE_OK, "Raw SQL execution should succeed");
959
960        // Verify the insert worked using Diesel
961        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM raw_test")
962            .get_result(connection)
963            .unwrap();
964        assert_eq!(count, 1);
965
966        let name: String = sql::<Text>("SELECT name FROM raw_test WHERE id = 1")
967            .get_result(connection)
968            .unwrap();
969        assert_eq!(name, "from_raw");
970    }
971
972    #[diesel_test_helper::test]
973    #[allow(unsafe_code)]
974    fn with_raw_connection_works_within_transaction() {
975        let connection = &mut connection();
976
977        crate::sql_query("CREATE TABLE txn_test (id INTEGER PRIMARY KEY, value INTEGER)")
978            .execute(connection)
979            .unwrap();
980
981        connection
982            .transaction::<_, crate::result::Error, _>(|conn| {
983                crate::sql_query("INSERT INTO txn_test (value) VALUES (42)")
984                    .execute(conn)
985                    .unwrap();
986
987                // SAFETY: We only read the autocommit status inside a transaction.
988                let autocommit = unsafe {
989                    conn.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
990                };
991
992                // Inside a transaction, autocommit should be disabled (returns 0)
993                assert_eq!(
994                    autocommit, 0,
995                    "Autocommit should be disabled inside transaction"
996                );
997
998                Ok(())
999            })
1000            .unwrap();
1001
1002        // After transaction commits, autocommit should be re-enabled
1003        let autocommit = unsafe {
1004            connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1005        };
1006        assert_ne!(
1007            autocommit, 0,
1008            "Autocommit should be enabled after transaction"
1009        );
1010    }
1011
1012    #[diesel_test_helper::test]
1013    // Registers a callback that is invoked by the native library, or reads memory
1014    // allocated by it, which is not supported when running under miri with a native
1015    // libsqlite3 (`-Zmiri-native-lib`).
1016    #[cfg(not(miri))] // ffi call
1017    #[allow(unsafe_code)]
1018    fn with_raw_connection_can_read_database_filename() {
1019        let connection = &mut connection();
1020
1021        // SAFETY: We only read the database filename, which is a read-only operation.
1022        let filename = unsafe {
1023            connection.with_raw_connection(|raw_conn| {
1024                let db_name = c"main";
1025                let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1026                if filename_ptr.is_null() {
1027                    None
1028                } else {
1029                    // For :memory: databases, this might return empty string or special value
1030                    let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1031                    Some(cstr.to_string_lossy().into_owned())
1032                }
1033            })
1034        };
1035
1036        // For in-memory databases, sqlite3_db_filename returns a non-null pointer
1037        // to an empty string
1038        assert_eq!(
1039            filename,
1040            Some(String::new()),
1041            "In-memory database filename should be an empty string"
1042        );
1043    }
1044
1045    #[diesel_test_helper::test]
1046    #[allow(unsafe_code)]
1047    fn with_raw_connection_changes_count() {
1048        let connection = &mut connection();
1049
1050        crate::sql_query("CREATE TABLE changes_test (id INTEGER PRIMARY KEY, value INTEGER)")
1051            .execute(connection)
1052            .unwrap();
1053
1054        crate::sql_query("INSERT INTO changes_test (value) VALUES (1), (2), (3)")
1055            .execute(connection)
1056            .unwrap();
1057
1058        // Update all rows using raw connection
1059        let changes = unsafe {
1060            connection.with_raw_connection(|raw_conn| {
1061                let sql = c"UPDATE changes_test SET value = value + 10";
1062                let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
1063                let rc = ffi::sqlite3_exec(
1064                    raw_conn,
1065                    sql.as_ptr(),
1066                    None,
1067                    core::ptr::null_mut(),
1068                    &mut err_msg,
1069                );
1070                if rc != ffi::SQLITE_OK && !err_msg.is_null() {
1071                    ffi::sqlite3_free(err_msg as *mut libc::c_void);
1072                    return -1;
1073                }
1074                ffi::sqlite3_changes(raw_conn)
1075            })
1076        };
1077
1078        assert_eq!(changes, 3, "Should have updated 3 rows");
1079
1080        // Verify the updates using Diesel
1081        let values: Vec<i32> = sql::<Integer>("SELECT value FROM changes_test ORDER BY id")
1082            .load(connection)
1083            .unwrap();
1084        assert_eq!(values, vec![11, 12, 13]);
1085    }
1086
1087    // catch_unwind is not available in WASM (panic = "abort")
1088    #[diesel_test_helper::test]
1089    #[allow(unsafe_code)]
1090    #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1091    fn with_raw_connection_recovers_after_panic() {
1092        let connection = &mut connection();
1093
1094        crate::sql_query("CREATE TABLE panic_test (id INTEGER PRIMARY KEY, value TEXT)")
1095            .execute(connection)
1096            .unwrap();
1097
1098        // Panic inside the callback
1099        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
1100            connection.with_raw_connection(|_raw_conn| {
1101                panic!("intentional panic inside with_raw_connection");
1102            })
1103        }));
1104        assert!(result.is_err(), "Should have caught the panic");
1105
1106        // Connection should still be usable after the panic
1107        crate::sql_query("INSERT INTO panic_test (value) VALUES ('after_panic')")
1108            .execute(connection)
1109            .unwrap();
1110
1111        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM panic_test")
1112            .get_result(connection)
1113            .unwrap();
1114        assert_eq!(count, 1, "Connection should work after panic in callback");
1115    }
1116
1117    // Filesystem access is not available in WASM
1118    #[diesel_test_helper::test]
1119    #[allow(unsafe_code)]
1120    // Registers a callback that is invoked by the native library, or reads memory
1121    // allocated by it, which is not supported when running under miri with a native
1122    // libsqlite3 (`-Zmiri-native-lib`).
1123    #[cfg(not(miri))] // ffi call
1124    #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1125    fn with_raw_connection_can_read_file_database_filename() {
1126        let dir = std::env::temp_dir().join("diesel_test_filename.db");
1127        let db_path = dir.to_str().unwrap();
1128
1129        // Clean up from any previous run
1130        let _ = std::fs::remove_file(db_path);
1131
1132        let connection = &mut SqliteConnection::establish(db_path).unwrap();
1133
1134        // SAFETY: We only read the database filename, which is a read-only operation.
1135        let filename = unsafe {
1136            connection.with_raw_connection(|raw_conn| {
1137                let db_name = c"main";
1138                let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1139                if filename_ptr.is_null() {
1140                    None
1141                } else {
1142                    let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1143                    Some(cstr.to_string_lossy().into_owned())
1144                }
1145            })
1146        };
1147
1148        let filename = filename.expect("File-based database should have a filename");
1149        assert!(
1150            filename.contains("diesel_test_filename.db"),
1151            "Filename should contain the database name, got: {filename}"
1152        );
1153
1154        // Clean up
1155        let _ = std::fs::remove_file(db_path);
1156    }
1157
1158    // Registers a callback that is invoked by the native library, or reads memory
1159    // allocated by it, which is not supported when running under miri with a native
1160    // libsqlite3 (`-Zmiri-native-lib`).
1161    #[cfg(not(miri))] // ffi call
1162    #[diesel_test_helper::test]
1163    fn database_serializes_and_deserializes_successfully() {
1164        let expected_users = vec![
1165            (
1166                1,
1167                "John Doe".to_string(),
1168                "john.doe@example.com".to_string(),
1169            ),
1170            (
1171                2,
1172                "Jane Doe".to_string(),
1173                "jane.doe@example.com".to_string(),
1174            ),
1175        ];
1176
1177        let conn1 = &mut connection();
1178        let _ =
1179            crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1180                .execute(conn1);
1181        let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1182            .execute(conn1);
1183
1184        for _i in 0..2 {
1185            let serialized_database = conn1.serialize_database_to_buffer();
1186            let conn2 = &mut connection();
1187            conn2
1188                .deserialize_readonly_database_from_buffer(
1189                    serialized_database.try_as_slice().unwrap(),
1190                )
1191                .unwrap();
1192
1193            let query =
1194                sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1195            let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1196
1197            assert_eq!(expected_users, actual_users);
1198            // drop the database here
1199            // and requery the database to make sure the database owns
1200            // required data
1201            std::mem::drop(serialized_database);
1202            let query =
1203                sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1204            let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1205
1206            assert_eq!(expected_users, actual_users);
1207        }
1208    }
1209
1210    // Registers a callback that is invoked by the native library, or reads memory
1211    // allocated by it, which is not supported when running under miri with a native
1212    // libsqlite3 (`-Zmiri-native-lib`).
1213    #[cfg(not(miri))] // ffi call
1214    #[diesel_test_helper::test]
1215    fn database_deserialize_random_bytes() {
1216        let buffer = vec![0, 1, 2, 3, 4];
1217        let conn = &mut SqliteConnection::establish(":memory:").unwrap();
1218
1219        conn.deserialize_readonly_database_from_buffer(&buffer)
1220            .unwrap();
1221
1222        let r = sql::<Integer>("SELECT id FROM users").load::<i32>(conn);
1223
1224        assert!(r.is_err());
1225        assert_eq!(format_error(&r.unwrap_err()), "file is not a database");
1226
1227        let conn = &mut SqliteConnection::establish(":memory:").unwrap();
1228
1229        let _ =
1230            crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1231                .execute(conn);
1232        let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1233            .execute(conn);
1234
1235        let db = conn.serialize_database_to_buffer();
1236        // only get a valid header, but append garbage
1237        let mut bad_buffer = db[..100].to_vec();
1238        bad_buffer.extend(b"whatever");
1239        conn.deserialize_readonly_database_from_buffer(&bad_buffer)
1240            .unwrap();
1241
1242        let r = sql::<Integer>("SELECT id FROM users").load::<i32>(conn);
1243
1244        assert!(r.is_err());
1245        assert_eq!(
1246            format_error(&r.unwrap_err()),
1247            "database disk image is malformed"
1248        );
1249
1250        // only get a valid header, but append garbage
1251        let mut size_fitting_bad_buffer = db[..100].to_vec();
1252        size_fitting_bad_buffer.extend(
1253            core::iter::repeat(b"abcdefghij")
1254                .flatten()
1255                .take(db.len() - 100),
1256        );
1257        let r = conn.deserialize_readonly_database_from_buffer(&size_fitting_bad_buffer);
1258
1259        assert!(r.is_err());
1260        assert_eq!(
1261            format_error(&r.unwrap_err()),
1262            "database disk image is malformed"
1263        );
1264    }
1265
1266    #[diesel_test_helper::test]
1267    fn database_serializes_empty_deserialized_database() {
1268        let conn = &mut SqliteConnection::establish(":memory:").unwrap();
1269        conn.deserialize_readonly_database_from_buffer(&[]).unwrap();
1270
1271        let serialized = conn.serialize_database_to_buffer();
1272
1273        assert!(serialized.is_empty());
1274        assert!(serialized.try_as_slice().unwrap().is_empty());
1275    }
1276
1277    #[cfg(all(
1278        feature = "std",
1279        not(all(target_family = "wasm", target_os = "unknown")),
1280        // These tests read memory allocated by the native library or rely on
1281        // native code invoking a panic hook, neither of which is supported when
1282        // running under miri with a native libsqlite3 (`-Zmiri-native-lib`).
1283        not(miri)
1284    ))]
1285    #[allow(unsafe_code)]
1286    mod sqlite_serialize_oom {
1287        use super::super::oom_test_support::{panic_message, run_in_child, with_heap_limit};
1288        use super::super::{SerializedDatabase, ffi};
1289        use crate::connection::{Connection, SimpleConnection};
1290        use crate::sqlite::SqliteConnection;
1291        use crate::test_helpers::format_error;
1292
1293        const MIN_DATABASE_BYTES: i64 = 1_048_576;
1294
1295        // 64 KiB covers statement setup but cannot hold the 1 MiB serialization,
1296        // pinning the failure to output allocation after SQLite reports its size.
1297        fn with_failing_serialize<R>(f: impl FnOnce() -> R) -> R {
1298            with_heap_limit(65_536, f)
1299        }
1300
1301        #[test]
1302        fn sqlite_serialize_oom_is_contained() {
1303            run_in_child(|| {
1304                let mut conn = large_database();
1305
1306                let (baseline_size, baseline) = serialize_direct(&conn);
1307                assert!(
1308                    baseline_size >= MIN_DATABASE_BYTES,
1309                    "the serialized database is smaller than 1 MiB"
1310                );
1311                assert!(
1312                    !baseline.is_null(),
1313                    "SQLite refused to serialize a valid database"
1314                );
1315                // SAFETY: `sqlite3_serialize` returned this buffer and no wrapper owns it.
1316                unsafe { ffi::sqlite3_free(baseline as _) };
1317
1318                let (reported_size, data) = with_failing_serialize(|| serialize_direct(&conn));
1319                if !data.is_null() {
1320                    // SAFETY: `sqlite3_serialize` returned this buffer and no wrapper owns it.
1321                    unsafe { ffi::sqlite3_free(data as _) };
1322                }
1323                assert!(
1324                    data.is_null(),
1325                    "SQLite did not fail the output allocation of the serialization"
1326                );
1327                // SQLite reports the required size before attempting output allocation.
1328                assert!(
1329                    reported_size >= MIN_DATABASE_BYTES,
1330                    "SQLite reported a serialization size of {reported_size} with a null buffer"
1331                );
1332
1333                let serialized: SerializedDatabase =
1334                    with_failing_serialize(|| conn.serialize_database_to_buffer());
1335                let error = serialized
1336                    .try_as_slice()
1337                    .expect_err("the failed output allocation must surface as an error");
1338                assert_eq!(format_error(&error), "out of memory");
1339
1340                let payload = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
1341                    core::hint::black_box(serialized[0]);
1342                }))
1343                .expect_err("the serialized database access did not panic");
1344                let message = panic_message(&*payload);
1345                assert!(
1346                    message.contains("Cannot access the serialized database: out of memory"),
1347                    "SQLite serialization allocation failure surfaced as `{message}` instead \
1348                     of a caught allocation panic"
1349                );
1350            });
1351        }
1352
1353        fn large_database() -> SqliteConnection {
1354            let mut conn = SqliteConnection::establish(":memory:").unwrap();
1355            conn.batch_execute(&format!(
1356                "CREATE TABLE blobs (id INTEGER PRIMARY KEY, payload BLOB);
1357                 INSERT INTO blobs (payload) VALUES (zeroblob({MIN_DATABASE_BYTES}));"
1358            ))
1359            .unwrap();
1360            conn
1361        }
1362
1363        fn serialize_direct(conn: &SqliteConnection) -> (ffi::sqlite3_int64, *mut u8) {
1364            // SAFETY: The connection is live, a null schema selects `main`, and `size` is a writable out-parameter.
1365            unsafe {
1366                let mut size: ffi::sqlite3_int64 = 0;
1367                let data = ffi::sqlite3_serialize(
1368                    conn.raw_connection.internal_connection.as_ptr(),
1369                    core::ptr::null(),
1370                    &mut size as *mut _,
1371                    0,
1372                );
1373                (size, data)
1374            }
1375        }
1376    }
1377
1378    #[cfg(all(
1379        feature = "std",
1380        not(all(target_family = "wasm", target_os = "unknown")),
1381        not(miri)
1382    ))]
1383    mod diesel_manage_updated_at_errors {
1384        use super::super::oom_test_support::run_in_child;
1385        use crate::connection::{Connection, SimpleConnection};
1386        use crate::query_dsl::RunQueryDsl;
1387        use crate::sqlite::{AuthorizerContext, AuthorizerDecision, SqliteConnection};
1388        use crate::test_helpers::format_error;
1389
1390        #[track_caller]
1391        fn assert_no_panic_output(stderr: &str, table_name: &str) {
1392            assert!(
1393                !stderr.contains("panicked") && !stderr.contains(table_name),
1394                "diesel_manage_updated_at reached the panic hook\nstderr:\n{stderr}"
1395            );
1396        }
1397
1398        #[test]
1399        fn missing_table_returns_error_without_panicking() {
1400            let stderr = run_in_child(|| {
1401                let mut conn = SqliteConnection::establish(":memory:").unwrap();
1402                let error = conn
1403                    .batch_execute("SELECT diesel_manage_updated_at('synthetic_key_7c91a2')")
1404                    .unwrap_err();
1405                assert_eq!(
1406                    format_error(&error),
1407                    "no such table: main.synthetic_key_7c91a2"
1408                );
1409            });
1410            assert_no_panic_output(&stderr, "synthetic_key_7c91a2");
1411        }
1412
1413        #[test]
1414        fn denied_trigger_returns_error_without_panicking() {
1415            let stderr = run_in_child(|| {
1416                let mut conn = SqliteConnection::establish(":memory:").unwrap();
1417                conn.batch_execute("CREATE TABLE guarded_7c91a2 (id INTEGER, updated_at TEXT)")
1418                    .unwrap();
1419                conn.on_authorize(|ctx| match ctx {
1420                    AuthorizerContext::CreateTrigger(_) => AuthorizerDecision::Deny,
1421                    _ => AuthorizerDecision::Allow,
1422                });
1423                let error = conn
1424                    .batch_execute("SELECT diesel_manage_updated_at('guarded_7c91a2')")
1425                    .unwrap_err();
1426                assert_eq!(format_error(&error), "not authorized");
1427
1428                conn.remove_authorizer();
1429                let triggers: i64 = crate::dsl::sql::<crate::sql_types::BigInt>(
1430                    "SELECT COUNT(*) FROM sqlite_master WHERE type = 'trigger'",
1431                )
1432                .get_result(&mut conn)
1433                .unwrap();
1434                assert_eq!(triggers, 0);
1435            });
1436            assert_no_panic_output(&stderr, "guarded_7c91a2");
1437        }
1438
1439        #[test]
1440        fn failed_step_returns_error_without_panicking() {
1441            let stderr = run_in_child(|| {
1442                let mut conn = SqliteConnection::establish(":memory:").unwrap();
1443                conn.batch_execute(
1444                    "CREATE TABLE readonly_7c91a2 (id INTEGER, updated_at TEXT);
1445                     PRAGMA query_only = ON;",
1446                )
1447                .unwrap();
1448                let error = conn
1449                    .batch_execute("SELECT diesel_manage_updated_at('readonly_7c91a2')")
1450                    .unwrap_err();
1451                assert_eq!(format_error(&error), "attempt to write a readonly database");
1452            });
1453            assert_no_panic_output(&stderr, "readonly_7c91a2");
1454        }
1455    }
1456
1457    #[cfg(not(miri))]
1458    #[diesel_test_helper::test]
1459    fn diesel_manage_updated_at_does_not_execute_its_argument() {
1460        let connection = &mut SqliteConnection::establish(":memory:").unwrap();
1461        connection
1462            .batch_execute(
1463                "CREATE TABLE t (id INTEGER PRIMARY KEY, updated_at TEXT);
1464                 CREATE TABLE victims (id INTEGER PRIMARY KEY);",
1465            )
1466            .unwrap();
1467        let payload = "t AFTER UPDATE ON t BEGIN SELECT 1; END; DROP TABLE victims; --";
1468
1469        let result = sql::<Integer>("SELECT diesel_manage_updated_at(")
1470            .bind::<Text, _>(payload)
1471            .sql(")")
1472            .get_result::<i32>(connection);
1473
1474        let schema = sql::<Text>("SELECT group_concat(name, ',') FROM sqlite_master")
1475            .get_result::<String>(connection)
1476            .unwrap();
1477        assert_eq!(schema, "t,victims");
1478        assert_eq!(
1479            result.map_err(|e| format_error(&e)),
1480            Err(format!("no such table: main.{payload}"))
1481        );
1482    }
1483
1484    #[cfg(not(miri))]
1485    #[diesel_test_helper::test]
1486    fn diesel_manage_updated_at_quotes_the_table_name() {
1487        let connection = &mut SqliteConnection::establish(":memory:").unwrap();
1488        let names = ["users", "select", "odd \"name\"", "a b", "a_b"];
1489        for name in names {
1490            let quoted = name.replace('"', "\"\"");
1491            connection
1492                .batch_execute(&format!(
1493                    "CREATE TABLE \"{quoted}\" (id INTEGER PRIMARY KEY, updated_at TEXT);
1494                     INSERT INTO \"{quoted}\" (id) VALUES (1);"
1495                ))
1496                .unwrap();
1497            sql::<Integer>("SELECT diesel_manage_updated_at(")
1498                .bind::<Text, _>(name)
1499                .sql(")")
1500                .get_result::<i32>(connection)
1501                .unwrap();
1502            connection
1503                .batch_execute(&format!("UPDATE \"{quoted}\" SET id = 2"))
1504                .unwrap();
1505            let updated = sql::<Integer>(&format!(
1506                "SELECT COUNT(*) FROM \"{quoted}\" WHERE updated_at IS NOT NULL"
1507            ))
1508            .get_result::<i32>(connection)
1509            .unwrap();
1510            assert_eq!(updated, 1, "table {name}");
1511        }
1512
1513        let triggers =
1514            sql::<Text>("SELECT name FROM sqlite_master WHERE type = 'trigger' ORDER BY rowid")
1515                .load::<String>(connection)
1516                .unwrap();
1517        let expected = names.map(|name| format!("__diesel_manage_updated_at_{name}"));
1518        assert_eq!(triggers, expected);
1519    }
1520
1521    // regression test for https://github.com/diesel-rs/diesel/issues/3425
1522    #[diesel_test_helper::test]
1523    fn test_correct_serialization_of_owned_strings() {
1524        use crate::prelude::*;
1525
1526        #[derive(Debug, crate::expression::AsExpression)]
1527        #[diesel(sql_type = diesel::sql_types::Text)]
1528        struct CustomWrapper(String);
1529
1530        impl crate::serialize::ToSql<Text, Sqlite> for CustomWrapper {
1531            fn to_sql<'b>(
1532                &'b self,
1533                out: &mut crate::serialize::Output<'b, '_, Sqlite>,
1534            ) -> crate::serialize::Result {
1535                out.set_value(self.0.to_string());
1536                Ok(crate::serialize::IsNull::No)
1537            }
1538        }
1539
1540        let connection = &mut connection();
1541
1542        let res = crate::select(
1543            CustomWrapper("".into())
1544                .into_sql::<crate::sql_types::Text>()
1545                .nullable(),
1546        )
1547        .get_result::<Option<String>>(connection)
1548        .unwrap();
1549        assert_eq!(res, Some(String::new()));
1550    }
1551
1552    #[diesel_test_helper::test]
1553    fn test_correct_serialization_of_owned_bytes() {
1554        use crate::prelude::*;
1555
1556        #[derive(Debug, crate::expression::AsExpression)]
1557        #[diesel(sql_type = diesel::sql_types::Binary)]
1558        struct CustomWrapper(Vec<u8>);
1559
1560        impl crate::serialize::ToSql<crate::sql_types::Binary, Sqlite> for CustomWrapper {
1561            fn to_sql<'b>(
1562                &'b self,
1563                out: &mut crate::serialize::Output<'b, '_, Sqlite>,
1564            ) -> crate::serialize::Result {
1565                out.set_value(self.0.clone());
1566                Ok(crate::serialize::IsNull::No)
1567            }
1568        }
1569
1570        let connection = &mut connection();
1571
1572        let res = crate::select(
1573            CustomWrapper(Vec::new())
1574                .into_sql::<crate::sql_types::Binary>()
1575                .nullable(),
1576        )
1577        .get_result::<Option<Vec<u8>>>(connection)
1578        .unwrap();
1579        assert_eq!(res, Some(Vec::new()));
1580    }
1581
1582    #[diesel_test_helper::test]
1583    fn correctly_handle_empty_query() {
1584        let check_empty_query_error = |r: crate::QueryResult<usize>| {
1585            assert!(r.is_err());
1586            let err = r.unwrap_err();
1587            assert!(
1588                matches!(err, crate::result::Error::QueryBuilderError(ref b) if b.is::<crate::result::EmptyQuery>()),
1589                "Expected a query builder error, but got {err}"
1590            );
1591        };
1592        let connection = &mut SqliteConnection::establish(":memory:").unwrap();
1593        check_empty_query_error(crate::sql_query("").execute(connection));
1594        check_empty_query_error(crate::sql_query("   ").execute(connection));
1595        check_empty_query_error(crate::sql_query("\n\t").execute(connection));
1596        check_empty_query_error(crate::sql_query("-- SELECT 1;").execute(connection));
1597    }
1598
1599    #[diesel_test_helper::test]
1600    fn last_insert_rowid_returns_none_on_fresh_connection() {
1601        let conn = &mut connection();
1602        assert_eq!(conn.last_insert_rowid(), None);
1603    }
1604
1605    #[diesel_test_helper::test]
1606    fn last_insert_rowid_returns_rowid_after_insert() {
1607        let conn = &mut connection();
1608        crate::sql_query("CREATE TABLE li_test (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1609            .execute(conn)
1610            .unwrap();
1611
1612        crate::sql_query("INSERT INTO li_test (val) VALUES ('a')")
1613            .execute(conn)
1614            .unwrap();
1615        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1616
1617        crate::sql_query("INSERT INTO li_test (val) VALUES ('b')")
1618            .execute(conn)
1619            .unwrap();
1620        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(2));
1621    }
1622
1623    // Registers a callback that is invoked by the native library, or reads memory
1624    // allocated by it, which is not supported when running under miri with a native
1625    // libsqlite3 (`-Zmiri-native-lib`).
1626    #[cfg(not(miri))] // ffi call
1627    #[diesel_test_helper::test]
1628    fn last_insert_rowid_unchanged_after_failed_insert() {
1629        let conn = &mut connection();
1630        crate::sql_query(
1631            "CREATE TABLE li_test2 (id INTEGER PRIMARY KEY, val TEXT NOT NULL UNIQUE)",
1632        )
1633        .execute(conn)
1634        .unwrap();
1635
1636        crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')")
1637            .execute(conn)
1638            .unwrap();
1639        let rowid = conn.last_insert_rowid();
1640        assert_eq!(rowid, NonZeroI64::new(1));
1641
1642        // This should fail due to UNIQUE constraint
1643        let result = crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')").execute(conn);
1644        assert!(result.is_err());
1645
1646        // rowid should be unchanged
1647        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1648    }
1649
1650    #[diesel_test_helper::test]
1651    fn last_insert_rowid_with_explicit_rowid() {
1652        let conn = &mut connection();
1653        crate::sql_query("CREATE TABLE li_test3 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1654            .execute(conn)
1655            .unwrap();
1656
1657        crate::sql_query("INSERT INTO li_test3 (id, val) VALUES (42, 'a')")
1658            .execute(conn)
1659            .unwrap();
1660        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(42));
1661    }
1662
1663    #[diesel_test_helper::test]
1664    fn last_insert_rowid_unchanged_after_delete_and_update() {
1665        let conn = &mut connection();
1666        crate::sql_query("CREATE TABLE li_test4 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1667            .execute(conn)
1668            .unwrap();
1669
1670        crate::sql_query("INSERT INTO li_test4 (val) VALUES ('a')")
1671            .execute(conn)
1672            .unwrap();
1673        let rowid = conn.last_insert_rowid();
1674        assert_eq!(rowid, NonZeroI64::new(1));
1675
1676        crate::sql_query("UPDATE li_test4 SET val = 'b' WHERE id = 1")
1677            .execute(conn)
1678            .unwrap();
1679        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1680
1681        crate::sql_query("DELETE FROM li_test4 WHERE id = 1")
1682            .execute(conn)
1683            .unwrap();
1684        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1685    }
1686
1687    #[diesel_test_helper::test]
1688    fn test_injection() {
1689        diesel::table! {
1690            #[sql_name = "quote'table"]
1691            quote_table (id) {
1692                id -> Nullable<Integer>,
1693                name -> Nullable<Text>,
1694            }
1695        }
1696
1697        let mut conn = SqliteConnection::establish(":memory:").unwrap();
1698
1699        conn.batch_execute("CREATE TABLE \"quote'table\" (id INTEGER PRIMARY KEY, name TEXT);")
1700            .unwrap();
1701
1702        diesel::insert_into(quote_table::table)
1703            .values((quote_table::id.eq(1), quote_table::name.eq("Jane")))
1704            .execute(&mut conn)
1705            .unwrap();
1706
1707        if cfg!(not(miri)) {
1708            // string access over ffi
1709            let data = quote_table::table
1710                .load::<(Option<i32>, Option<String>)>(&mut conn)
1711                .unwrap();
1712            assert_eq!(data, [(Some(1), Some("Jane".to_owned()))]);
1713        }
1714    }
1715
1716    #[crate::declare_sql_function]
1717    extern "SQL" {
1718        fn sqlite_version() -> Text;
1719    }
1720
1721    #[diesel_test_helper::test]
1722    #[cfg(not(miri))] // string access over ffi
1723    fn version_matches_sqlite_version() {
1724        let conn = &mut connection();
1725        let reported = crate::select(sqlite_version())
1726            .get_result::<String>(conn)
1727            .unwrap();
1728        assert_eq!(conn.version().to_string(), reported);
1729    }
1730
1731    #[cfg(all(
1732        feature = "std",
1733        not(all(target_family = "wasm", target_os = "unknown")),
1734        // runs processes
1735        not(miri)
1736    ))]
1737    #[diesel_test_helper::test]
1738    fn deserialize_in_auto_extension_keeps_buffer_alive() {
1739        use super::oom_test_support::run_in_child;
1740
1741        run_in_child(|| {
1742            use std::sync::OnceLock;
1743            #[allow(unsafe_code, reason = "Test code")]
1744            fn load_image(conn: &mut BorrowedSqliteConnection) -> QueryResult<()> {
1745                // `conn` is a borrowed connection; its `serialized_data` is dropped
1746                // when this callback returns, but SQLite keeps using the buffer.
1747                unsafe {
1748                    conn.inner_mut()
1749                        .deserialize_readonly_database_from_buffer(IMAGE.get().unwrap())
1750                }
1751            }
1752
1753            static IMAGE: OnceLock<Vec<u8>> = OnceLock::new();
1754
1755            let mut src = SqliteConnection::establish(":memory:").unwrap();
1756            src.batch_execute("CREATE TABLE t(x TEXT); INSERT INTO t VALUES ('hello');")
1757                .unwrap();
1758            let image = src
1759                .serialize_database_to_buffer()
1760                .try_as_slice()
1761                .unwrap()
1762                .to_vec();
1763            IMAGE.set(image).unwrap();
1764
1765            crate::sqlite::register_auto_extension(load_image).unwrap();
1766            let mut conn = SqliteConnection::establish(":memory:").unwrap();
1767            crate::sqlite::reset_auto_extension();
1768
1769            let rows: QueryResult<Vec<String>> = sql::<Text>("SELECT x FROM t").load(&mut conn);
1770            assert_eq!(rows.unwrap(), vec!["hello".to_string()]);
1771        });
1772    }
1773}