Skip to main content

diesel/sqlite/connection/
mod.rs

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