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