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