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