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