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