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
7pub mod authorizer;
8mod bind_collector;
9mod collation_needed;
10mod functions;
11mod hooks;
12mod limits;
13mod owned_row;
14mod raw;
15mod row;
16mod serialized_database;
17pub(in crate::sqlite) mod sqlite_blob;
18mod sqlite_value;
19mod statement_iterator;
20mod stmt;
21mod trace;
22mod update_hook;
23
24pub use self::authorizer::{AuthorizerContext, AuthorizerDecision};
25pub use self::bind_collector::SqliteBindCollector;#[diesel_derives::__diesel_public_if(
26    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
27)]
28pub(in crate::sqlite) use self::bind_collector::SqliteBindCollector;
29pub use self::bind_collector::SqliteBindValue;
30#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
31pub use self::bind_collector::{OwnedSqliteBindValue, SqliteBindCollectorData, SqliteBindValueRef};
32pub use self::collation_needed::{CollationNeededContext, SqliteTextRep};
33pub use self::limits::SqliteLimit;
34use self::raw::RawConnection;
35pub use self::serialized_database::SerializedDatabase;
36pub use self::sqlite_value::SqliteValue;
37use self::statement_iterator::*;
38use self::stmt::{Statement, StatementUse};
39pub use self::trace::{SqliteTraceEvent, SqliteTraceFlags};
40pub use self::update_hook::{
41    SqliteChangeEvent, SqliteChangeOp, SqliteChangeOps, SqliteUpdateRouter,
42};
43use super::SqliteAggregateFunction;
44use crate::connection::instrumentation::{DynInstrumentation, StrQueryHelper};
45use crate::connection::statement_cache::StatementCache;
46use crate::connection::*;
47use crate::deserialize::{FromSqlRow, StaticallySizedRow};
48use crate::expression::QueryMetadata;
49use crate::query_builder::*;
50use crate::query_source::{ColumnHasTable, NamedTable};
51use crate::result::*;
52use crate::serialize::ToSql;
53use crate::sql_types::{HasSqlType, TypeMetadata};
54use crate::sqlite::{Sqlite, SqliteFunctionBehavior};
55use alloc::string::String;
56use alloc::vec::Vec;
57use core::ffi as libc;
58use core::num::NonZeroI64;
59
60/// Connections for the SQLite backend. Unlike other backends, SQLite supported
61/// connection URLs are:
62///
63/// - File paths (`test.db`)
64/// - [URIs](https://sqlite.org/uri.html) (`file://test.db`)
65/// - Special identifiers (`:memory:`)
66///
67/// # Supported loading model implementations
68///
69/// * [`DefaultLoadingMode`]
70///
71/// As `SqliteConnection` only supports a single loading mode implementation,
72/// it is **not required** to explicitly specify a loading mode
73/// when calling [`RunQueryDsl::load_iter()`] or [`LoadConnection::load`]
74///
75/// [`RunQueryDsl::load_iter()`]: crate::query_dsl::RunQueryDsl::load_iter
76///
77/// ## DefaultLoadingMode
78///
79/// `SqliteConnection` only supports a single loading mode, which loads
80/// values row by row from the result set.
81///
82/// ```rust
83/// # include!("../../doctest_setup.rs");
84/// #
85/// # fn main() {
86/// #     run_test().unwrap();
87/// # }
88/// #
89/// # fn run_test() -> QueryResult<()> {
90/// #     use schema::users;
91/// #     let connection = &mut establish_connection();
92/// use diesel::connection::DefaultLoadingMode;
93/// {
94///     // scope to restrict the lifetime of the iterator
95///     let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
96///
97///     for r in iter1 {
98///         let (id, name) = r?;
99///         println!("Id: {} Name: {}", id, name);
100///     }
101/// }
102///
103/// // works without specifying the loading mode
104/// let iter2 = users::table.load_iter::<(i32, String), _>(connection)?;
105///
106/// for r in iter2 {
107///     let (id, name) = r?;
108///     println!("Id: {} Name: {}", id, name);
109/// }
110/// #   Ok(())
111/// # }
112/// ```
113///
114/// This mode does **not support** creating
115/// multiple iterators using the same connection.
116///
117/// ```compile_fail
118/// # include!("../../doctest_setup.rs");
119/// #
120/// # fn main() {
121/// #     run_test().unwrap();
122/// # }
123/// #
124/// # fn run_test() -> QueryResult<()> {
125/// #     use schema::users;
126/// #     let connection = &mut establish_connection();
127/// use diesel::connection::DefaultLoadingMode;
128///
129/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
130/// let iter2 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
131///
132/// for r in iter1 {
133///     let (id, name) = r?;
134///     println!("Id: {} Name: {}", id, name);
135/// }
136///
137/// for r in iter2 {
138///     let (id, name) = r?;
139///     println!("Id: {} Name: {}", id, name);
140/// }
141/// #   Ok(())
142/// # }
143/// ```
144///
145/// # Concurrency
146///
147/// By default, when running into a database lock, the operation will abort with a
148/// `Database locked` error. However, it's possible to configure it for greater concurrency,
149/// trading latency for not having to deal with retries yourself.
150///
151/// You can use this example as blue-print for which statements to run after establishing a connection.
152/// It is **important** to run each `PRAGMA` in a single statement to make sure all of them apply
153/// correctly. In addition the order of the `PRAGMA` statements is relevant to prevent timeout
154/// issues for the later `PRAGMA` statements.
155///
156/// ```rust
157/// # include!("../../doctest_setup.rs");
158/// #
159/// # fn main() {
160/// #     run_test().unwrap();
161/// # }
162/// #
163/// # fn run_test() -> QueryResult<()> {
164/// #     use schema::users;
165/// use diesel::connection::SimpleConnection;
166/// let conn = &mut establish_connection();
167/// // see https://fractaledmind.github.io/2023/09/07/enhancing-rails-sqlite-fine-tuning/
168/// // sleep if the database is busy, this corresponds to up to 2 seconds sleeping time.
169/// conn.batch_execute("PRAGMA busy_timeout = 2000;")?;
170/// // better write-concurrency
171/// conn.batch_execute("PRAGMA journal_mode = WAL;")?;
172/// // fsync only in critical moments
173/// conn.batch_execute("PRAGMA synchronous = NORMAL;")?;
174/// // write WAL changes back every 1000 pages, for an in average 1MB WAL file.
175/// // May affect readers if number is increased
176/// conn.batch_execute("PRAGMA wal_autocheckpoint = 1000;")?;
177/// // free some space by truncating possibly massive WAL files from the last run
178/// conn.batch_execute("PRAGMA wal_checkpoint(TRUNCATE);")?;
179/// #   Ok(())
180/// # }
181/// ```
182#[allow(missing_debug_implementations)]
183#[cfg(feature = "__sqlite-shared")]
184pub struct SqliteConnection {
185    // statement_cache needs to be before raw_connection
186    // otherwise we will get errors about open statements before closing the
187    // connection itself
188    statement_cache: StatementCache<Sqlite, Statement>,
189    raw_connection: RawConnection,
190    transaction_state: AnsiTransactionManager,
191    // this exists for the sole purpose of implementing `WithMetadataLookup` trait
192    // and avoiding static mut which will be deprecated in 2024 edition
193    metadata_lookup: (),
194    instrumentation: DynInstrumentation,
195    // We potentially need to store a serialized
196    // database in here to make sure the database bytes
197    // live as long as the connection
198    // This is used by SqliteConnection::deserialize_readonly_database_from_buffer
199    // only
200    // This field needs to come after the RawConnection
201    // as we need to make sure the data are still there until the
202    // connection is dropped
203    //
204    // We are not allowed to modify the inner buffer until the database connection is dropped
205    serialized_data: Vec<Vec<u8>>,
206}
207
208// This relies on the invariant that RawConnection or Statement are never
209// leaked. If a reference to one of those was held on a different thread, this
210// would not be thread safe.
211#[allow(unsafe_code)]
212unsafe impl Send for SqliteConnection {}
213
214impl SimpleConnection for SqliteConnection {
215    fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
216        self.instrumentation
217            .on_connection_event(InstrumentationEvent::StartQuery {
218                query: &StrQueryHelper::new(query),
219            });
220        let resp = self.raw_connection.exec(query);
221        self.instrumentation
222            .on_connection_event(InstrumentationEvent::FinishQuery {
223                query: &StrQueryHelper::new(query),
224                error: resp.as_ref().err(),
225            });
226        resp
227    }
228}
229
230impl ConnectionSealed for SqliteConnection {}
231
232impl Connection for SqliteConnection {
233    type Backend = Sqlite;
234    type TransactionManager = AnsiTransactionManager;
235
236    /// Establish a connection to the database specified by `database_url`.
237    ///
238    /// See [SqliteConnection] for supported `database_url`.
239    ///
240    /// If the database does not exist, this method will try to
241    /// create a new database and then establish a connection to it.
242    ///
243    /// ## WASM support
244    ///
245    /// If you plan to use this connection type on the `wasm32-unknown-unknown` target please
246    /// make sure to read the following notes:
247    ///
248    /// * The database is stored in memory by default.
249    /// * Persistent VFS (Virtual File Systems) is optional,
250    ///   see <https://github.com/Spxg/sqlite-wasm-rs> for details
251    fn establish(database_url: &str) -> ConnectionResult<Self> {
252        let mut instrumentation = DynInstrumentation::default_instrumentation();
253        instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
254            url: database_url,
255        });
256
257        let establish_result = Self::establish_inner(database_url);
258        instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
259            url: database_url,
260            error: establish_result.as_ref().err(),
261        });
262        let mut conn = establish_result?;
263        conn.instrumentation = instrumentation;
264        Ok(conn)
265    }
266
267    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
268    where
269        T: QueryFragment<Self::Backend> + QueryId,
270    {
271        let statement_use = self.prepared_query(source)?;
272        statement_use.run().and_then(|_| {
273            self.raw_connection
274                .rows_affected_by_last_query()
275                .map_err(Error::DeserializationError)
276        })
277    }
278
279    fn transaction_state(&mut self) -> &mut AnsiTransactionManager
280    where
281        Self: Sized,
282    {
283        &mut self.transaction_state
284    }
285
286    fn instrumentation(&mut self) -> &mut dyn Instrumentation {
287        &mut *self.instrumentation
288    }
289
290    fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
291        self.instrumentation = instrumentation.into();
292    }
293
294    fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
295        self.statement_cache.set_cache_size(size);
296    }
297}
298
299impl LoadConnection<DefaultLoadingMode> for SqliteConnection {
300    type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>;
301    type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>;
302
303    fn load<'conn, 'query, T>(
304        &'conn mut self,
305        source: T,
306    ) -> QueryResult<Self::Cursor<'conn, 'query>>
307    where
308        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
309        Self::Backend: QueryMetadata<T::SqlType>,
310    {
311        let statement = self.prepared_query(source)?;
312
313        Ok(StatementIterator::new(statement))
314    }
315}
316
317impl WithMetadataLookup for SqliteConnection {
318    fn metadata_lookup(&mut self) -> &mut <Sqlite as TypeMetadata>::MetadataLookup {
319        &mut self.metadata_lookup
320    }
321}
322
323#[cfg(feature = "r2d2")]
324impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
325    fn ping(&mut self) -> QueryResult<()> {
326        use crate::RunQueryDsl;
327
328        crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
329    }
330
331    fn is_broken(&mut self) -> bool {
332        AnsiTransactionManager::is_broken_transaction_manager(self)
333    }
334}
335
336impl MultiConnectionHelper for SqliteConnection {
337    fn to_any<'a>(
338        lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
339    ) -> &mut (dyn core::any::Any + 'a) {
340        lookup
341    }
342
343    fn from_any(
344        lookup: &mut dyn core::any::Any,
345    ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
346        lookup.downcast_mut()
347    }
348}
349
350/// The decision returned by an [`on_commit`](SqliteConnection::on_commit)
351/// callback, controlling whether a pending commit completes.
352#[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]
impl ::core::clone::Clone for CommitDecision {
    #[inline]
    fn clone(&self) -> CommitDecision { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CommitDecision { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for CommitDecision {
    #[inline]
    fn eq(&self, other: &CommitDecision) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CommitDecision {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq)]
353pub enum CommitDecision {
354    /// Let the commit proceed normally.
355    Proceed,
356    /// Convert the commit into a rollback.
357    Rollback,
358}
359
360/// The decision returned by an [`on_progress`](SqliteConnection::on_progress)
361/// callback, controlling whether a long-running query keeps executing.
362#[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]
impl ::core::clone::Clone for ProgressDecision {
    #[inline]
    fn clone(&self) -> ProgressDecision { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ProgressDecision { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for ProgressDecision {
    #[inline]
    fn eq(&self, other: &ProgressDecision) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ProgressDecision {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq)]
363pub enum ProgressDecision {
364    /// Let the query continue executing.
365    Continue,
366    /// Interrupt the query (causes `SQLITE_INTERRUPT`).
367    Interrupt,
368}
369
370/// The decision returned by an [`on_busy`](SqliteConnection::on_busy)
371/// callback when the database is locked.
372#[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]
impl ::core::clone::Clone for BusyDecision {
    #[inline]
    fn clone(&self) -> BusyDecision { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for BusyDecision { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for BusyDecision {
    #[inline]
    fn eq(&self, other: &BusyDecision) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for BusyDecision {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq)]
373pub enum BusyDecision {
374    /// Retry the locked operation.
375    Retry,
376    /// Give up, returning `SQLITE_BUSY` to the caller.
377    GiveUp,
378}
379
380impl SqliteConnection {
381    /// Run a transaction with `BEGIN IMMEDIATE`
382    ///
383    /// This method will return an error if a transaction is already open.
384    ///
385    /// # Example
386    ///
387    /// ```rust
388    /// # include!("../../doctest_setup.rs");
389    /// #
390    /// # fn main() {
391    /// #     run_test().unwrap();
392    /// # }
393    /// #
394    /// # fn run_test() -> QueryResult<()> {
395    /// #     let mut conn = SqliteConnection::establish(":memory:").unwrap();
396    /// conn.immediate_transaction(|conn| {
397    ///     // Do stuff in a transaction
398    ///     Ok(())
399    /// })
400    /// # }
401    /// ```
402    pub fn immediate_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
403    where
404        F: FnOnce(&mut Self) -> Result<T, E>,
405        E: From<Error>,
406    {
407        self.transaction_sql(f, "BEGIN IMMEDIATE")
408    }
409
410    /// Run a transaction with `BEGIN EXCLUSIVE`
411    ///
412    /// This method will return an error if a transaction is already open.
413    ///
414    /// # Example
415    ///
416    /// ```rust
417    /// # include!("../../doctest_setup.rs");
418    /// #
419    /// # fn main() {
420    /// #     run_test().unwrap();
421    /// # }
422    /// #
423    /// # fn run_test() -> QueryResult<()> {
424    /// #     let mut conn = SqliteConnection::establish(":memory:").unwrap();
425    /// conn.exclusive_transaction(|conn| {
426    ///     // Do stuff in a transaction
427    ///     Ok(())
428    /// })
429    /// # }
430    /// ```
431    pub fn exclusive_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
432    where
433        F: FnOnce(&mut Self) -> Result<T, E>,
434        E: From<Error>,
435    {
436        self.transaction_sql(f, "BEGIN EXCLUSIVE")
437    }
438
439    /// Returns the rowid of the most recent successful INSERT on this connection.
440    ///
441    /// Returns `None` if no successful INSERT into a rowid table has been performed
442    /// on this connection, and `Some(rowid)` otherwise.
443    ///
444    /// See [the SQLite documentation](https://www.sqlite.org/c3ref/last_insert_rowid.html)
445    /// for details.
446    ///
447    /// # Caveats
448    /// - Inserts into `WITHOUT ROWID` tables are not recorded
449    /// - Failed `INSERT` (constraint violations) do not change the value
450    /// - `INSERT OR REPLACE` always updates the value
451    /// - Within triggers, returns the rowid of the trigger's INSERT;
452    ///   reverts after the trigger completes
453    ///
454    /// # Example
455    /// ```rust
456    /// # include!("../../doctest_setup.rs");
457    /// # fn main() {
458    /// #     run_test().unwrap();
459    /// # }
460    /// # fn run_test() -> QueryResult<()> {
461    /// use core::num::NonZeroI64;
462    /// use diesel::connection::SimpleConnection;
463    /// let conn = &mut SqliteConnection::establish(":memory:").unwrap();
464    /// conn.batch_execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")?;
465    /// conn.batch_execute("INSERT INTO users (name) VALUES ('Sean')")?;
466    /// let rowid = conn.last_insert_rowid();
467    /// assert_eq!(rowid, NonZeroI64::new(1));
468    /// conn.batch_execute("INSERT INTO users (name) VALUES ('Tess')")?;
469    /// let rowid = conn.last_insert_rowid();
470    /// assert_eq!(rowid, NonZeroI64::new(2));
471    /// # Ok(())
472    /// # }
473    /// ```
474    pub fn last_insert_rowid(&self) -> Option<NonZeroI64> {
475        NonZeroI64::new(self.raw_connection.last_insert_rowid())
476    }
477
478    /// Returns an object that can be used to stream a BLOB from the database
479    ///
480    /// # Example
481    ///
482    /// ```rust
483    /// # include!("../../doctest_setup.rs");
484    /// # table! {
485    /// #     myblobs {
486    /// #         id -> Integer,
487    /// #         mydata -> Blob,
488    /// #     }
489    /// # }
490    /// # fn main() {
491    /// #     run_test().unwrap();
492    /// # }
493    /// # fn run_test() -> Result<(), Box<dyn std::error::Error>> {
494    /// use std::io::Read;
495    /// use diesel::connection::SimpleConnection;
496    /// let conn = &mut SqliteConnection::establish(":memory:").unwrap();
497    /// conn.batch_execute("CREATE TABLE myblobs (id INTEGER PRIMARY KEY, mydata BLOB)")?;
498    /// conn.batch_execute("INSERT INTO myblobs (mydata) VALUES ('abc')")?;
499    /// let mut data = conn.get_read_only_blob(myblobs::mydata, 1)?;
500    /// let mut buf = vec![];
501    /// data.read_to_end(&mut buf)?;
502    /// assert_eq!(buf, b"abc");
503    /// # Ok(())
504    /// # }
505    /// ```
506    pub fn get_read_only_blob<'conn, 'query, U>(
507        &'conn self,
508        blob_column: U,
509        row_id: i64,
510    ) -> Result<sqlite_blob::SqliteReadOnlyBlob<'conn>, Error>
511    where
512        'query: 'conn,
513        U: ColumnHasTable,
514        U::Table: NamedTable,
515    {
516        let table = blob_column.table();
517
518        let database_name = table.schema().unwrap_or("main");
519        let column_name = blob_column.name();
520        let table_name = table.table();
521
522        self.raw_connection
523            .blob_open(database_name, table_name, column_name, row_id)
524    }
525
526    fn transaction_sql<T, E, F>(&mut self, f: F, sql: &str) -> Result<T, E>
527    where
528        F: FnOnce(&mut Self) -> Result<T, E>,
529        E: From<Error>,
530    {
531        AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?;
532        match f(&mut *self) {
533            Ok(value) => {
534                AnsiTransactionManager::commit_transaction(&mut *self)?;
535                Ok(value)
536            }
537            Err(e) => {
538                AnsiTransactionManager::rollback_transaction(&mut *self)?;
539                Err(e)
540            }
541        }
542    }
543
544    fn prepared_query<'conn, 'query, T>(
545        &'conn mut self,
546        source: T,
547    ) -> QueryResult<StatementUse<'conn, 'query>>
548    where
549        T: QueryFragment<Sqlite> + QueryId + 'query,
550    {
551        self.instrumentation
552            .on_connection_event(InstrumentationEvent::StartQuery {
553                query: &crate::debug_query(&source),
554            });
555        let raw_connection = &self.raw_connection;
556        let cache = &mut self.statement_cache;
557        let statement = match cache.cached_statement(
558            &source,
559            &Sqlite,
560            &[],
561            raw_connection,
562            Statement::prepare,
563            &mut *self.instrumentation,
564        ) {
565            Ok(statement) => statement,
566            Err(e) => {
567                self.instrumentation
568                    .on_connection_event(InstrumentationEvent::FinishQuery {
569                        query: &crate::debug_query(&source),
570                        error: Some(&e),
571                    });
572
573                return Err(e);
574            }
575        };
576
577        StatementUse::bind(statement, source, &mut *self.instrumentation)
578    }
579
580    #[doc(hidden)]
581    pub fn register_sql_function<ArgsSqlType, RetSqlType, Args, Ret, F>(
582        &mut self,
583        fn_name: &str,
584        behavior: SqliteFunctionBehavior,
585        mut f: F,
586    ) -> QueryResult<()>
587    where
588        F: FnMut(Args) -> Ret + core::panic::UnwindSafe + Send + 'static,
589        Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
590        Ret: ToSql<RetSqlType, Sqlite>,
591        Sqlite: HasSqlType<RetSqlType>,
592    {
593        functions::register(&self.raw_connection, fn_name, behavior, move |_, args| {
594            f(args)
595        })
596    }
597
598    #[doc(hidden)]
599    pub fn register_noarg_sql_function<RetSqlType, Ret, F>(
600        &mut self,
601        fn_name: &str,
602        behavior: SqliteFunctionBehavior,
603        f: F,
604    ) -> QueryResult<()>
605    where
606        F: FnMut() -> Ret + core::panic::UnwindSafe + Send + 'static,
607        Ret: ToSql<RetSqlType, Sqlite>,
608        Sqlite: HasSqlType<RetSqlType>,
609    {
610        functions::register_noargs(&self.raw_connection, fn_name, behavior, f)
611    }
612
613    #[doc(hidden)]
614    pub fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
615        &mut self,
616        fn_name: &str,
617        behavior: SqliteFunctionBehavior,
618    ) -> QueryResult<()>
619    where
620        A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
621        Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
622        Ret: ToSql<RetSqlType, Sqlite>,
623        Sqlite: HasSqlType<RetSqlType>,
624    {
625        functions::register_aggregate::<_, _, _, _, A>(&self.raw_connection, fn_name, behavior)
626    }
627
628    /// Register a collation function.
629    ///
630    /// `collation` must always return the same answer given the same inputs.
631    /// If `collation` panics and unwinds the stack, the process is aborted, since it is used
632    /// across a C FFI boundary, which cannot be unwound across and there is no way to
633    /// signal failures via the SQLite interface in this case..
634    ///
635    /// If the name is already registered it will be overwritten.
636    ///
637    /// This method will return an error if registering the function fails, either due to an
638    /// out-of-memory situation or because a collation with that name already exists and is
639    /// currently being used in parallel by a query.
640    ///
641    /// The collation needs to be specified when creating a table:
642    /// `CREATE TABLE my_table ( str TEXT COLLATE MY_COLLATION )`,
643    /// where `MY_COLLATION` corresponds to name passed as `collation_name`.
644    ///
645    /// # Example
646    ///
647    /// ```rust
648    /// # include!("../../doctest_setup.rs");
649    /// #
650    /// # fn main() {
651    /// #     run_test().unwrap();
652    /// # }
653    /// #
654    /// # fn run_test() -> QueryResult<()> {
655    /// #     let mut conn = SqliteConnection::establish(":memory:").unwrap();
656    /// // sqlite NOCASE only works for ASCII characters,
657    /// // this collation allows handling UTF-8 (barring locale differences)
658    /// conn.register_collation("RUSTNOCASE", |rhs, lhs| {
659    ///     rhs.to_lowercase().cmp(&lhs.to_lowercase())
660    /// })
661    /// # }
662    /// ```
663    pub fn register_collation<F>(&mut self, collation_name: &str, collation: F) -> QueryResult<()>
664    where
665        F: Fn(&str, &str) -> core::cmp::Ordering + Send + 'static + core::panic::UnwindSafe,
666    {
667        self.raw_connection
668            .register_collation_function(collation_name, collation)
669    }
670
671    /// Serialize the current SQLite database into a byte buffer.
672    ///
673    /// The serialized data is identical to the data that would be written to disk if the database
674    /// was saved in a file.
675    ///
676    /// # Returns
677    ///
678    /// This function returns a byte slice representing the serialized database.
679    pub fn serialize_database_to_buffer(&mut self) -> SerializedDatabase {
680        self.raw_connection.serialize()
681    }
682
683    /// Deserialize an SQLite database from a byte buffer.
684    ///
685    /// This function takes a byte slice and attempts to deserialize it into a SQLite database.
686    /// If successful, the database is loaded into the connection. If the deserialization fails,
687    /// an error is returned.
688    ///
689    /// The database is opened in READONLY mode.
690    ///
691    /// # Example
692    ///
693    /// ```no_run
694    /// # use diesel::sqlite::SerializedDatabase;
695    /// # use diesel::sqlite::SqliteConnection;
696    /// # use diesel::result::QueryResult;
697    /// # use diesel::sql_query;
698    /// # use diesel::Connection;
699    /// # use diesel::RunQueryDsl;
700    /// # fn main() {
701    /// let connection = &mut SqliteConnection::establish(":memory:").unwrap();
702    ///
703    /// sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
704    ///     .execute(connection).unwrap();
705    /// sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
706    ///     .execute(connection).unwrap();
707    ///
708    /// // Serialize the database to a byte vector
709    /// let serialized_db: SerializedDatabase = connection.serialize_database_to_buffer();
710    ///
711    /// // Create a new in-memory SQLite database
712    /// let connection = &mut SqliteConnection::establish(":memory:").unwrap();
713    ///
714    /// // Deserialize the byte vector into the new database
715    /// connection.deserialize_readonly_database_from_buffer(serialized_db.as_slice()).unwrap();
716    /// #
717    /// # }
718    /// ```
719    // TODO: Diesel 3.0 This signature needs to change, we want to expose more options (schema name, readonly)
720    // and also ensure that this is not as unsafe as the current construct anymore. Maybe just accept a owned buffer or static pointer
721    // only instead? (So `Cow<'static, [u8]>`?)
722    #[allow(unsafe_code)]
723    pub fn deserialize_readonly_database_from_buffer(&mut self, data: &[u8]) -> QueryResult<()> {
724        // we copy the buffer here
725        // to make sure the underlying buffer lives as long as the connection
726        self.serialized_data.push(data.to_vec());
727        let last = self
728            .serialized_data
729            .last()
730            .expect("We literally pushed it above, so it's there");
731        unsafe {
732            // SAFETY: We store the buffer inside of the connection and we never touch it until
733            // we drop the connection
734            self.raw_connection.deserialize(last)
735        }
736    }
737
738    /// Provides temporary access to the raw SQLite database connection handle.
739    ///
740    /// This method provides a way to access the underlying `sqlite3` pointer,
741    /// enabling direct use of the SQLite C API for advanced features that
742    /// Diesel does not wrap, such as the [session extension](https://www.sqlite.org/sessionintro.html),
743    /// [hooks](https://www.sqlite.org/c3ref/update_hook.html), or other advanced APIs.
744    ///
745    /// # Why Diesel Doesn't Wrap These APIs
746    ///
747    /// Certain SQLite features, such as the session extension, are **optional** and only
748    /// available when SQLite is compiled with specific flags (e.g., `-DSQLITE_ENABLE_SESSION`
749    /// and `-DSQLITE_ENABLE_PREUPDATE_HOOK` for sessions). These compile-time options determine
750    /// whether the corresponding C API functions exist in the SQLite library's ABI.
751    ///
752    /// Because Diesel must work with any SQLite library at runtime—including system-provided
753    /// libraries that may lack these optional features—it **cannot safely provide wrappers**
754    /// for APIs that may or may not exist. Doing so would either:
755    ///
756    /// - Cause **linker errors** at compile time if the user's `libsqlite3-sys` wasn't compiled
757    ///   with the required flags, or
758    /// - Cause **undefined behavior** at runtime if Diesel called functions that don't exist
759    ///   in the linked library.
760    ///
761    /// While feature gates could theoretically solve this problem, Diesel already has an
762    /// extensive API surface with many existing feature combinations. Each new feature gate
763    /// adds a **combinatorial explosion** of test configurations that must be validated,
764    /// making the library increasingly difficult to maintain. Therefore, exposing the raw
765    /// connection is the preferred approach for niche SQLite features.
766    ///
767    /// By exposing the raw connection handle, Diesel allows users who **know** they have
768    /// access to a properly configured SQLite build to use these advanced features directly
769    /// through their own FFI bindings.
770    ///
771    /// # Safety
772    ///
773    /// This method is marked `unsafe` because improper use of the raw connection handle
774    /// can lead to undefined behavior. The caller must ensure that:
775    ///
776    /// - The connection handle is **not closed** during the callback.
777    /// - The connection handle is **not stored** beyond the callback's scope.
778    /// - Concurrent access rules are respected (SQLite connections are not thread-safe
779    ///   unless using serialized threading mode).
780    /// - **Transaction state is not modified** — do not execute `BEGIN`, `COMMIT`,
781    ///   `ROLLBACK`, or `SAVEPOINT` statements via the raw handle. Diesel's
782    ///   [`AnsiTransactionManager`] tracks transaction nesting internally, and
783    ///   bypassing it will cause Diesel's view of the transaction state to diverge
784    ///   from SQLite's actual state.
785    /// - **Diesel's prepared statements are not disturbed** — do not call
786    ///   `sqlite3_finalize()` or `sqlite3_reset()` on statements that belong to
787    ///   Diesel's `StatementCache`. Doing so will cause use-after-free or
788    ///   double-free when Diesel later accesses those statements.
789    ///
790    /// [`AnsiTransactionManager`]: crate::connection::AnsiTransactionManager
791    ///
792    /// # Example
793    ///
794    /// ```rust
795    /// use diesel::sqlite::SqliteConnection;
796    /// use diesel::Connection;
797    ///
798    /// let mut conn = SqliteConnection::establish(":memory:").unwrap();
799    ///
800    /// // SAFETY: We do not close or store the connection handle,
801    /// // and we do not modify Diesel-managed state (transactions, cached statements).
802    /// let is_valid = unsafe {
803    ///     conn.with_raw_connection(|raw_conn| {
804    ///         // The raw connection pointer can be passed to SQLite C API functions
805    ///         // from your own `libsqlite3-sys` (native) or `sqlite-wasm-rs` (WASM)
806    ///         // dependency — for example, `sqlite3_get_autocommit(raw_conn)` or
807    ///         // `sqlite3session_create(raw_conn, ...)`.
808    ///         !raw_conn.is_null()
809    ///     })
810    /// };
811    /// assert!(is_valid);
812    /// ```
813    ///
814    /// # Platform Notes
815    ///
816    /// This method works identically on both native and WASM targets. However,
817    /// you must depend on the appropriate FFI crate for your target:
818    ///
819    /// - **Native**: Add `libsqlite3-sys` as a dependency
820    /// - **WASM** (`wasm32-unknown-unknown`): Add `sqlite-wasm-rs` as a dependency
821    ///
822    /// Both crates expose a compatible `sqlite3` type that can be used with the
823    /// pointer returned by this method.
824    #[allow(unsafe_code)]
825    pub unsafe fn with_raw_connection<R, F>(&mut self, f: F) -> R
826    where
827        F: FnOnce(*mut ffi::sqlite3) -> R,
828    {
829        f(self.raw_connection.internal_connection.as_ptr())
830    }
831
832    /// Runs `f` with a borrowed `SqliteConnection` wrapping `db`, giving SQLite
833    /// callbacks the full connection API. Statements prepared during `f` are
834    /// finalized on return, but `db` is left open, since SQLite owns it.
835    ///
836    /// # Safety
837    ///
838    /// `db` must be a valid `sqlite3` handle that stays open for the duration
839    /// of the call.
840    #[allow(unsafe_code)]
841    pub(crate) unsafe fn with_borrowed_connection<R>(
842        db: core::ptr::NonNull<ffi::sqlite3>,
843        f: impl FnOnce(&mut SqliteConnection) -> R,
844    ) -> R {
845        // Tears the borrowed connection down on every exit path, including a
846        // panic unwinding out of `f`.
847        struct Borrowed(core::mem::ManuallyDrop<SqliteConnection>);
848
849        impl Drop for Borrowed {
850            fn drop(&mut self) {
851                // SAFETY: `self.0` is not touched again after this take.
852                let conn = unsafe { core::mem::ManuallyDrop::take(&mut self.0) };
853                let SqliteConnection {
854                    statement_cache,
855                    raw_connection,
856                    ..
857                } = conn;
858                // Finalize prepared statements, but do not run `RawConnection`'s
859                // `Drop`, which would close a handle we do not own.
860                drop(statement_cache);
861                core::mem::forget(raw_connection);
862            }
863        }
864
865        let mut conn = Borrowed(core::mem::ManuallyDrop::new(SqliteConnection {
866            statement_cache: StatementCache::new(),
867            raw_connection: RawConnection::from_ptr(db),
868            transaction_state: AnsiTransactionManager::default(),
869            metadata_lookup: (),
870            instrumentation: DynInstrumentation::default_instrumentation(),
871            serialized_data: Vec::new(),
872        }));
873
874        let result = f(&mut conn.0);
875
876        // The borrowed connection is discarded without committing or rolling
877        // back, so a transaction left open by `f` would leak onto the handle.
878        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!(
879            matches!(
880                AnsiTransactionManager::transaction_manager_status_mut(&mut *conn.0)
881                    .transaction_depth(),
882                Ok(None)
883            ),
884            "callback must not leave an open transaction on the borrowed connection"
885        );
886
887        result
888    }
889
890    /// Set a runtime limit for this connection, returning its previous value.
891    ///
892    /// Lowering these limits is a way to harden a connection against untrusted
893    /// SQL. See the [SQLite documentation](https://www.sqlite.org/c3ref/limit.html)
894    /// for the meaning of each [`SqliteLimit`].
895    ///
896    /// # Example
897    ///
898    /// ```rust
899    /// # include!("../../doctest_setup.rs");
900    /// # fn main() { run_test(); }
901    /// # fn run_test() {
902    /// use diesel::sqlite::SqliteLimit;
903    ///
904    /// let mut conn = SqliteConnection::establish(":memory:").unwrap();
905    ///
906    /// // Cap SQL statement length at 1 KiB, keeping the previous value.
907    /// let previous = conn.set_limit(SqliteLimit::SqlLength, 1024);
908    /// assert!(previous > 0);
909    /// assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 1024);
910    /// # }
911    /// ```
912    pub fn set_limit(&mut self, limit: SqliteLimit, value: i32) -> i32 {
913        self.raw_connection.set_limit(limit, value)
914    }
915
916    /// Get the current value of a runtime limit for this connection.
917    ///
918    /// See the [SQLite documentation](https://www.sqlite.org/c3ref/limit.html)
919    /// for the meaning of each [`SqliteLimit`].
920    ///
921    /// # Example
922    ///
923    /// ```rust
924    /// # include!("../../doctest_setup.rs");
925    /// # fn main() { run_test(); }
926    /// # fn run_test() {
927    /// use diesel::sqlite::SqliteLimit;
928    ///
929    /// let conn = SqliteConnection::establish(":memory:").unwrap();
930    /// assert!(conn.get_limit(SqliteLimit::SqlLength) > 0);
931    /// # }
932    /// ```
933    pub fn get_limit(&self, limit: SqliteLimit) -> i32 {
934        self.raw_connection.get_limit(limit)
935    }
936
937    /// Apply SQLite's recommended limits for hardening against untrusted SQL.
938    ///
939    /// These are the values from the "Untrusted SQL Inputs" table of SQLite's
940    /// [security documentation](https://sqlite.org/security.html). They are
941    /// intentionally restrictive, so call [`set_limit`](Self::set_limit)
942    /// afterwards to relax any that are too aggressive for your application.
943    ///
944    /// | Limit | Value |
945    /// |-------|-------|
946    /// | `Length` | 1,000,000 |
947    /// | `SqlLength` | 100,000 |
948    /// | `ColumnCount` | 100 |
949    /// | `ExprDepth` | 10 |
950    /// | `CompoundSelect` | 3 |
951    /// | `VdbeOp` | 25,000 |
952    /// | `FunctionArg` | 8 |
953    /// | `Attached` | 0 |
954    /// | `LikePatternLength` | 50 |
955    /// | `VariableNumber` | 10 |
956    /// | `TriggerDepth` | 10 |
957    ///
958    /// The table's `PARSER_DEPTH` recommendation is omitted because it is a
959    /// compile-time only setting with no runtime `sqlite3_limit()` category.
960    /// `WorkerThreads` is left untouched (its default of 0 is already safe).
961    ///
962    /// # Example
963    ///
964    /// ```rust
965    /// # include!("../../doctest_setup.rs");
966    /// # fn main() { run_test(); }
967    /// # fn run_test() {
968    /// use diesel::sqlite::SqliteLimit;
969    ///
970    /// let mut conn = SqliteConnection::establish(":memory:").unwrap();
971    /// conn.set_recommended_security_limits();
972    /// assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 100_000);
973    ///
974    /// // Relax an individual limit that is too strict for this application.
975    /// conn.set_limit(SqliteLimit::VariableNumber, 999);
976    /// assert_eq!(conn.get_limit(SqliteLimit::VariableNumber), 999);
977    /// # }
978    /// ```
979    pub fn set_recommended_security_limits(&mut self) {
980        self.set_limit(SqliteLimit::Length, SqliteLimit::SAFE_LENGTH_LIMIT);
981        self.set_limit(SqliteLimit::SqlLength, SqliteLimit::SAFE_SQL_LENGTH_LIMIT);
982        self.set_limit(
983            SqliteLimit::ColumnCount,
984            SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
985        );
986        self.set_limit(SqliteLimit::ExprDepth, SqliteLimit::SAFE_EXPR_DEPTH_LIMIT);
987        self.set_limit(
988            SqliteLimit::CompoundSelect,
989            SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
990        );
991        self.set_limit(SqliteLimit::VdbeOp, SqliteLimit::SAFE_VDBE_OP_LIMIT);
992        self.set_limit(
993            SqliteLimit::FunctionArg,
994            SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
995        );
996        self.set_limit(SqliteLimit::Attached, SqliteLimit::SAFE_ATTACHED_LIMIT);
997        self.set_limit(
998            SqliteLimit::LikePatternLength,
999            SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
1000        );
1001        self.set_limit(
1002            SqliteLimit::VariableNumber,
1003            SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
1004        );
1005        self.set_limit(
1006            SqliteLimit::TriggerDepth,
1007            SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
1008        );
1009    }
1010
1011    /// Enable or disable SQLite defensive mode.
1012    ///
1013    /// When enabled, defensive mode prevents direct writes to shadow tables
1014    /// (FTS5, R-Tree, etc.), dangerous PRAGMAs like `writable_schema`,
1015    /// `sqlite3_deserialize()` from opening unsafe database images, and other
1016    /// potentially dangerous operations. Enable it for any connection that may
1017    /// process untrusted data. It is the single most important hardening flag.
1018    ///
1019    /// Requires SQLite 3.26.0 or later, otherwise returns an error.
1020    ///
1021    /// # Security Hardening Recipe
1022    ///
1023    /// ```rust
1024    /// # include!("../../doctest_setup.rs");
1025    /// # fn main() {
1026    /// #     let mut conn = SqliteConnection::establish(":memory:").unwrap();
1027    /// conn.set_defensive(true).unwrap();
1028    /// conn.set_trusted_schema(false).unwrap();
1029    /// conn.set_recommended_security_limits();
1030    /// # }
1031    /// ```
1032    ///
1033    /// Extension loading is off by default. Enable it only when needed via
1034    /// [`with_load_extension_enabled`][Self::with_load_extension_enabled]. See
1035    /// [`set_recommended_security_limits`][Self::set_recommended_security_limits]
1036    /// to harden the SQLite resource limits as well.
1037    pub fn set_defensive(&mut self, enabled: bool) -> QueryResult<()> {
1038        self.raw_connection
1039            .set_db_config_bool(ffi::SQLITE_DBCONFIG_DEFENSIVE, enabled)
1040    }
1041
1042    /// Check if defensive mode is enabled.
1043    ///
1044    /// See [`set_defensive`][Self::set_defensive] for details.
1045    pub fn is_defensive(&self) -> QueryResult<bool> {
1046        self.raw_connection
1047            .get_db_config_bool(ffi::SQLITE_DBCONFIG_DEFENSIVE)
1048    }
1049
1050    /// Enable or disable trusted schema mode.
1051    ///
1052    /// When disabled (untrusted), SQL functions called from schema objects
1053    /// (views, triggers, CHECK constraints, DEFAULT expressions, generated
1054    /// columns, expression indexes) are restricted to those marked
1055    /// [`INNOCUOUS`][crate::sqlite::SqliteFunctionBehavior::INNOCUOUS]. Disable
1056    /// it when opening database files from untrusted sources, and register your
1057    /// custom functions with appropriate
1058    /// [`SqliteFunctionBehavior`][crate::sqlite::SqliteFunctionBehavior] flags.
1059    ///
1060    /// Requires SQLite 3.31.0 or later, otherwise returns an error.
1061    pub fn set_trusted_schema(&mut self, trusted: bool) -> QueryResult<()> {
1062        self.raw_connection
1063            .set_db_config_bool(ffi::SQLITE_DBCONFIG_TRUSTED_SCHEMA, trusted)
1064    }
1065
1066    /// Check if trusted schema mode is enabled.
1067    ///
1068    /// See [`set_trusted_schema`][Self::set_trusted_schema] for details.
1069    pub fn is_trusted_schema(&self) -> QueryResult<bool> {
1070        self.raw_connection
1071            .get_db_config_bool(ffi::SQLITE_DBCONFIG_TRUSTED_SCHEMA)
1072    }
1073
1074    /// Runs the given closure with the `load_extension()` SQL function enabled,
1075    /// disabling it again afterwards.
1076    ///
1077    /// This controls the [`load_extension()`](https://www.sqlite.org/lang_corefunc.html#load_extension)
1078    /// **SQL function**, not the `sqlite3_load_extension()` C API (which Diesel
1079    /// does not expose). Extension loading is off by default, and scoping it to a
1080    /// closure keeps the window in which it is enabled as small as possible.
1081    ///
1082    /// Requires SQLite 3.13.0 or later, otherwise returns an error. Has no effect
1083    /// if SQLite was compiled with `SQLITE_OMIT_LOAD_EXTENSION`.
1084    ///
1085    /// # Panics
1086    ///
1087    /// If `f` panics, extension loading is disabled again before the panic
1088    /// resumes. no-std builds cannot catch the unwind, so there the flag is
1089    /// restored only on a normal return.
1090    ///
1091    /// # Example
1092    ///
1093    /// ```rust
1094    /// # include!("../../doctest_setup.rs");
1095    /// # fn main() {
1096    /// #     let mut conn = SqliteConnection::establish(":memory:").unwrap();
1097    /// let result: QueryResult<()> = conn.with_load_extension_enabled(|_conn| Ok(()));
1098    /// result.unwrap();
1099    /// # }
1100    /// ```
1101    pub fn with_load_extension_enabled<R, E>(
1102        &mut self,
1103        f: impl FnOnce(&mut Self) -> Result<R, E>,
1104    ) -> Result<R, E>
1105    where
1106        E: From<crate::result::Error>,
1107    {
1108        self.set_load_extension_enabled(true)?;
1109
1110        // On std builds, catch a panic from `f` so extension loading is restored
1111        // before the panic is resumed. no-std cannot catch unwinding, so there
1112        // the flag is restored only on a normal return.
1113        #[cfg(feature = "std")]
1114        {
1115            match std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| f(self))) {
1116                Ok(r) => {
1117                    self.set_load_extension_enabled(false)?;
1118                    r
1119                }
1120                Err(panic) => {
1121                    let _ = self.set_load_extension_enabled(false);
1122                    std::panic::resume_unwind(panic);
1123                }
1124            }
1125        }
1126        #[cfg(not(feature = "std"))]
1127        {
1128            let r = f(self);
1129            self.set_load_extension_enabled(false)?;
1130            r
1131        }
1132    }
1133
1134    fn set_load_extension_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1135        self.raw_connection
1136            .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, enabled)
1137    }
1138
1139    #[cfg(test)]
1140    fn is_load_extension_enabled(&self) -> QueryResult<bool> {
1141        self.raw_connection
1142            .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION)
1143    }
1144
1145    /// Enable or disable the `fts3_tokenizer()` SQL function.
1146    ///
1147    /// The [`fts3_tokenizer()`](https://www.sqlite.org/fts3.html#f3tknzr) function
1148    /// allows overloading the default FTS3/FTS4 tokenizer, which can be exploited
1149    /// if an attacker can execute arbitrary SQL. Disable it unless you need custom
1150    /// FTS3 tokenizers.
1151    ///
1152    /// Requires SQLite 3.12.0 or later, otherwise returns an error.
1153    pub fn set_fts3_tokenizer_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1154        self.raw_connection
1155            .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, enabled)
1156    }
1157
1158    /// Check if the `fts3_tokenizer()` SQL function is enabled.
1159    ///
1160    /// See [`set_fts3_tokenizer_enabled`][Self::set_fts3_tokenizer_enabled] for details.
1161    pub fn is_fts3_tokenizer_enabled(&self) -> QueryResult<bool> {
1162        self.raw_connection
1163            .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER)
1164    }
1165
1166    /// Enable or disable direct writes to `sqlite_master`.
1167    ///
1168    /// When enabled, allows direct modification of the `sqlite_master` table,
1169    /// which can corrupt the database if misused. Keep it disabled unless you
1170    /// need to repair or modify the schema directly. Defensive mode
1171    /// ([`set_defensive`][Self::set_defensive]) also prevents this.
1172    ///
1173    /// Requires SQLite 3.28.0 or later, otherwise returns an error.
1174    pub fn set_writable_schema(&mut self, enabled: bool) -> QueryResult<()> {
1175        self.raw_connection
1176            .set_db_config_bool(ffi::SQLITE_DBCONFIG_WRITABLE_SCHEMA, enabled)
1177    }
1178
1179    /// Check if direct writes to `sqlite_master` are enabled.
1180    ///
1181    /// See [`set_writable_schema`][Self::set_writable_schema] for details.
1182    pub fn is_writable_schema(&self) -> QueryResult<bool> {
1183        self.raw_connection
1184            .get_db_config_bool(ffi::SQLITE_DBCONFIG_WRITABLE_SCHEMA)
1185    }
1186
1187    /// Enable or disable ATTACH from creating new database files.
1188    ///
1189    /// When disabled, [`ATTACH`](https://www.sqlite.org/lang_attach.html) can only
1190    /// open existing database files, not create new ones. Disable it where
1191    /// database file creation should be restricted.
1192    ///
1193    /// Requires SQLite 3.49.0 or later, otherwise returns an error.
1194    pub fn set_attach_create_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1195        self.raw_connection
1196            .set_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE, enabled)
1197    }
1198
1199    /// Check if ATTACH can create new database files.
1200    ///
1201    /// See [`set_attach_create_enabled`][Self::set_attach_create_enabled] for details.
1202    pub fn is_attach_create_enabled(&self) -> QueryResult<bool> {
1203        self.raw_connection
1204            .get_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE)
1205    }
1206
1207    /// Enable or disable ATTACH from opening databases in write mode.
1208    ///
1209    /// When disabled, all attached databases are opened as read-only. Disable it
1210    /// to restrict write access to attached databases.
1211    ///
1212    /// Requires SQLite 3.49.0 or later, otherwise returns an error.
1213    pub fn set_attach_write_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1214        self.raw_connection
1215            .set_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE, enabled)
1216    }
1217
1218    /// Check if ATTACH can open databases in write mode.
1219    ///
1220    /// See [`set_attach_write_enabled`][Self::set_attach_write_enabled] for details.
1221    pub fn is_attach_write_enabled(&self) -> QueryResult<bool> {
1222        self.raw_connection
1223            .get_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE)
1224    }
1225
1226    /// Enable or disable trigger execution.
1227    ///
1228    /// When disabled, triggers will not fire for any DML operations.
1229    ///
1230    /// Requires SQLite 3.8.7 or later, otherwise returns an error.
1231    pub fn set_triggers_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1232        self.raw_connection
1233            .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_TRIGGER, enabled)
1234    }
1235
1236    /// Check if trigger execution is enabled.
1237    ///
1238    /// See [`set_triggers_enabled`][Self::set_triggers_enabled] for details.
1239    pub fn are_triggers_enabled(&self) -> QueryResult<bool> {
1240        self.raw_connection
1241            .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_TRIGGER)
1242    }
1243
1244    /// Enable or disable view expansion.
1245    ///
1246    /// When disabled, queries against views will fail.
1247    ///
1248    /// Requires SQLite 3.30.0 or later, otherwise returns an error.
1249    pub fn set_views_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1250        self.raw_connection
1251            .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_VIEW, enabled)
1252    }
1253
1254    /// Check if view expansion is enabled.
1255    ///
1256    /// See [`set_views_enabled`][Self::set_views_enabled] for details.
1257    pub fn are_views_enabled(&self) -> QueryResult<bool> {
1258        self.raw_connection
1259            .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_VIEW)
1260    }
1261
1262    /// Enable or disable foreign key constraint enforcement.
1263    ///
1264    /// This is equivalent to `PRAGMA foreign_keys = ON/OFF`.
1265    ///
1266    /// Requires SQLite 3.8.7 or later, otherwise returns an error.
1267    pub fn set_foreign_keys_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1268        self.raw_connection
1269            .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FKEY, enabled)
1270    }
1271
1272    /// Check if foreign key constraints are enabled.
1273    ///
1274    /// See [`set_foreign_keys_enabled`][Self::set_foreign_keys_enabled] for details.
1275    pub fn are_foreign_keys_enabled(&self) -> QueryResult<bool> {
1276        self.raw_connection
1277            .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FKEY)
1278    }
1279
1280    /// Enable or disable double-quoted strings in DML statements.
1281    ///
1282    /// When enabled, double-quoted strings are interpreted as string literals
1283    /// rather than identifiers, a legacy behavior that can cause issues. Disable
1284    /// it for stricter SQL compliance.
1285    ///
1286    /// Requires SQLite 3.29.0 or later, otherwise returns an error.
1287    pub fn set_double_quoted_strings_dml(&mut self, enabled: bool) -> QueryResult<()> {
1288        self.raw_connection
1289            .set_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DML, enabled)
1290    }
1291
1292    /// Check if double-quoted strings in DML are enabled.
1293    ///
1294    /// See [`set_double_quoted_strings_dml`][Self::set_double_quoted_strings_dml] for details.
1295    pub fn are_double_quoted_strings_dml_enabled(&self) -> QueryResult<bool> {
1296        self.raw_connection
1297            .get_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DML)
1298    }
1299
1300    /// Enable or disable double-quoted strings in DDL statements.
1301    ///
1302    /// When enabled, double-quoted strings are interpreted as string literals
1303    /// rather than identifiers, a legacy behavior that can cause issues. Disable
1304    /// it for stricter SQL compliance.
1305    ///
1306    /// Requires SQLite 3.29.0 or later, otherwise returns an error.
1307    pub fn set_double_quoted_strings_ddl(&mut self, enabled: bool) -> QueryResult<()> {
1308        self.raw_connection
1309            .set_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DDL, enabled)
1310    }
1311
1312    /// Check if double-quoted strings in DDL are enabled.
1313    ///
1314    /// See [`set_double_quoted_strings_ddl`][Self::set_double_quoted_strings_ddl] for details.
1315    pub fn are_double_quoted_strings_ddl_enabled(&self) -> QueryResult<bool> {
1316        self.raw_connection
1317            .get_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DDL)
1318    }
1319
1320    fn register_diesel_sql_functions(&self) -> QueryResult<()> {
1321        use crate::sql_types::{Integer, Text};
1322
1323        // This function has side effects (creates triggers), so it should not
1324        // be deterministic. We use DIRECTONLY to prevent it from being called
1325        // from malicious schema objects in untrusted databases.
1326        functions::register::<Text, Integer, _, _, _>(
1327            &self.raw_connection,
1328            "diesel_manage_updated_at",
1329            SqliteFunctionBehavior::DIRECTONLY,
1330            |conn, table_name: String| {
1331                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!(
1332                    include_str!("diesel_manage_updated_at.sql"),
1333                    table_name = table_name
1334                ))
1335                .expect("Failed to create trigger");
1336                0 // have to return *something*
1337            },
1338        )
1339    }
1340
1341    fn establish_inner(database_url: &str) -> Result<SqliteConnection, ConnectionError> {
1342        use crate::result::ConnectionError::CouldntSetupConfiguration;
1343        let raw_connection = RawConnection::establish(database_url)?;
1344        let conn = Self {
1345            statement_cache: StatementCache::new(),
1346            raw_connection,
1347            transaction_state: AnsiTransactionManager::default(),
1348            metadata_lookup: (),
1349            instrumentation: DynInstrumentation::none(),
1350            serialized_data: Vec::new(),
1351        };
1352        conn.register_diesel_sql_functions()
1353            .map_err(CouldntSetupConfiguration)?;
1354        Ok(conn)
1355    }
1356}
1357
1358fn error_message(err_code: libc::c_int) -> &'static str {
1359    ffi::code_to_str(err_code)
1360}
1361
1362#[cfg(test)]
1363mod tests {
1364    use super::*;
1365    use crate::dsl::sql;
1366    use crate::prelude::*;
1367    use crate::sql_types::{Integer, Text};
1368    use crate::sqlite::SqliteFunctionBehavior;
1369
1370    fn connection() -> SqliteConnection {
1371        SqliteConnection::establish(":memory:").unwrap()
1372    }
1373
1374    #[diesel_test_helper::test]
1375    #[allow(unsafe_code)]
1376    fn with_raw_connection_can_return_values() {
1377        let connection = &mut connection();
1378
1379        // SAFETY: We only read connection status, which doesn't modify state.
1380        let autocommit_status = unsafe {
1381            connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1382        };
1383
1384        // Outside a transaction, autocommit should be enabled (returns non-zero)
1385        assert_ne!(autocommit_status, 0, "Expected autocommit to be enabled");
1386    }
1387
1388    #[diesel_test_helper::test]
1389    #[allow(unsafe_code)]
1390    fn with_raw_connection_works_after_diesel_operations() {
1391        let connection = &mut connection();
1392
1393        // First, do some Diesel operations
1394        crate::sql_query("CREATE TABLE test_table (id INTEGER PRIMARY KEY, value TEXT)")
1395            .execute(connection)
1396            .unwrap();
1397        crate::sql_query("INSERT INTO test_table (value) VALUES ('hello')")
1398            .execute(connection)
1399            .unwrap();
1400
1401        // SAFETY: We only read the last insert rowid, which is a read-only operation.
1402        let last_rowid = unsafe {
1403            connection.with_raw_connection(|raw_conn| ffi::sqlite3_last_insert_rowid(raw_conn))
1404        };
1405
1406        assert_eq!(last_rowid, 1, "Last insert rowid should be 1");
1407
1408        // Verify Diesel still works after using raw connection
1409        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM test_table")
1410            .get_result(connection)
1411            .unwrap();
1412        assert_eq!(count, 1);
1413    }
1414
1415    #[diesel_test_helper::test]
1416    #[allow(unsafe_code)]
1417    fn with_raw_connection_can_execute_raw_sql() {
1418        let connection = &mut connection();
1419
1420        // Create a table using Diesel first
1421        crate::sql_query("CREATE TABLE raw_test (id INTEGER PRIMARY KEY, name TEXT)")
1422            .execute(connection)
1423            .unwrap();
1424
1425        // SAFETY: We execute a simple INSERT via raw SQLite API.
1426        // This modifies the database but in a way compatible with Diesel.
1427        let result = unsafe {
1428            connection.with_raw_connection(|raw_conn| {
1429                let sql = c"INSERT INTO raw_test (name) VALUES ('from_raw')";
1430                let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
1431                let rc = ffi::sqlite3_exec(
1432                    raw_conn,
1433                    sql.as_ptr(),
1434                    None,
1435                    core::ptr::null_mut(),
1436                    &mut err_msg,
1437                );
1438                if rc != ffi::SQLITE_OK && !err_msg.is_null() {
1439                    ffi::sqlite3_free(err_msg as *mut libc::c_void);
1440                }
1441                rc
1442            })
1443        };
1444
1445        assert_eq!(result, ffi::SQLITE_OK, "Raw SQL execution should succeed");
1446
1447        // Verify the insert worked using Diesel
1448        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM raw_test")
1449            .get_result(connection)
1450            .unwrap();
1451        assert_eq!(count, 1);
1452
1453        let name: String = sql::<Text>("SELECT name FROM raw_test WHERE id = 1")
1454            .get_result(connection)
1455            .unwrap();
1456        assert_eq!(name, "from_raw");
1457    }
1458
1459    #[diesel_test_helper::test]
1460    #[allow(unsafe_code)]
1461    fn with_raw_connection_works_within_transaction() {
1462        let connection = &mut connection();
1463
1464        crate::sql_query("CREATE TABLE txn_test (id INTEGER PRIMARY KEY, value INTEGER)")
1465            .execute(connection)
1466            .unwrap();
1467
1468        connection
1469            .transaction::<_, crate::result::Error, _>(|conn| {
1470                crate::sql_query("INSERT INTO txn_test (value) VALUES (42)")
1471                    .execute(conn)
1472                    .unwrap();
1473
1474                // SAFETY: We only read the autocommit status inside a transaction.
1475                let autocommit = unsafe {
1476                    conn.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1477                };
1478
1479                // Inside a transaction, autocommit should be disabled (returns 0)
1480                assert_eq!(
1481                    autocommit, 0,
1482                    "Autocommit should be disabled inside transaction"
1483                );
1484
1485                Ok(())
1486            })
1487            .unwrap();
1488
1489        // After transaction commits, autocommit should be re-enabled
1490        let autocommit = unsafe {
1491            connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1492        };
1493        assert_ne!(
1494            autocommit, 0,
1495            "Autocommit should be enabled after transaction"
1496        );
1497    }
1498
1499    #[diesel_test_helper::test]
1500    #[allow(unsafe_code)]
1501    fn with_raw_connection_can_read_database_filename() {
1502        let connection = &mut connection();
1503
1504        // SAFETY: We only read the database filename, which is a read-only operation.
1505        let filename = unsafe {
1506            connection.with_raw_connection(|raw_conn| {
1507                let db_name = c"main";
1508                let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1509                if filename_ptr.is_null() {
1510                    None
1511                } else {
1512                    // For :memory: databases, this might return empty string or special value
1513                    let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1514                    Some(cstr.to_string_lossy().into_owned())
1515                }
1516            })
1517        };
1518
1519        // For in-memory databases, sqlite3_db_filename returns a non-null pointer
1520        // to an empty string
1521        assert_eq!(
1522            filename,
1523            Some(String::new()),
1524            "In-memory database filename should be an empty string"
1525        );
1526    }
1527
1528    #[diesel_test_helper::test]
1529    #[allow(unsafe_code)]
1530    fn with_raw_connection_changes_count() {
1531        let connection = &mut connection();
1532
1533        crate::sql_query("CREATE TABLE changes_test (id INTEGER PRIMARY KEY, value INTEGER)")
1534            .execute(connection)
1535            .unwrap();
1536
1537        crate::sql_query("INSERT INTO changes_test (value) VALUES (1), (2), (3)")
1538            .execute(connection)
1539            .unwrap();
1540
1541        // Update all rows using raw connection
1542        let changes = unsafe {
1543            connection.with_raw_connection(|raw_conn| {
1544                let sql = c"UPDATE changes_test SET value = value + 10";
1545                let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
1546                let rc = ffi::sqlite3_exec(
1547                    raw_conn,
1548                    sql.as_ptr(),
1549                    None,
1550                    core::ptr::null_mut(),
1551                    &mut err_msg,
1552                );
1553                if rc != ffi::SQLITE_OK && !err_msg.is_null() {
1554                    ffi::sqlite3_free(err_msg as *mut libc::c_void);
1555                    return -1;
1556                }
1557                ffi::sqlite3_changes(raw_conn)
1558            })
1559        };
1560
1561        assert_eq!(changes, 3, "Should have updated 3 rows");
1562
1563        // Verify the updates using Diesel
1564        let values: Vec<i32> = sql::<Integer>("SELECT value FROM changes_test ORDER BY id")
1565            .load(connection)
1566            .unwrap();
1567        assert_eq!(values, vec![11, 12, 13]);
1568    }
1569
1570    // catch_unwind is not available in WASM (panic = "abort")
1571    #[diesel_test_helper::test]
1572    #[allow(unsafe_code)]
1573    #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1574    fn with_raw_connection_recovers_after_panic() {
1575        let connection = &mut connection();
1576
1577        crate::sql_query("CREATE TABLE panic_test (id INTEGER PRIMARY KEY, value TEXT)")
1578            .execute(connection)
1579            .unwrap();
1580
1581        // Panic inside the callback
1582        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
1583            connection.with_raw_connection(|_raw_conn| {
1584                panic!("intentional panic inside with_raw_connection");
1585            })
1586        }));
1587        assert!(result.is_err(), "Should have caught the panic");
1588
1589        // Connection should still be usable after the panic
1590        crate::sql_query("INSERT INTO panic_test (value) VALUES ('after_panic')")
1591            .execute(connection)
1592            .unwrap();
1593
1594        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM panic_test")
1595            .get_result(connection)
1596            .unwrap();
1597        assert_eq!(count, 1, "Connection should work after panic in callback");
1598    }
1599
1600    // Filesystem access is not available in WASM
1601    #[diesel_test_helper::test]
1602    #[allow(unsafe_code)]
1603    #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1604    fn with_raw_connection_can_read_file_database_filename() {
1605        let dir = std::env::temp_dir().join("diesel_test_filename.db");
1606        let db_path = dir.to_str().unwrap();
1607
1608        // Clean up from any previous run
1609        let _ = std::fs::remove_file(db_path);
1610
1611        let connection = &mut SqliteConnection::establish(db_path).unwrap();
1612
1613        // SAFETY: We only read the database filename, which is a read-only operation.
1614        let filename = unsafe {
1615            connection.with_raw_connection(|raw_conn| {
1616                let db_name = c"main";
1617                let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1618                if filename_ptr.is_null() {
1619                    None
1620                } else {
1621                    let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1622                    Some(cstr.to_string_lossy().into_owned())
1623                }
1624            })
1625        };
1626
1627        let filename = filename.expect("File-based database should have a filename");
1628        assert!(
1629            filename.contains("diesel_test_filename.db"),
1630            "Filename should contain the database name, got: {filename}"
1631        );
1632
1633        // Clean up
1634        let _ = std::fs::remove_file(db_path);
1635    }
1636
1637    #[declare_sql_function]
1638    extern "SQL" {
1639        fn fun_case(x: Text) -> Text;
1640        fn my_add(x: Integer, y: Integer) -> Integer;
1641        fn answer() -> Integer;
1642        fn add_counter(x: Integer) -> Integer;
1643
1644        #[aggregate]
1645        fn my_sum(expr: Integer) -> Integer;
1646        #[aggregate]
1647        fn range_max(expr1: Integer, expr2: Integer, expr3: Integer) -> Nullable<Integer>;
1648    }
1649
1650    #[diesel_test_helper::test]
1651    fn database_serializes_and_deserializes_successfully() {
1652        let expected_users = vec![
1653            (
1654                1,
1655                "John Doe".to_string(),
1656                "john.doe@example.com".to_string(),
1657            ),
1658            (
1659                2,
1660                "Jane Doe".to_string(),
1661                "jane.doe@example.com".to_string(),
1662            ),
1663        ];
1664
1665        let conn1 = &mut connection();
1666        let _ =
1667            crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1668                .execute(conn1);
1669        let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1670            .execute(conn1);
1671
1672        for _i in 0..2 {
1673            let serialized_database = conn1.serialize_database_to_buffer();
1674            let conn2 = &mut connection();
1675            conn2
1676                .deserialize_readonly_database_from_buffer(serialized_database.as_slice())
1677                .unwrap();
1678
1679            let query =
1680                sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1681            let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1682
1683            assert_eq!(expected_users, actual_users);
1684            // drop the database here
1685            // and requery the database to make sure the database owns
1686            // required data
1687            std::mem::drop(serialized_database);
1688            let query =
1689                sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1690            let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1691
1692            assert_eq!(expected_users, actual_users);
1693        }
1694    }
1695
1696    #[diesel_test_helper::test]
1697    fn database_deserialize_random_bytes() {
1698        let buffer = vec![0, 1, 2, 3, 4];
1699        let conn = &mut SqliteConnection::establish(":memory:").unwrap();
1700
1701        conn.deserialize_readonly_database_from_buffer(&buffer)
1702            .unwrap();
1703
1704        let r = sql::<Integer>("SELECT id FROM users").load::<i32>(conn);
1705
1706        assert!(r.is_err());
1707        assert_eq!(r.unwrap_err().to_string(), "file is not a database");
1708
1709        let conn = &mut SqliteConnection::establish(":memory:").unwrap();
1710
1711        let _ =
1712            crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1713                .execute(conn);
1714        let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1715            .execute(conn);
1716
1717        let db = conn.serialize_database_to_buffer();
1718        // only get a valid header, but append garbage
1719        let mut bad_buffer = db[..100].to_vec();
1720        bad_buffer.extend(b"whatever");
1721        conn.deserialize_readonly_database_from_buffer(&bad_buffer)
1722            .unwrap();
1723
1724        let r = sql::<Integer>("SELECT id FROM users").load::<i32>(conn);
1725
1726        assert!(r.is_err());
1727        assert_eq!(
1728            r.unwrap_err().to_string(),
1729            "database disk image is malformed"
1730        );
1731
1732        // only get a valid header, but append garbage
1733        let mut size_fitting_bad_buffer = db[..100].to_vec();
1734        size_fitting_bad_buffer.extend(
1735            core::iter::repeat(b"abcdefghij")
1736                .flatten()
1737                .take(db.len() - 100),
1738        );
1739        let r = conn.deserialize_readonly_database_from_buffer(&size_fitting_bad_buffer);
1740
1741        assert!(r.is_err());
1742        assert_eq!(
1743            r.unwrap_err().to_string(),
1744            "database disk image is malformed"
1745        );
1746    }
1747
1748    #[diesel_test_helper::test]
1749    fn register_custom_function() {
1750        let connection = &mut connection();
1751        fun_case_utils::register_impl(connection, |x: String| {
1752            x.chars()
1753                .enumerate()
1754                .map(|(i, c)| {
1755                    if i % 2 == 0 {
1756                        c.to_lowercase().to_string()
1757                    } else {
1758                        c.to_uppercase().to_string()
1759                    }
1760                })
1761                .collect::<String>()
1762        })
1763        .unwrap();
1764
1765        let mapped_string = crate::select(fun_case("foobar"))
1766            .get_result::<String>(connection)
1767            .unwrap();
1768        assert_eq!("fOoBaR", mapped_string);
1769    }
1770
1771    #[diesel_test_helper::test]
1772    fn register_multiarg_function() {
1773        let connection = &mut connection();
1774        my_add_utils::register_impl(connection, |x: i32, y: i32| x + y).unwrap();
1775
1776        let added = crate::select(my_add(1, 2)).get_result::<i32>(connection);
1777        assert_eq!(Ok(3), added);
1778    }
1779
1780    #[diesel_test_helper::test]
1781    fn register_noarg_function() {
1782        let connection = &mut connection();
1783        answer_utils::register_impl(connection, || 42).unwrap();
1784
1785        let answer = crate::select(answer()).get_result::<i32>(connection);
1786        assert_eq!(Ok(42), answer);
1787    }
1788
1789    #[diesel_test_helper::test]
1790    fn register_nondeterministic_noarg_function() {
1791        let connection = &mut connection();
1792        answer_utils::register_nondeterministic_impl(connection, || 42).unwrap();
1793
1794        let answer = crate::select(answer()).get_result::<i32>(connection);
1795        assert_eq!(Ok(42), answer);
1796    }
1797
1798    #[diesel_test_helper::test]
1799    fn register_nondeterministic_function() {
1800        let connection = &mut connection();
1801        let mut y = 0;
1802        add_counter_utils::register_nondeterministic_impl(connection, move |x: i32| {
1803            y += 1;
1804            x + y
1805        })
1806        .unwrap();
1807
1808        let added = crate::select((add_counter(1), add_counter(1), add_counter(1)))
1809            .get_result::<(i32, i32, i32)>(connection);
1810        assert_eq!(Ok((2, 3, 4)), added);
1811    }
1812
1813    #[derive(Default)]
1814    struct MySum {
1815        sum: i32,
1816    }
1817
1818    impl SqliteAggregateFunction<i32> for MySum {
1819        type Output = i32;
1820
1821        fn step(&mut self, expr: i32) {
1822            self.sum += expr;
1823        }
1824
1825        fn finalize(aggregator: Option<Self>) -> Self::Output {
1826            aggregator.map(|a| a.sum).unwrap_or_default()
1827        }
1828    }
1829
1830    table! {
1831        my_sum_example {
1832            id -> Integer,
1833            value -> Integer,
1834        }
1835    }
1836
1837    #[diesel_test_helper::test]
1838    fn register_aggregate_function() {
1839        use self::my_sum_example::dsl::*;
1840
1841        let connection = &mut connection();
1842        crate::sql_query(
1843            "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1844        )
1845        .execute(connection)
1846        .unwrap();
1847        crate::sql_query("INSERT INTO my_sum_example (value) VALUES (1), (2), (3)")
1848            .execute(connection)
1849            .unwrap();
1850
1851        my_sum_utils::register_impl_with_behavior::<MySum, _>(
1852            connection,
1853            SqliteFunctionBehavior::DETERMINISTIC,
1854        )
1855        .unwrap();
1856
1857        let result = my_sum_example
1858            .select(my_sum(value))
1859            .get_result::<i32>(connection);
1860        assert_eq!(Ok(6), result);
1861    }
1862
1863    #[diesel_test_helper::test]
1864    fn register_aggregate_function_returns_finalize_default_on_empty_set() {
1865        use self::my_sum_example::dsl::*;
1866
1867        let connection = &mut connection();
1868        crate::sql_query(
1869            "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1870        )
1871        .execute(connection)
1872        .unwrap();
1873
1874        my_sum_utils::register_impl_with_behavior::<MySum, _>(
1875            connection,
1876            SqliteFunctionBehavior::DETERMINISTIC,
1877        )
1878        .unwrap();
1879
1880        let result = my_sum_example
1881            .select(my_sum(value))
1882            .get_result::<i32>(connection);
1883        assert_eq!(Ok(0), result);
1884    }
1885
1886    #[derive(Default)]
1887    struct RangeMax<T> {
1888        max_value: Option<T>,
1889    }
1890
1891    impl<T: Default + Ord + Copy + Clone> SqliteAggregateFunction<(T, T, T)> for RangeMax<T> {
1892        type Output = Option<T>;
1893
1894        fn step(&mut self, (x0, x1, x2): (T, T, T)) {
1895            let max = if x0 >= x1 && x0 >= x2 {
1896                x0
1897            } else if x1 >= x0 && x1 >= x2 {
1898                x1
1899            } else {
1900                x2
1901            };
1902
1903            self.max_value = match self.max_value {
1904                Some(current_max_value) if max > current_max_value => Some(max),
1905                None => Some(max),
1906                _ => self.max_value,
1907            };
1908        }
1909
1910        fn finalize(aggregator: Option<Self>) -> Self::Output {
1911            aggregator?.max_value
1912        }
1913    }
1914
1915    table! {
1916        range_max_example {
1917            id -> Integer,
1918            value1 -> Integer,
1919            value2 -> Integer,
1920            value3 -> Integer,
1921        }
1922    }
1923
1924    #[diesel_test_helper::test]
1925    fn register_aggregate_multiarg_function() {
1926        use self::range_max_example::dsl::*;
1927
1928        let connection = &mut connection();
1929        crate::sql_query(
1930            r#"CREATE TABLE range_max_example (
1931                id integer primary key autoincrement,
1932                value1 integer,
1933                value2 integer,
1934                value3 integer
1935            )"#,
1936        )
1937        .execute(connection)
1938        .unwrap();
1939        crate::sql_query(
1940            "INSERT INTO range_max_example (value1, value2, value3) VALUES (3, 2, 1), (2, 2, 2)",
1941        )
1942        .execute(connection)
1943        .unwrap();
1944
1945        range_max_utils::register_impl_with_behavior::<RangeMax<i32>, _, _, _>(
1946            connection,
1947            SqliteFunctionBehavior::DETERMINISTIC,
1948        )
1949        .unwrap();
1950        let result = range_max_example
1951            .select(range_max(value1, value2, value3))
1952            .get_result::<Option<i32>>(connection)
1953            .unwrap();
1954        assert_eq!(Some(3), result);
1955    }
1956
1957    table! {
1958        my_collation_example {
1959            id -> Integer,
1960            value -> Text,
1961        }
1962    }
1963
1964    #[diesel_test_helper::test]
1965    fn register_collation_function() {
1966        use self::my_collation_example::dsl::*;
1967
1968        let connection = &mut connection();
1969
1970        connection
1971            .register_collation("RUSTNOCASE", |rhs, lhs| {
1972                rhs.to_lowercase().cmp(&lhs.to_lowercase())
1973            })
1974            .unwrap();
1975
1976        crate::sql_query(
1977                "CREATE TABLE my_collation_example (id integer primary key autoincrement, value text collate RUSTNOCASE)",
1978            ).execute(connection)
1979            .unwrap();
1980        crate::sql_query(
1981            "INSERT INTO my_collation_example (value) VALUES ('foo'), ('FOo'), ('f00')",
1982        )
1983        .execute(connection)
1984        .unwrap();
1985
1986        let result = my_collation_example
1987            .filter(value.eq("foo"))
1988            .select(value)
1989            .load::<String>(connection);
1990        assert_eq!(
1991            Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
1992            result.as_ref().map(|vec| vec.as_ref())
1993        );
1994
1995        let result = my_collation_example
1996            .filter(value.eq("FOO"))
1997            .select(value)
1998            .load::<String>(connection);
1999        assert_eq!(
2000            Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
2001            result.as_ref().map(|vec| vec.as_ref())
2002        );
2003
2004        let result = my_collation_example
2005            .filter(value.eq("f00"))
2006            .select(value)
2007            .load::<String>(connection);
2008        assert_eq!(
2009            Ok(&["f00".to_owned()][..]),
2010            result.as_ref().map(|vec| vec.as_ref())
2011        );
2012
2013        let result = my_collation_example
2014            .filter(value.eq("F00"))
2015            .select(value)
2016            .load::<String>(connection);
2017        assert_eq!(
2018            Ok(&["f00".to_owned()][..]),
2019            result.as_ref().map(|vec| vec.as_ref())
2020        );
2021
2022        let result = my_collation_example
2023            .filter(value.eq("oof"))
2024            .select(value)
2025            .load::<String>(connection);
2026        assert_eq!(Ok(&[][..]), result.as_ref().map(|vec| vec.as_ref()));
2027    }
2028
2029    // regression test for https://github.com/diesel-rs/diesel/issues/3425
2030    #[diesel_test_helper::test]
2031    fn test_correct_serialization_of_owned_strings() {
2032        use crate::prelude::*;
2033
2034        #[derive(Debug, crate::expression::AsExpression)]
2035        #[diesel(sql_type = diesel::sql_types::Text)]
2036        struct CustomWrapper(String);
2037
2038        impl crate::serialize::ToSql<Text, Sqlite> for CustomWrapper {
2039            fn to_sql<'b>(
2040                &'b self,
2041                out: &mut crate::serialize::Output<'b, '_, Sqlite>,
2042            ) -> crate::serialize::Result {
2043                out.set_value(self.0.to_string());
2044                Ok(crate::serialize::IsNull::No)
2045            }
2046        }
2047
2048        let connection = &mut connection();
2049
2050        let res = crate::select(
2051            CustomWrapper("".into())
2052                .into_sql::<crate::sql_types::Text>()
2053                .nullable(),
2054        )
2055        .get_result::<Option<String>>(connection)
2056        .unwrap();
2057        assert_eq!(res, Some(String::new()));
2058    }
2059
2060    #[diesel_test_helper::test]
2061    fn test_correct_serialization_of_owned_bytes() {
2062        use crate::prelude::*;
2063
2064        #[derive(Debug, crate::expression::AsExpression)]
2065        #[diesel(sql_type = diesel::sql_types::Binary)]
2066        struct CustomWrapper(Vec<u8>);
2067
2068        impl crate::serialize::ToSql<crate::sql_types::Binary, Sqlite> for CustomWrapper {
2069            fn to_sql<'b>(
2070                &'b self,
2071                out: &mut crate::serialize::Output<'b, '_, Sqlite>,
2072            ) -> crate::serialize::Result {
2073                out.set_value(self.0.clone());
2074                Ok(crate::serialize::IsNull::No)
2075            }
2076        }
2077
2078        let connection = &mut connection();
2079
2080        let res = crate::select(
2081            CustomWrapper(Vec::new())
2082                .into_sql::<crate::sql_types::Binary>()
2083                .nullable(),
2084        )
2085        .get_result::<Option<Vec<u8>>>(connection)
2086        .unwrap();
2087        assert_eq!(res, Some(Vec::new()));
2088    }
2089
2090    #[diesel_test_helper::test]
2091    fn correctly_handle_empty_query() {
2092        let check_empty_query_error = |r: crate::QueryResult<usize>| {
2093            assert!(r.is_err());
2094            let err = r.unwrap_err();
2095            assert!(
2096                matches!(err, crate::result::Error::QueryBuilderError(ref b) if b.is::<crate::result::EmptyQuery>()),
2097                "Expected a query builder error, but got {err}"
2098            );
2099        };
2100        let connection = &mut SqliteConnection::establish(":memory:").unwrap();
2101        check_empty_query_error(crate::sql_query("").execute(connection));
2102        check_empty_query_error(crate::sql_query("   ").execute(connection));
2103        check_empty_query_error(crate::sql_query("\n\t").execute(connection));
2104        check_empty_query_error(crate::sql_query("-- SELECT 1;").execute(connection));
2105    }
2106
2107    #[diesel_test_helper::test]
2108    fn last_insert_rowid_returns_none_on_fresh_connection() {
2109        let conn = &mut connection();
2110        assert_eq!(conn.last_insert_rowid(), None);
2111    }
2112
2113    #[diesel_test_helper::test]
2114    fn last_insert_rowid_returns_rowid_after_insert() {
2115        let conn = &mut connection();
2116        crate::sql_query("CREATE TABLE li_test (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
2117            .execute(conn)
2118            .unwrap();
2119
2120        crate::sql_query("INSERT INTO li_test (val) VALUES ('a')")
2121            .execute(conn)
2122            .unwrap();
2123        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2124
2125        crate::sql_query("INSERT INTO li_test (val) VALUES ('b')")
2126            .execute(conn)
2127            .unwrap();
2128        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(2));
2129    }
2130
2131    #[diesel_test_helper::test]
2132    fn last_insert_rowid_unchanged_after_failed_insert() {
2133        let conn = &mut connection();
2134        crate::sql_query(
2135            "CREATE TABLE li_test2 (id INTEGER PRIMARY KEY, val TEXT NOT NULL UNIQUE)",
2136        )
2137        .execute(conn)
2138        .unwrap();
2139
2140        crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')")
2141            .execute(conn)
2142            .unwrap();
2143        let rowid = conn.last_insert_rowid();
2144        assert_eq!(rowid, NonZeroI64::new(1));
2145
2146        // This should fail due to UNIQUE constraint
2147        let result = crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')").execute(conn);
2148        assert!(result.is_err());
2149
2150        // rowid should be unchanged
2151        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2152    }
2153
2154    #[diesel_test_helper::test]
2155    fn last_insert_rowid_with_explicit_rowid() {
2156        let conn = &mut connection();
2157        crate::sql_query("CREATE TABLE li_test3 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
2158            .execute(conn)
2159            .unwrap();
2160
2161        crate::sql_query("INSERT INTO li_test3 (id, val) VALUES (42, 'a')")
2162            .execute(conn)
2163            .unwrap();
2164        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(42));
2165    }
2166
2167    #[diesel_test_helper::test]
2168    fn last_insert_rowid_unchanged_after_delete_and_update() {
2169        let conn = &mut connection();
2170        crate::sql_query("CREATE TABLE li_test4 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
2171            .execute(conn)
2172            .unwrap();
2173
2174        crate::sql_query("INSERT INTO li_test4 (val) VALUES ('a')")
2175            .execute(conn)
2176            .unwrap();
2177        let rowid = conn.last_insert_rowid();
2178        assert_eq!(rowid, NonZeroI64::new(1));
2179
2180        crate::sql_query("UPDATE li_test4 SET val = 'b' WHERE id = 1")
2181            .execute(conn)
2182            .unwrap();
2183        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2184
2185        crate::sql_query("DELETE FROM li_test4 WHERE id = 1")
2186            .execute(conn)
2187            .unwrap();
2188        assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2189    }
2190
2191    #[diesel_test_helper::test]
2192    fn read_bytes_from_blob() {
2193        table! {
2194            blobs {
2195                id -> Integer,
2196                data -> Blob,
2197                data2 -> Blob,
2198            }
2199        }
2200
2201        use std::io::Read;
2202
2203        let conn = &mut connection();
2204
2205        let _ =
2206            crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB, data2 BLOB)")
2207                .execute(conn);
2208
2209        let _ = crate::sql_query(
2210            "INSERT INTO blobs (data, data2) VALUES ('abc', 'def'), ('123', '456')",
2211        )
2212        .execute(conn);
2213
2214        let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2215        let mut buf = vec![];
2216        data.read_to_end(&mut buf).unwrap();
2217
2218        assert_eq!(buf, b"abc");
2219
2220        let mut data2 = conn.get_read_only_blob(blobs::data2, 1).unwrap();
2221        let mut buf = vec![];
2222        data2.read_to_end(&mut buf).unwrap();
2223
2224        assert_eq!(buf, b"def");
2225    }
2226
2227    #[diesel_test_helper::test]
2228    fn read_seek_bytes() {
2229        table! {
2230            blobs {
2231                id -> Integer,
2232                data -> Blob,
2233            }
2234        }
2235
2236        use std::io::Read;
2237        use std::io::Seek;
2238        use std::io::SeekFrom;
2239
2240        let conn = &mut connection();
2241
2242        let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
2243            .execute(conn);
2244
2245        let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abcdefghi')").execute(conn);
2246
2247        let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2248
2249        let mut buf = [0; 1];
2250        assert_eq!(data.read(&mut buf).unwrap(), 1);
2251        assert_eq!(&buf, b"a");
2252
2253        // Seek one forward
2254        assert_eq!(data.seek(SeekFrom::Current(1)).unwrap(), 2);
2255
2256        let mut buf = [0; 1];
2257        assert_eq!(data.read(&mut buf).unwrap(), 1);
2258        assert_eq!(&buf, b"c");
2259
2260        // Seek back to start
2261        assert_eq!(data.seek(SeekFrom::Start(0)).unwrap(), 0);
2262
2263        let mut buf = [0; 1];
2264        assert_eq!(data.read(&mut buf).unwrap(), 1);
2265        assert_eq!(&buf, b"a");
2266
2267        // Seek before start
2268        assert_eq!(data.seek(SeekFrom::Current(-10)).unwrap(), 0);
2269
2270        let mut buf = [0; 1];
2271        assert_eq!(data.read(&mut buf).unwrap(), 1);
2272        assert_eq!(&buf, b"a");
2273
2274        // Seek after end
2275        data.seek(SeekFrom::Current(100)).unwrap();
2276
2277        // Now we don't get any bytes back
2278        let mut buf = [0; 1];
2279        assert_eq!(data.read(&mut buf).unwrap(), 0);
2280    }
2281
2282    #[diesel_test_helper::test]
2283    fn use_conn_after_blob_drop() {
2284        table! {
2285            blobs {
2286                id -> Integer,
2287                data -> Blob,
2288            }
2289        }
2290
2291        let conn = &mut connection();
2292
2293        let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
2294            .execute(conn);
2295
2296        let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abc')").execute(conn);
2297
2298        let data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2299        drop(data);
2300
2301        let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('def')").execute(conn);
2302    }
2303
2304    #[diesel_test_helper::test]
2305    fn blob_transaction() {
2306        table! {
2307            blobs {
2308                id -> Integer,
2309                data -> Blob,
2310            }
2311        }
2312
2313        use std::io::Read;
2314
2315        let conn = &mut connection();
2316
2317        let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
2318            .execute(conn);
2319
2320        let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abc')").execute(conn);
2321
2322        {
2323            let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2324            let mut buf = vec![];
2325            data.read_to_end(&mut buf).unwrap();
2326            assert_eq!(buf, b"abc");
2327        }
2328
2329        let res = conn.exclusive_transaction(|conn| {
2330            crate::sql_query("UPDATE blobs SET data = 'def' WHERE id = 1").execute(conn)?;
2331
2332            let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2333            let mut buf = vec![];
2334            data.read_to_end(&mut buf).unwrap();
2335            assert_eq!(buf, b"def");
2336
2337            Result::<(), _>::Err(Error::RollbackTransaction)
2338        });
2339
2340        assert_eq!(res.unwrap_err(), Error::RollbackTransaction);
2341
2342        let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2343        let mut buf = vec![];
2344        data.read_to_end(&mut buf).unwrap();
2345        assert_eq!(buf, b"abc");
2346    }
2347
2348    #[diesel_test_helper::test]
2349    fn aggregate_function_works_with_aligned_data() {
2350        #[derive(Debug, Default)]
2351        #[repr(align(64))]
2352        struct OverAligned;
2353
2354        impl SqliteAggregateFunction<i32> for OverAligned {
2355            type Output = i64;
2356
2357            fn step(&mut self, _value: i32) {
2358                let need = core::mem::align_of::<Self>();
2359                let got = core::mem::align_of_val(self);
2360                assert_eq!(need, got);
2361            }
2362
2363            fn finalize(_agg: Option<Self>) -> i64 {
2364                0
2365            }
2366        }
2367        #[declare_sql_function]
2368        extern "SQL" {
2369            #[aggregate]
2370            fn over_aligned_sum(x: Integer) -> diesel::sql_types::BigInt;
2371        }
2372
2373        let mut conn = SqliteConnection::establish(":memory:").unwrap();
2374        over_aligned_sum_utils::register_impl::<OverAligned, _>(&mut conn).unwrap();
2375
2376        diesel::select(over_aligned_sum(1))
2377            .execute(&mut conn)
2378            .unwrap();
2379    }
2380
2381    #[diesel_test_helper::test]
2382    fn sum_twice() {
2383        #[derive(Default)]
2384        struct Sum(i32);
2385
2386        impl SqliteAggregateFunction<i32> for Sum {
2387            type Output = i32;
2388
2389            fn step(&mut self, value: i32) {
2390                self.0 += value;
2391            }
2392
2393            fn finalize(agg: Option<Self>) -> i32 {
2394                agg.map(|s| s.0).unwrap_or_default()
2395            }
2396        }
2397
2398        #[declare_sql_function]
2399        extern "SQL" {
2400            #[aggregate]
2401            fn my_sum(x: Integer) -> Integer;
2402        }
2403
2404        let mut conn = SqliteConnection::establish(":memory:").unwrap();
2405        my_sum_utils::register_impl::<Sum, _>(&mut conn).unwrap();
2406
2407        conn.batch_execute(
2408            "
2409            CREATE TABLE test(key1 INTEGER, key2 INTEGER);
2410            INSERT INTO test(key1, key2) VALUES (1, 2), (2, 4), (3, 6);
2411",
2412        )
2413        .unwrap();
2414
2415        table! {
2416            test (key1, key2) {
2417                key1 -> Integer,
2418                key2 -> Integer,
2419            }
2420        }
2421
2422        let (first_res, second_res) = test::table
2423            .select((my_sum(test::key1), my_sum(test::key2)))
2424            .get_result::<(i32, i32)>(&mut conn)
2425            .unwrap();
2426
2427        assert_eq!(first_res, 6);
2428        assert_eq!(second_res, 12);
2429
2430        conn.batch_execute("DELETE FROM test").unwrap();
2431        let (first_res, second_res) = test::table
2432            .select((my_sum(test::key1), my_sum(test::key2)))
2433            .get_result::<(i32, i32)>(&mut conn)
2434            .unwrap();
2435
2436        assert_eq!(first_res, 0);
2437        assert_eq!(second_res, 0);
2438    }
2439
2440    #[diesel_test_helper::test]
2441    fn test_injection() {
2442        diesel::table! {
2443            #[sql_name = "quote'table"]
2444            quote_table (id) {
2445                id -> Nullable<Integer>,
2446                name -> Nullable<Text>,
2447            }
2448        }
2449
2450        let mut conn = SqliteConnection::establish(":memory:").unwrap();
2451
2452        conn.batch_execute("CREATE TABLE \"quote'table\" (id INTEGER PRIMARY KEY, name TEXT);")
2453            .unwrap();
2454
2455        diesel::insert_into(quote_table::table)
2456            .values((quote_table::id.eq(1), quote_table::name.eq("Jane")))
2457            .execute(&mut conn)
2458            .unwrap();
2459
2460        let data = quote_table::table
2461            .load::<(Option<i32>, Option<String>)>(&mut conn)
2462            .unwrap();
2463        assert_eq!(data, [(Some(1), Some("Jane".to_owned()))]);
2464    }
2465
2466    #[diesel_test_helper::test]
2467    fn set_limit_returns_previous_value() {
2468        let mut conn = connection();
2469        let original = conn.get_limit(SqliteLimit::SqlLength);
2470
2471        // Setting a new value returns the old one, and a second set returns the
2472        // value installed by the first.
2473        assert_eq!(conn.set_limit(SqliteLimit::SqlLength, 1024), original);
2474        assert_eq!(conn.set_limit(SqliteLimit::SqlLength, 2048), 1024);
2475        assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 2048);
2476    }
2477
2478    #[diesel_test_helper::test]
2479    fn get_limit_does_not_mutate() {
2480        let conn = connection();
2481        let first = conn.get_limit(SqliteLimit::ExprDepth);
2482        // Querying is implemented by passing -1 to sqlite3_limit, which must
2483        // leave the limit unchanged.
2484        assert!(first > 0);
2485        assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), first);
2486    }
2487
2488    #[diesel_test_helper::test]
2489    fn set_limit_enforces_length() {
2490        let mut conn = connection();
2491        conn.set_limit(SqliteLimit::Length, 100);
2492
2493        assert!(
2494            crate::sql_query("SELECT length(randomblob(50))")
2495                .execute(&mut conn)
2496                .is_ok()
2497        );
2498        // A 500-byte blob exceeds the 100-byte row/value limit ("string or blob too big").
2499        assert!(
2500            crate::sql_query("SELECT length(randomblob(500))")
2501                .execute(&mut conn)
2502                .is_err()
2503        );
2504    }
2505
2506    #[diesel_test_helper::test]
2507    fn set_limit_enforces_column_count() {
2508        // A wide result set runs under the default column limit but fails once the limit is
2509        // lowered below its column count ("too many columns in result set").
2510        let wide = format!(
2511            "SELECT {}",
2512            (1..=30)
2513                .map(|i| i.to_string())
2514                .collect::<Vec<_>>()
2515                .join(", ")
2516        );
2517
2518        let mut unconstrained = connection();
2519        assert!(crate::sql_query(&wide).execute(&mut unconstrained).is_ok());
2520
2521        let mut conn = connection();
2522        conn.set_limit(SqliteLimit::ColumnCount, 10);
2523        assert!(crate::sql_query(&wide).execute(&mut conn).is_err());
2524    }
2525
2526    #[diesel_test_helper::test]
2527    fn set_limit_enforces_expr_depth() {
2528        let mut conn = connection();
2529        conn.set_limit(SqliteLimit::ExprDepth, 5);
2530
2531        assert!(crate::sql_query("SELECT 1+1").execute(&mut conn).is_ok());
2532        // A 40-deep addition tree exceeds the parse-tree depth of five.
2533        let deep = format!("SELECT {}1", "1+".repeat(40));
2534        assert!(crate::sql_query(&deep).execute(&mut conn).is_err());
2535    }
2536
2537    #[diesel_test_helper::test]
2538    fn set_limit_enforces_compound_select() {
2539        let mut conn = connection();
2540        conn.set_limit(SqliteLimit::CompoundSelect, 2);
2541
2542        assert!(
2543            crate::sql_query("SELECT 1 UNION SELECT 2")
2544                .execute(&mut conn)
2545                .is_ok()
2546        );
2547        // Five UNION terms exceed the limit of two ("too many terms in compound SELECT").
2548        assert!(
2549            crate::sql_query(
2550                "SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5"
2551            )
2552            .execute(&mut conn)
2553            .is_err()
2554        );
2555    }
2556
2557    #[diesel_test_helper::test]
2558    fn set_limit_enforces_vdbe_op() {
2559        // The same heavy statement runs under the default opcode budget but fails once that
2560        // budget is restricted to a tiny value (reported as SQLITE_NOMEM).
2561        let heavy = "SELECT count(*) FROM sqlite_master a, sqlite_master b, sqlite_master c";
2562
2563        let mut unconstrained = connection();
2564        assert!(crate::sql_query(heavy).execute(&mut unconstrained).is_ok());
2565
2566        let mut conn = connection();
2567        conn.set_limit(SqliteLimit::VdbeOp, 5);
2568        assert!(crate::sql_query(heavy).execute(&mut conn).is_err());
2569    }
2570
2571    #[diesel_test_helper::test]
2572    fn set_limit_enforces_function_arg() {
2573        let mut conn = connection();
2574        conn.set_limit(SqliteLimit::FunctionArg, 3);
2575
2576        assert!(
2577            crate::sql_query("SELECT max(1, 2, 3)")
2578                .execute(&mut conn)
2579                .is_ok()
2580        );
2581        // Eight arguments exceed the limit of three ("too many arguments on function max").
2582        assert!(
2583            crate::sql_query("SELECT max(1, 2, 3, 4, 5, 6, 7, 8)")
2584                .execute(&mut conn)
2585                .is_err()
2586        );
2587    }
2588
2589    #[diesel_test_helper::test]
2590    fn set_limit_enforces_attached() {
2591        let mut conn = connection();
2592        conn.set_limit(SqliteLimit::Attached, 0);
2593
2594        // With zero attachments allowed, any ATTACH is rejected ("too many attached databases").
2595        assert!(
2596            crate::sql_query("ATTACH DATABASE ':memory:' AS aux_db")
2597                .execute(&mut conn)
2598                .is_err()
2599        );
2600    }
2601
2602    #[diesel_test_helper::test]
2603    fn set_limit_enforces_variable_number() {
2604        let mut conn = connection();
2605        // The published default sits below the bundled ceiling, so it is applied verbatim and
2606        // acts as the boundary: a parameter index at the limit is accepted, one past it is
2607        // rejected ("variable number must be between ?1 and ?N").
2608        conn.set_limit(
2609            SqliteLimit::VariableNumber,
2610            SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT,
2611        );
2612        let at_limit = format!("SELECT ?{}", SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT);
2613        let past_limit = format!(
2614            "SELECT ?{}",
2615            SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT as i64 + 1
2616        );
2617        assert!(crate::sql_query(&at_limit).execute(&mut conn).is_ok());
2618        assert!(crate::sql_query(&past_limit).execute(&mut conn).is_err());
2619    }
2620
2621    #[diesel_test_helper::test]
2622    fn set_limit_enforces_trigger_depth() {
2623        use crate::connection::SimpleConnection;
2624
2625        // A recursive trigger that terminates on its own at x = 100.
2626        let setup = "PRAGMA recursive_triggers = ON;\
2627             CREATE TABLE recur (x INTEGER);\
2628             CREATE TRIGGER recur_tr AFTER INSERT ON recur WHEN NEW.x < 100 \
2629             BEGIN INSERT INTO recur VALUES (NEW.x + 1); END;";
2630
2631        // Under the default depth the recursion completes.
2632        let mut unconstrained = connection();
2633        unconstrained.batch_execute(setup).unwrap();
2634        assert!(
2635            crate::sql_query("INSERT INTO recur VALUES (1)")
2636                .execute(&mut unconstrained)
2637                .is_ok()
2638        );
2639
2640        // A tiny depth limit is hit before the recursion can terminate
2641        // ("too many levels of trigger recursion").
2642        let mut conn = connection();
2643        conn.set_limit(SqliteLimit::TriggerDepth, 3);
2644        conn.batch_execute(setup).unwrap();
2645        assert!(
2646            crate::sql_query("INSERT INTO recur VALUES (1)")
2647                .execute(&mut conn)
2648                .is_err()
2649        );
2650    }
2651
2652    #[diesel_test_helper::test]
2653    fn worker_threads_limit_has_no_runtime_error_path() {
2654        // Unlike the other categories, WorkerThreads only caps the number of auxiliary sort
2655        // threads a statement may start. Lowering it never raises an error, it only affects
2656        // performance. There is therefore no enforcement failure to assert, only that the value
2657        // is applied and ordinary queries keep working.
2658        let mut conn = connection();
2659        conn.set_limit(SqliteLimit::WorkerThreads, 0);
2660        assert_eq!(conn.get_limit(SqliteLimit::WorkerThreads), 0);
2661        assert!(crate::sql_query("SELECT 1").execute(&mut conn).is_ok());
2662    }
2663
2664    #[diesel_test_helper::test]
2665    fn set_limit_enforces_sql_length() {
2666        let mut conn = connection();
2667        conn.set_limit(SqliteLimit::SqlLength, 20);
2668
2669        // A statement longer than 20 bytes is rejected by SQLite.
2670        let result =
2671            crate::sql_query("SELECT * FROM sqlite_master WHERE type = 'table'").execute(&mut conn);
2672        assert!(result.is_err());
2673    }
2674
2675    #[diesel_test_helper::test]
2676    fn set_limit_enforces_like_pattern_length() {
2677        let mut conn = connection();
2678        conn.set_limit(SqliteLimit::LikePatternLength, 100);
2679
2680        assert!(
2681            crate::sql_query("SELECT 'test' LIKE 'te%'")
2682                .execute(&mut conn)
2683                .is_ok()
2684        );
2685
2686        let long_pattern = "%".repeat(200);
2687        let query = format!("SELECT 'test' LIKE '{long_pattern}'");
2688        assert!(crate::sql_query(&query).execute(&mut conn).is_err());
2689    }
2690
2691    #[diesel_test_helper::test]
2692    fn set_limit_clamps_above_compile_time_maximum() {
2693        let mut conn = connection();
2694        // SQLite clamps a requested value to its hard compile-time ceiling
2695        // rather than accepting it verbatim.
2696        conn.set_limit(SqliteLimit::Length, i32::MAX);
2697        let clamped = conn.get_limit(SqliteLimit::Length);
2698        assert!(clamped > 0 && clamped < i32::MAX);
2699    }
2700
2701    #[diesel_test_helper::test]
2702    fn set_recommended_security_limits_applies_documented_table() {
2703        let mut conn = connection();
2704        conn.set_recommended_security_limits();
2705
2706        assert_eq!(conn.get_limit(SqliteLimit::Length), 1_000_000);
2707        assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 100_000);
2708        assert_eq!(conn.get_limit(SqliteLimit::ColumnCount), 100);
2709        assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), 10);
2710        assert_eq!(conn.get_limit(SqliteLimit::CompoundSelect), 3);
2711        assert_eq!(conn.get_limit(SqliteLimit::VdbeOp), 25_000);
2712        assert_eq!(conn.get_limit(SqliteLimit::FunctionArg), 8);
2713        assert_eq!(conn.get_limit(SqliteLimit::Attached), 0);
2714        assert_eq!(conn.get_limit(SqliteLimit::LikePatternLength), 50);
2715        assert_eq!(conn.get_limit(SqliteLimit::VariableNumber), 10);
2716        assert_eq!(conn.get_limit(SqliteLimit::TriggerDepth), 10);
2717    }
2718
2719    #[diesel_test_helper::test]
2720    fn safe_limit_constants_do_not_exceed_defaults() {
2721        // The hardened value for each category is a tightening of SQLite's published default, so
2722        // it must never be larger. This is asserted instead of comparing the `DEFAULT_*`
2723        // constants to a fresh connection, because the runtime default of categories such as
2724        // `FunctionArg` and `VariableNumber` is build-dependent (the bundled libsqlite3-sys
2725        // raises several of them), while these published constants are fixed.
2726        let pairs = [
2727            (
2728                SqliteLimit::SAFE_LENGTH_LIMIT,
2729                SqliteLimit::DEFAULT_LENGTH_LIMIT,
2730            ),
2731            (
2732                SqliteLimit::SAFE_SQL_LENGTH_LIMIT,
2733                SqliteLimit::DEFAULT_SQL_LENGTH_LIMIT,
2734            ),
2735            (
2736                SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
2737                SqliteLimit::DEFAULT_COLUMN_COUNT_LIMIT,
2738            ),
2739            (
2740                SqliteLimit::SAFE_EXPR_DEPTH_LIMIT,
2741                SqliteLimit::DEFAULT_EXPR_DEPTH_LIMIT,
2742            ),
2743            (
2744                SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
2745                SqliteLimit::DEFAULT_COMPOUND_SELECT_LIMIT,
2746            ),
2747            (
2748                SqliteLimit::SAFE_VDBE_OP_LIMIT,
2749                SqliteLimit::DEFAULT_VDBE_OP_LIMIT,
2750            ),
2751            (
2752                SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
2753                SqliteLimit::DEFAULT_FUNCTION_ARG_LIMIT,
2754            ),
2755            (
2756                SqliteLimit::SAFE_ATTACHED_LIMIT,
2757                SqliteLimit::DEFAULT_ATTACHED_LIMIT,
2758            ),
2759            (
2760                SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
2761                SqliteLimit::DEFAULT_LIKE_PATTERN_LENGTH_LIMIT,
2762            ),
2763            (
2764                SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
2765                SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT,
2766            ),
2767            (
2768                SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
2769                SqliteLimit::DEFAULT_TRIGGER_DEPTH_LIMIT,
2770            ),
2771            (
2772                SqliteLimit::SAFE_WORKER_THREADS_LIMIT,
2773                SqliteLimit::DEFAULT_WORKER_THREADS_LIMIT,
2774            ),
2775        ];
2776        for (safe, default) in pairs {
2777            assert!(
2778                safe <= default,
2779                "safe value {safe} exceeds default {default}"
2780            );
2781        }
2782    }
2783
2784    #[diesel_test_helper::test]
2785    fn safe_limit_constants_match_recommended_setter() {
2786        let mut conn = connection();
2787        conn.set_recommended_security_limits();
2788
2789        assert_eq!(
2790            conn.get_limit(SqliteLimit::Length),
2791            SqliteLimit::SAFE_LENGTH_LIMIT
2792        );
2793        assert_eq!(
2794            conn.get_limit(SqliteLimit::SqlLength),
2795            SqliteLimit::SAFE_SQL_LENGTH_LIMIT
2796        );
2797        assert_eq!(
2798            conn.get_limit(SqliteLimit::ColumnCount),
2799            SqliteLimit::SAFE_COLUMN_COUNT_LIMIT
2800        );
2801        assert_eq!(
2802            conn.get_limit(SqliteLimit::ExprDepth),
2803            SqliteLimit::SAFE_EXPR_DEPTH_LIMIT
2804        );
2805        assert_eq!(
2806            conn.get_limit(SqliteLimit::CompoundSelect),
2807            SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT
2808        );
2809        assert_eq!(
2810            conn.get_limit(SqliteLimit::VdbeOp),
2811            SqliteLimit::SAFE_VDBE_OP_LIMIT
2812        );
2813        assert_eq!(
2814            conn.get_limit(SqliteLimit::FunctionArg),
2815            SqliteLimit::SAFE_FUNCTION_ARG_LIMIT
2816        );
2817        assert_eq!(
2818            conn.get_limit(SqliteLimit::Attached),
2819            SqliteLimit::SAFE_ATTACHED_LIMIT
2820        );
2821        assert_eq!(
2822            conn.get_limit(SqliteLimit::LikePatternLength),
2823            SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT
2824        );
2825        assert_eq!(
2826            conn.get_limit(SqliteLimit::VariableNumber),
2827            SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT
2828        );
2829        assert_eq!(
2830            conn.get_limit(SqliteLimit::TriggerDepth),
2831            SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT
2832        );
2833        // The recommended setter leaves `WorkerThreads` untouched because its default is already
2834        // safe, so assert that the documented safe value matches what the connection reports.
2835        assert_eq!(
2836            conn.get_limit(SqliteLimit::WorkerThreads),
2837            SqliteLimit::SAFE_WORKER_THREADS_LIMIT
2838        );
2839    }
2840
2841    // ---- db_config tests ----
2842
2843    #[diesel_test_helper::test]
2844    fn db_config_defensive_roundtrip() {
2845        let conn = &mut connection();
2846        conn.set_defensive(true).unwrap();
2847        assert!(conn.is_defensive().unwrap());
2848        conn.set_defensive(false).unwrap();
2849        assert!(!conn.is_defensive().unwrap());
2850    }
2851
2852    #[diesel_test_helper::test]
2853    fn db_config_trusted_schema_roundtrip() {
2854        let conn = &mut connection();
2855        conn.set_trusted_schema(false).unwrap();
2856        assert!(!conn.is_trusted_schema().unwrap());
2857        conn.set_trusted_schema(true).unwrap();
2858        assert!(conn.is_trusted_schema().unwrap());
2859    }
2860
2861    #[diesel_test_helper::test]
2862    fn db_config_with_load_extension_enabled_scopes_the_flag() {
2863        let conn = &mut connection();
2864        conn.with_load_extension_enabled(|conn| {
2865            // Enabled for the duration of the closure.
2866            assert!(conn.is_load_extension_enabled().unwrap());
2867            QueryResult::Ok(())
2868        })
2869        .unwrap();
2870        // Disabled again afterwards.
2871        assert!(!conn.is_load_extension_enabled().unwrap());
2872    }
2873
2874    #[cfg(all(
2875        feature = "std",
2876        not(all(target_family = "wasm", target_os = "unknown"))
2877    ))]
2878    #[diesel_test_helper::test]
2879    fn with_load_extension_enabled_disables_after_panic() {
2880        let conn = &mut connection();
2881        let outcome = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
2882            conn.with_load_extension_enabled(|_conn| -> QueryResult<()> {
2883                panic!("boom inside closure");
2884            })
2885        }));
2886        assert!(outcome.is_err(), "panic should propagate");
2887        assert!(
2888            !conn.is_load_extension_enabled().unwrap(),
2889            "extension loading must be disabled again after a panic"
2890        );
2891    }
2892
2893    #[diesel_test_helper::test]
2894    fn db_config_triggers_roundtrip() {
2895        let conn = &mut connection();
2896        conn.set_triggers_enabled(false).unwrap();
2897        assert!(!conn.are_triggers_enabled().unwrap());
2898        conn.set_triggers_enabled(true).unwrap();
2899        assert!(conn.are_triggers_enabled().unwrap());
2900    }
2901
2902    #[diesel_test_helper::test]
2903    fn db_config_views_roundtrip() {
2904        let conn = &mut connection();
2905        conn.set_views_enabled(false).unwrap();
2906        assert!(!conn.are_views_enabled().unwrap());
2907        conn.set_views_enabled(true).unwrap();
2908        assert!(conn.are_views_enabled().unwrap());
2909    }
2910
2911    #[diesel_test_helper::test]
2912    fn db_config_foreign_keys_roundtrip() {
2913        let conn = &mut connection();
2914        conn.set_foreign_keys_enabled(true).unwrap();
2915        assert!(conn.are_foreign_keys_enabled().unwrap());
2916        conn.set_foreign_keys_enabled(false).unwrap();
2917        assert!(!conn.are_foreign_keys_enabled().unwrap());
2918    }
2919
2920    #[diesel_test_helper::test]
2921    fn db_config_dqs_dml_roundtrip() {
2922        let conn = &mut connection();
2923        conn.set_double_quoted_strings_dml(false).unwrap();
2924        assert!(!conn.are_double_quoted_strings_dml_enabled().unwrap());
2925        conn.set_double_quoted_strings_dml(true).unwrap();
2926        assert!(conn.are_double_quoted_strings_dml_enabled().unwrap());
2927    }
2928
2929    #[diesel_test_helper::test]
2930    fn db_config_dqs_ddl_roundtrip() {
2931        let conn = &mut connection();
2932        conn.set_double_quoted_strings_ddl(false).unwrap();
2933        assert!(!conn.are_double_quoted_strings_ddl_enabled().unwrap());
2934        conn.set_double_quoted_strings_ddl(true).unwrap();
2935        assert!(conn.are_double_quoted_strings_ddl_enabled().unwrap());
2936    }
2937
2938    #[diesel_test_helper::test]
2939    fn db_config_fts3_tokenizer_roundtrip() {
2940        let conn = &mut connection();
2941        conn.set_fts3_tokenizer_enabled(false).unwrap();
2942        assert!(!conn.is_fts3_tokenizer_enabled().unwrap());
2943        conn.set_fts3_tokenizer_enabled(true).unwrap();
2944        assert!(conn.is_fts3_tokenizer_enabled().unwrap());
2945    }
2946
2947    #[diesel_test_helper::test]
2948    fn db_config_writable_schema_roundtrip() {
2949        let conn = &mut connection();
2950        conn.set_writable_schema(false).unwrap();
2951        assert!(!conn.is_writable_schema().unwrap());
2952        conn.set_writable_schema(true).unwrap();
2953        assert!(conn.is_writable_schema().unwrap());
2954    }
2955
2956    #[diesel_test_helper::test]
2957    fn db_config_attach_create_roundtrip() {
2958        let conn = &mut connection();
2959        // ATTACH_CREATE requires SQLite 3.46.0+; skip if unsupported
2960        if conn.set_attach_create_enabled(false).is_err() {
2961            return;
2962        }
2963        assert!(!conn.is_attach_create_enabled().unwrap());
2964        conn.set_attach_create_enabled(true).unwrap();
2965        assert!(conn.is_attach_create_enabled().unwrap());
2966    }
2967
2968    #[diesel_test_helper::test]
2969    fn db_config_attach_write_roundtrip() {
2970        let conn = &mut connection();
2971        // ATTACH_WRITE requires SQLite 3.46.0+; skip if unsupported
2972        if conn.set_attach_write_enabled(false).is_err() {
2973            return;
2974        }
2975        assert!(!conn.is_attach_write_enabled().unwrap());
2976        conn.set_attach_write_enabled(true).unwrap();
2977        assert!(conn.is_attach_write_enabled().unwrap());
2978    }
2979
2980    // ---- behavioral db_config tests ----
2981
2982    #[diesel_test_helper::test]
2983    fn defensive_mode_blocks_writable_schema() {
2984        let conn = &mut connection();
2985        conn.set_defensive(true).unwrap();
2986        // In defensive mode, writable_schema should remain off even if we try to set it
2987        let _ = crate::sql_query("PRAGMA writable_schema = ON").execute(conn);
2988        assert!(!conn.is_writable_schema().unwrap());
2989    }
2990
2991    #[diesel_test_helper::test]
2992    fn foreign_keys_enabled_enforces_constraints() {
2993        let conn = &mut connection();
2994        conn.set_foreign_keys_enabled(true).unwrap();
2995
2996        crate::sql_query("CREATE TABLE parent (id INTEGER PRIMARY KEY)")
2997            .execute(conn)
2998            .unwrap();
2999        crate::sql_query(
3000            "CREATE TABLE child (id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES parent(id))",
3001        )
3002        .execute(conn)
3003        .unwrap();
3004
3005        // Insert a child row with no matching parent — should fail with FK enabled
3006        let result =
3007            crate::sql_query("INSERT INTO child (id, parent_id) VALUES (1, 999)").execute(conn);
3008        assert!(result.is_err());
3009    }
3010
3011    #[diesel_test_helper::test]
3012    fn views_disabled_blocks_view_queries() {
3013        let conn = &mut connection();
3014        crate::sql_query("CREATE TABLE base (id INTEGER PRIMARY KEY)")
3015            .execute(conn)
3016            .unwrap();
3017        crate::sql_query("INSERT INTO base (id) VALUES (1)")
3018            .execute(conn)
3019            .unwrap();
3020        crate::sql_query("CREATE VIEW base_view AS SELECT id FROM base")
3021            .execute(conn)
3022            .unwrap();
3023
3024        // Enabled (default): the view can be queried.
3025        conn.set_views_enabled(true).unwrap();
3026        assert!(
3027            crate::sql_query("SELECT id FROM base_view")
3028                .execute(conn)
3029                .is_ok()
3030        );
3031
3032        // Disabled: queries that reference the view fail.
3033        conn.set_views_enabled(false).unwrap();
3034        assert!(
3035            crate::sql_query("SELECT id FROM base_view")
3036                .execute(conn)
3037                .is_err()
3038        );
3039    }
3040
3041    #[diesel_test_helper::test]
3042    fn triggers_disabled_prevents_firing() {
3043        let conn = &mut connection();
3044        crate::sql_query("CREATE TABLE source (id INTEGER PRIMARY KEY)")
3045            .execute(conn)
3046            .unwrap();
3047        crate::sql_query("CREATE TABLE trigger_log (n INTEGER)")
3048            .execute(conn)
3049            .unwrap();
3050        crate::sql_query("CREATE TRIGGER log_insert AFTER INSERT ON source BEGIN INSERT INTO trigger_log (n) VALUES (1); END")
3051            .execute(conn)
3052            .unwrap();
3053
3054        // Disabled: inserting into `source` must not fire the trigger.
3055        conn.set_triggers_enabled(false).unwrap();
3056        crate::sql_query("INSERT INTO source (id) VALUES (1)")
3057            .execute(conn)
3058            .unwrap();
3059        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM trigger_log")
3060            .get_result(conn)
3061            .unwrap();
3062        assert_eq!(0, count, "trigger should not fire while disabled");
3063
3064        // Enabled: the trigger fires and writes one row.
3065        conn.set_triggers_enabled(true).unwrap();
3066        crate::sql_query("INSERT INTO source (id) VALUES (2)")
3067            .execute(conn)
3068            .unwrap();
3069        let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM trigger_log")
3070            .get_result(conn)
3071            .unwrap();
3072        assert_eq!(1, count, "trigger should fire while enabled");
3073    }
3074
3075    #[diesel_test_helper::test]
3076    fn dqs_dml_controls_double_quoted_string_literals() {
3077        let conn = &mut connection();
3078
3079        // Disabled: a double-quoted token in DML is parsed as an identifier, so a
3080        // bare `"text"` that is not a column errors.
3081        conn.set_double_quoted_strings_dml(false).unwrap();
3082        let disabled = sql::<Text>(r#"SELECT "bare_token""#).get_result::<String>(conn);
3083        assert!(disabled.is_err());
3084
3085        // Enabled: the same token is accepted as a string literal.
3086        conn.set_double_quoted_strings_dml(true).unwrap();
3087        let enabled = sql::<Text>(r#"SELECT "bare_token""#).get_result::<String>(conn);
3088        assert_eq!(Ok("bare_token".to_owned()), enabled);
3089    }
3090
3091    #[diesel_test_helper::test]
3092    fn dqs_ddl_controls_double_quoted_string_literals() {
3093        let conn = &mut connection();
3094
3095        // Disabled: a double-quoted token in a CHECK constraint is parsed as an
3096        // identifier. As there is no such column, creating the table errors.
3097        conn.set_double_quoted_strings_ddl(false).unwrap();
3098        let disabled =
3099            crate::sql_query(r#"CREATE TABLE dqs_off (name TEXT, CHECK (name <> "not_a_column"))"#)
3100                .execute(conn);
3101        assert!(disabled.is_err());
3102
3103        // Enabled: the same token is accepted as a string literal, so the CHECK
3104        // constraint (and the table) are created successfully.
3105        conn.set_double_quoted_strings_ddl(true).unwrap();
3106        let enabled =
3107            crate::sql_query(r#"CREATE TABLE dqs_on (name TEXT, CHECK (name <> "not_a_column"))"#)
3108                .execute(conn);
3109        assert!(enabled.is_ok());
3110    }
3111
3112    #[diesel_test_helper::test]
3113    fn writable_schema_controls_direct_sqlite_master_writes() {
3114        let conn = &mut connection();
3115        crate::sql_query("CREATE TABLE protected (id INTEGER PRIMARY KEY)")
3116            .execute(conn)
3117            .unwrap();
3118
3119        let update =
3120            "UPDATE sqlite_master SET sql = sql WHERE type = 'table' AND name = 'protected'";
3121
3122        // Disabled (default): a direct write to sqlite_master is rejected.
3123        conn.set_writable_schema(false).unwrap();
3124        assert!(crate::sql_query(update).execute(conn).is_err());
3125
3126        // Enabled: the same write is permitted.
3127        conn.set_writable_schema(true).unwrap();
3128        assert!(crate::sql_query(update).execute(conn).is_ok());
3129    }
3130
3131    #[diesel_test_helper::test]
3132    fn fts3_tokenizer_disabled_blocks_the_function() {
3133        let conn = &mut connection();
3134
3135        // Enable first to detect whether FTS3 is compiled into this SQLite build.
3136        conn.set_fts3_tokenizer_enabled(true).unwrap();
3137        let enabled = sql::<crate::sql_types::Binary>("SELECT fts3_tokenizer('simple')")
3138            .get_result::<Vec<u8>>(conn);
3139        if enabled.is_err() {
3140            // FTS3 is not available in this build, so there is nothing to assert.
3141            return;
3142        }
3143
3144        // Disabled: the `fts3_tokenizer()` SQL function is no longer callable.
3145        conn.set_fts3_tokenizer_enabled(false).unwrap();
3146        let disabled = sql::<crate::sql_types::Binary>("SELECT fts3_tokenizer('simple')")
3147            .get_result::<Vec<u8>>(conn);
3148        assert!(disabled.is_err());
3149    }
3150
3151    // These ATTACH tests need a real filesystem (temp files), which is not
3152    // available on the wasm target, where SQLite is in-memory only.
3153    #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3154    fn temp_db_path(tag: &str) -> std::path::PathBuf {
3155        let mut path = std::env::temp_dir();
3156        path.push(format!("diesel_attach_{}_{}.db", std::process::id(), tag));
3157        path
3158    }
3159
3160    #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3161    #[diesel_test_helper::test]
3162    fn attach_create_disabled_blocks_new_database_files() {
3163        let conn = &mut connection();
3164
3165        // The ATTACH_CREATE option was added in SQLite 3.49.0; skip on older
3166        // libraries (e.g. the system SQLite on the Ubuntu 24.04 CI runners).
3167        if conn.set_attach_create_enabled(false).is_err() {
3168            return;
3169        }
3170
3171        let path = temp_db_path("create");
3172        let _ = std::fs::remove_file(&path);
3173        let attach = format!("ATTACH DATABASE '{}' AS aux_create", path.display());
3174
3175        // Disabled: attaching a path that does not exist yet must fail.
3176        assert!(crate::sql_query(&attach).execute(conn).is_err());
3177
3178        // Enabled: the same ATTACH now creates and opens the file.
3179        conn.set_attach_create_enabled(true).unwrap();
3180        crate::sql_query(&attach).execute(conn).unwrap();
3181        crate::sql_query("DETACH DATABASE aux_create")
3182            .execute(conn)
3183            .unwrap();
3184
3185        let _ = std::fs::remove_file(&path);
3186    }
3187
3188    #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3189    #[diesel_test_helper::test]
3190    fn attach_write_disabled_opens_attached_databases_read_only() {
3191        let conn = &mut connection();
3192
3193        // The ATTACH_WRITE option was added in SQLite 3.49.0; skip on older
3194        // libraries (e.g. the system SQLite on the Ubuntu 24.04 CI runners).
3195        // This guard also leaves ATTACH_WRITE disabled for the first check below.
3196        if conn.set_attach_write_enabled(false).is_err() {
3197            return;
3198        }
3199
3200        // Seed an existing on-disk database with a table to write into.
3201        let path = temp_db_path("write");
3202        let _ = std::fs::remove_file(&path);
3203        {
3204            let mut seed = SqliteConnection::establish(path.to_str().unwrap()).unwrap();
3205            crate::sql_query("CREATE TABLE t (id INTEGER)")
3206                .execute(&mut seed)
3207                .unwrap();
3208        }
3209        let attach = format!("ATTACH DATABASE '{}' AS aux_write", path.display());
3210
3211        // Disabled: the attached database is opened read-only, so writes fail.
3212        crate::sql_query(&attach).execute(conn).unwrap();
3213        assert!(
3214            crate::sql_query("INSERT INTO aux_write.t (id) VALUES (1)")
3215                .execute(conn)
3216                .is_err()
3217        );
3218        crate::sql_query("DETACH DATABASE aux_write")
3219            .execute(conn)
3220            .unwrap();
3221
3222        // Enabled: the attached database is writable again.
3223        conn.set_attach_write_enabled(true).unwrap();
3224        crate::sql_query(&attach).execute(conn).unwrap();
3225        crate::sql_query("INSERT INTO aux_write.t (id) VALUES (1)")
3226            .execute(conn)
3227            .unwrap();
3228        crate::sql_query("DETACH DATABASE aux_write")
3229            .execute(conn)
3230            .unwrap();
3231
3232        let _ = std::fs::remove_file(&path);
3233    }
3234
3235    // ---- DIRECTONLY / INNOCUOUS function behavior tests ----
3236
3237    #[declare_sql_function]
3238    extern "SQL" {
3239        fn directonly_fn() -> Integer;
3240        fn innocuous_fn() -> Integer;
3241    }
3242
3243    #[diesel_test_helper::test]
3244    fn directonly_function_blocked_from_view() {
3245        let conn = &mut connection();
3246
3247        // Register a DIRECTONLY function
3248        directonly_fn_utils::register_impl_with_behavior(
3249            conn,
3250            SqliteFunctionBehavior::DIRECTONLY,
3251            || 42,
3252        )
3253        .unwrap();
3254
3255        // Direct call works
3256        let result = crate::select(directonly_fn()).get_result::<i32>(conn);
3257        assert_eq!(Ok(42), result);
3258
3259        // Create a view that calls the function
3260        crate::sql_query("CREATE VIEW test_view AS SELECT directonly_fn() AS val")
3261            .execute(conn)
3262            .unwrap();
3263
3264        // Disable trusted schema so DIRECTONLY is enforced from schema objects
3265        conn.set_trusted_schema(false).unwrap();
3266
3267        // Querying the view should fail because the function is DIRECTONLY
3268        let result = crate::sql_query("SELECT val FROM test_view").execute(conn);
3269        assert!(result.is_err());
3270    }
3271
3272    #[diesel_test_helper::test]
3273    fn innocuous_function_allowed_from_view_with_untrusted_schema() {
3274        let conn = &mut connection();
3275
3276        // Register an INNOCUOUS function
3277        innocuous_fn_utils::register_impl_with_behavior(
3278            conn,
3279            SqliteFunctionBehavior::DETERMINISTIC | SqliteFunctionBehavior::INNOCUOUS,
3280            || 99,
3281        )
3282        .unwrap();
3283
3284        // Create a view that calls the function
3285        crate::sql_query("CREATE VIEW innocuous_view AS SELECT innocuous_fn() AS val")
3286            .execute(conn)
3287            .unwrap();
3288
3289        // Disable trusted schema
3290        conn.set_trusted_schema(false).unwrap();
3291
3292        // Querying the view should succeed because the function is INNOCUOUS
3293        let result = crate::sql_query("SELECT val FROM innocuous_view").execute(conn);
3294        assert!(result.is_ok());
3295    }
3296}