diesel/connection/
mod.rs

1//! Types related to database connections
2
3pub(crate) mod instrumentation;
4#[cfg(all(
5    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
6    any(feature = "sqlite", feature = "postgres", feature = "mysql")
7))]
8pub(crate) mod statement_cache;
9#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
10pub mod statement_cache;
11mod transaction_manager;
12
13use crate::backend::Backend;
14use crate::expression::QueryMetadata;
15use crate::query_builder::{Query, QueryFragment, QueryId};
16use crate::result::*;
17use crate::sql_types::TypeMetadata;
18use std::fmt::Debug;
19
20#[doc(inline)]
21pub use self::instrumentation::{
22    get_default_instrumentation, set_default_instrumentation, DebugQuery, Instrumentation,
23    InstrumentationEvent,
24};
25#[doc(inline)]
26pub use self::transaction_manager::{
27    AnsiTransactionManager, InTransactionStatus, TransactionDepthChange, TransactionManager,
28    TransactionManagerStatus, ValidTransactionManagerStatus,
29};
30
31#[diesel_derives::__diesel_public_if(
32    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
33)]
34pub(crate) use self::private::ConnectionSealed;
35
36#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
37pub use self::private::MultiConnectionHelper;
38
39#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
40pub use self::instrumentation::StrQueryHelper;
41
42#[cfg(all(
43    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
44    any(feature = "sqlite", feature = "postgres", feature = "mysql")
45))]
46pub(crate) use self::private::MultiConnectionHelper;
47
48/// Perform simple operations on a backend.
49///
50/// You should likely use [`Connection`] instead.
51pub trait SimpleConnection {
52    /// Execute multiple SQL statements within the same string.
53    ///
54    /// This function is used to execute migrations,
55    /// which may contain more than one SQL statement.
56    fn batch_execute(&mut self, query: &str) -> QueryResult<()>;
57}
58
59#[doc(hidden)]
60#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
61#[deprecated(note = "Directly use `LoadConnection::Cursor` instead")]
62pub type LoadRowIter<'conn, 'query, C, DB, B = DefaultLoadingMode> =
63    <C as self::private::ConnectionHelperType<DB, B>>::Cursor<'conn, 'query>;
64
65/// A connection to a database
66///
67/// This trait represents a database connection. It can be used to query the database through
68/// the query dsl provided by diesel, custom extensions or raw sql queries.
69///
70/// # Implementing a custom connection
71///
72/// There are several reasons why you would want to implement a custom connection implementation:
73///
74/// * To wrap an existing connection for instrumentation purposes
75/// * To use a different underlying library to provide a connection implementation
76/// for already existing backends.
77/// * To add support for an unsupported database system
78///
79/// Implementing a `Connection` in a third party crate requires
80/// enabling the
81/// `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
82/// crate feature which grants access to some of diesel's implementation details.
83///
84///
85/// ## Wrapping an existing connection impl
86///
87/// Wrapping an existing connection allows you to customize the implementation to
88/// add additional functionality, like for example instrumentation. For this use case
89/// you only need to implement `Connection`, [`LoadConnection`] and all super traits.
90/// You should forward any method call to the wrapped connection type.
91/// It is **important** to also forward any method where diesel provides a
92/// default implementation, as the wrapped connection implementation may
93/// contain a customized implementation.
94///
95/// To allow the integration of your new connection type with other diesel features
96#[cfg_attr(
97    feature = "r2d2",
98    doc = "it may be useful to also implement [`R2D2Connection`](crate::r2d2::R2D2Connection)"
99)]
100#[cfg_attr(
101    not(feature = "r2d2"),
102    doc = "it may be useful to also implement `R2D2Connection`"
103)]
104/// and [`MigrationConnection`](crate::migration::MigrationConnection).
105///
106/// ## Provide a new connection implementation for an existing backend
107///
108/// Implementing a new connection based on an existing backend can enable the usage of
109/// other methods to connect to the database. One example here would be to replace
110/// the official diesel provided connection implementations with an implementation
111/// based on a pure rust connection crate.
112///
113/// **It's important to use prepared statements to implement the following methods:**
114/// * [`LoadConnection::load`]
115/// * [`Connection::execute_returning_count`]
116///
117/// For performance reasons it may also be meaningful to cache already prepared statements.
118#[cfg_attr(
119    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
120    doc = "See [`StatementCache`](self::statement_cache::StatementCache)"
121)]
122#[cfg_attr(
123    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
124    doc = "See `StatementCache`"
125)]
126/// for a helper type to implement prepared statement caching.
127#[cfg_attr(
128    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
129    doc = "The [statement_cache](self::statement_cache)"
130)]
131#[cfg_attr(
132    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
133    doc = "The statement_cache"
134)]
135/// module documentation contains details about efficient prepared statement caching
136/// based on diesels query builder.
137///
138/// It is required to implement at least the following parts:
139///
140/// * A row type that describes how to receive values form a database row.
141///   This type needs to implement [`Row`](crate::row::Row)
142/// * A field type that describes a database field value.
143///   This type needs to implement [`Field`](crate::row::Field)
144/// * A connection type that wraps the connection +
145///   the necessary state management.
146/// * Maybe a [`TransactionManager`] implementation matching
147///  the interface provided by the database connection crate.
148///  Otherwise the implementation used by the corresponding
149///  `Connection` in diesel can be reused.
150///
151/// To allow the integration of your new connection type with other diesel features
152#[cfg_attr(
153    feature = "r2d2",
154    doc = "it may be useful to also implement [`R2D2Connection`](crate::r2d2::R2D2Connection)"
155)]
156#[cfg_attr(
157    not(feature = "r2d2"),
158    doc = "it may be useful to also implement `R2D2Connection`"
159)]
160/// and [`MigrationConnection`](crate::migration::MigrationConnection).
161///
162/// The exact implementation of the `Connection` trait depends on the interface provided
163/// by the connection crate/library. A struct implementing `Connection` should
164#[cfg_attr(
165    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
166    doc = "likely contain a [`StatementCache`](self::statement_cache::StatementCache)"
167)]
168#[cfg_attr(
169    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
170    doc = "likely contain a `StatementCache`"
171)]
172/// to cache prepared statements efficiently.
173///
174/// As implementations differ significantly between the supported backends
175/// we cannot give a one for all description here. Generally it's likely a
176/// good idea to follow the implementation of the corresponding connection
177/// in diesel at a high level to gain some idea how to implement your
178/// custom implementation.
179///
180/// ## Implement support for an unsupported database system
181///
182/// Additionally to anything mentioned in the previous section the following steps are required:
183///
184/// * Implement a custom backend type. See the documentation of [`Backend`] for details
185/// * Implement appropriate [`FromSql`](crate::deserialize::FromSql)/
186/// [`ToSql`](crate::serialize::ToSql) conversions.
187/// At least the following impls should be considered:
188///     * `i16`: `FromSql<SmallInt, YourBackend>`
189///     * `i32`: `FromSql<Integer, YourBackend>`
190///     * `i64`: `FromSql<BigInt, YourBackend>`
191///     * `f32`: `FromSql<Float, YourBackend>`
192///     * `f64`: `FromSql<Double, YourBackend>`
193///     * `bool`: `FromSql<Bool, YourBackend>`
194///     * `String`: `FromSql<Text, YourBackend>`
195///     * `Vec<u8>`: `FromSql<Binary, YourBackend>`
196///     * `i16`: `ToSql<SmallInt, YourBackend>`
197///     * `i32`: `ToSql<Integer, YourBackend>`
198///     * `i64`: `ToSql<BigInt, YourBackend>`
199///     * `f32`: `ToSql<Float, YourBackend>`
200///     * `f64`: `ToSql<Double, YourBackend>`
201///     * `bool`: `ToSql<Bool, YourBackend>`
202///     * `String`: `ToSql<Text, YourBackend>`
203///     * `Vec<u8>`: `ToSql<Binary, YourBackend>`
204/// * Maybe a [`TransactionManager`] implementation matching
205///  the interface provided by the database connection crate.
206///  Otherwise the implementation used by the corresponding
207///  `Connection` in diesel can be reused.
208///
209/// As these implementations will vary depending on the backend being used,
210/// we cannot give concrete examples here. We recommend looking at our existing
211/// implementations to see how you can implement your own connection.
212pub trait Connection: SimpleConnection + Sized + Send
213where
214    // This trait bound is there so that implementing a new connection is
215    // gated behind the `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
216    // feature flag
217    Self: ConnectionSealed,
218{
219    /// The backend this type connects to
220    type Backend: Backend;
221
222    /// The transaction manager implementation used by this connection
223    #[diesel_derives::__diesel_public_if(
224        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
225    )]
226    type TransactionManager: TransactionManager<Self>;
227
228    /// Establishes a new connection to the database
229    ///
230    /// The argument to this method and the method's behavior varies by backend.
231    /// See the documentation for that backend's connection class
232    /// for details about what it accepts and how it behaves.
233    fn establish(database_url: &str) -> ConnectionResult<Self>;
234
235    /// Executes the given function inside of a database transaction
236    ///
237    /// This function executes the provided closure `f` inside a database
238    /// transaction. If there is already an open transaction for the current
239    /// connection savepoints will be used instead. The connection is committed if
240    /// the closure returns `Ok(_)`, it will be rolled back if it returns `Err(_)`.
241    /// For both cases the original result value will be returned from this function.
242    ///
243    /// If the transaction fails to commit due to a `SerializationFailure` or a
244    /// `ReadOnlyTransaction` a rollback will be attempted.
245    /// If the rollback fails, the error will be returned in a
246    /// [`Error::RollbackErrorOnCommit`],
247    /// from which you will be able to extract both the original commit error and
248    /// the rollback error.
249    /// In addition, the connection will be considered broken
250    /// as it contains a uncommitted unabortable open transaction. Any further
251    /// interaction with the transaction system will result in an returned error
252    /// in this case.
253    ///
254    /// If the closure returns an `Err(_)` and the rollback fails the function
255    /// will return that rollback error directly, and the transaction manager will
256    /// be marked as broken as it contains a uncommitted unabortable open transaction.
257    ///
258    /// If a nested transaction fails to release the corresponding savepoint
259    /// the error will be returned directly.
260    ///
261    /// # Example
262    ///
263    /// ```rust
264    /// # include!("../doctest_setup.rs");
265    /// use diesel::result::Error;
266    ///
267    /// # fn main() {
268    /// #     run_test().unwrap();
269    /// # }
270    /// #
271    /// # fn run_test() -> QueryResult<()> {
272    /// #     use schema::users::dsl::*;
273    /// #     let conn = &mut establish_connection();
274    /// conn.transaction::<_, Error, _>(|conn| {
275    ///     diesel::insert_into(users)
276    ///         .values(name.eq("Ruby"))
277    ///         .execute(conn)?;
278    ///
279    ///     let all_names = users.select(name).load::<String>(conn)?;
280    ///     assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names);
281    ///
282    ///     Ok(())
283    /// })?;
284    ///
285    /// conn.transaction::<(), _, _>(|conn| {
286    ///     diesel::insert_into(users)
287    ///         .values(name.eq("Pascal"))
288    ///         .execute(conn)?;
289    ///
290    ///     let all_names = users.select(name).load::<String>(conn)?;
291    ///     assert_eq!(vec!["Sean", "Tess", "Ruby", "Pascal"], all_names);
292    ///
293    ///     // If we want to roll back the transaction, but don't have an
294    ///     // actual error to return, we can return `RollbackTransaction`.
295    ///     Err(Error::RollbackTransaction)
296    /// });
297    ///
298    /// let all_names = users.select(name).load::<String>(conn)?;
299    /// assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names);
300    /// #     Ok(())
301    /// # }
302    /// ```
303    fn transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
304    where
305        F: FnOnce(&mut Self) -> Result<T, E>,
306        E: From<Error>,
307    {
308        Self::TransactionManager::transaction(self, f)
309    }
310
311    /// Creates a transaction that will never be committed. This is useful for
312    /// tests. Panics if called while inside of a transaction or
313    /// if called with a connection containing a broken transaction
314    fn begin_test_transaction(&mut self) -> QueryResult<()> {
315        match Self::TransactionManager::transaction_manager_status_mut(self) {
316            TransactionManagerStatus::Valid(valid_status) => {
317                assert_eq!(None, valid_status.transaction_depth())
318            }
319            TransactionManagerStatus::InError => panic!("Transaction manager in error"),
320        };
321        Self::TransactionManager::begin_transaction(self)?;
322        // set the test transaction flag
323        // to prevent that this connection gets dropped in connection pools
324        // Tests commonly set the poolsize to 1 and use `begin_test_transaction`
325        // to prevent modifications to the schema
326        Self::TransactionManager::transaction_manager_status_mut(self).set_test_transaction_flag();
327        Ok(())
328    }
329
330    /// Executes the given function inside a transaction, but does not commit
331    /// it. Panics if the given function returns an error.
332    ///
333    /// # Example
334    ///
335    /// ```rust
336    /// # include!("../doctest_setup.rs");
337    /// use diesel::result::Error;
338    ///
339    /// # fn main() {
340    /// #     run_test().unwrap();
341    /// # }
342    /// #
343    /// # fn run_test() -> QueryResult<()> {
344    /// #     use schema::users::dsl::*;
345    /// #     let conn = &mut establish_connection();
346    /// conn.test_transaction::<_, Error, _>(|conn| {
347    ///     diesel::insert_into(users)
348    ///         .values(name.eq("Ruby"))
349    ///         .execute(conn)?;
350    ///
351    ///     let all_names = users.select(name).load::<String>(conn)?;
352    ///     assert_eq!(vec!["Sean", "Tess", "Ruby"], all_names);
353    ///
354    ///     Ok(())
355    /// });
356    ///
357    /// // Even though we returned `Ok`, the transaction wasn't committed.
358    /// let all_names = users.select(name).load::<String>(conn)?;
359    /// assert_eq!(vec!["Sean", "Tess"], all_names);
360    /// #     Ok(())
361    /// # }
362    /// ```
363    fn test_transaction<T, E, F>(&mut self, f: F) -> T
364    where
365        F: FnOnce(&mut Self) -> Result<T, E>,
366        E: Debug,
367    {
368        let mut user_result = None;
369        let _ = self.transaction::<(), _, _>(|conn| {
370            user_result = f(conn).ok();
371            Err(Error::RollbackTransaction)
372        });
373        user_result.expect("Transaction did not succeed")
374    }
375
376    /// Execute a single SQL statements given by a query and return
377    /// number of affected rows
378    #[diesel_derives::__diesel_public_if(
379        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
380    )]
381    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
382    where
383        T: QueryFragment<Self::Backend> + QueryId;
384
385    /// Get access to the current transaction state of this connection
386    ///
387    /// This function should be used from [`TransactionManager`] to access
388    /// internally required state.
389    #[diesel_derives::__diesel_public_if(
390        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
391    )]
392    fn transaction_state(
393        &mut self,
394    ) -> &mut <Self::TransactionManager as TransactionManager<Self>>::TransactionStateData;
395
396    /// Get the instrumentation instance stored in this connection
397    #[diesel_derives::__diesel_public_if(
398        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
399    )]
400    fn instrumentation(&mut self) -> &mut dyn Instrumentation;
401
402    /// Set a specific [`Instrumentation`] implementation for this connection
403    fn set_instrumentation(&mut self, instrumentation: impl Instrumentation);
404}
405
406/// The specific part of a [`Connection`] which actually loads data from the database
407///
408/// This is a separate trait to allow connection implementations to specify
409/// different loading modes via the generic parameter.
410pub trait LoadConnection<B = DefaultLoadingMode>: Connection {
411    /// The cursor type returned by [`LoadConnection::load`]
412    ///
413    /// Users should handle this as opaque type that implements [`Iterator`]
414    type Cursor<'conn, 'query>: Iterator<
415        Item = QueryResult<<Self as LoadConnection<B>>::Row<'conn, 'query>>,
416    >
417    where
418        Self: 'conn;
419
420    /// The row type used as [`Iterator::Item`] for the iterator implementation
421    /// of [`LoadConnection::Cursor`]
422    type Row<'conn, 'query>: crate::row::Row<'conn, Self::Backend>
423    where
424        Self: 'conn;
425
426    /// Executes a given query and returns any requested values
427    ///
428    /// This function executes a given query and returns the
429    /// query result as given by the database. **Normal users
430    /// should not use this function**. Use
431    /// [`QueryDsl::load`](crate::QueryDsl) instead.
432    ///
433    /// This function is useful for people trying to build an alternative
434    /// dsl on top of diesel. It returns an [`impl Iterator<Item = QueryResult<&impl Row<Self::Backend>>`](Iterator).
435    /// This type can be used to iterate over all rows returned by the database.
436    #[diesel_derives::__diesel_public_if(
437        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
438    )]
439    fn load<'conn, 'query, T>(
440        &'conn mut self,
441        source: T,
442    ) -> QueryResult<Self::Cursor<'conn, 'query>>
443    where
444        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
445        Self::Backend: QueryMetadata<T::SqlType>;
446}
447
448/// Describes a connection with an underlying [`crate::sql_types::TypeMetadata::MetadataLookup`]
449#[diesel_derives::__diesel_public_if(
450    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
451)]
452pub trait WithMetadataLookup: Connection {
453    /// Retrieves the underlying metadata lookup
454    fn metadata_lookup(&mut self) -> &mut <Self::Backend as TypeMetadata>::MetadataLookup;
455}
456
457/// A variant of the [`Connection`](trait.Connection.html) trait that is
458/// usable with dynamic dispatch
459///
460/// If you are looking for a way to use pass database connections
461/// for different database backends around in your application
462/// this trait won't help you much. Normally you should only
463/// need to use this trait if you are interacting with a connection
464/// passed to a [`Migration`](../migration/trait.Migration.html)
465pub trait BoxableConnection<DB: Backend>: SimpleConnection + std::any::Any {
466    /// Maps the current connection to `std::any::Any`
467    #[diesel_derives::__diesel_public_if(
468        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
469    )]
470    fn as_any(&self) -> &dyn std::any::Any;
471
472    #[doc(hidden)]
473    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
474}
475
476impl<C> BoxableConnection<C::Backend> for C
477where
478    C: Connection + std::any::Any,
479{
480    fn as_any(&self) -> &dyn std::any::Any {
481        self
482    }
483
484    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
485        self
486    }
487}
488
489/// The default loading mode provided by a [`Connection`].
490///
491/// Checkout the documentation of concrete connection types for details about
492/// supported loading modes.
493///
494/// All types implementing [`Connection`] should provide at least
495/// a single [`LoadConnection<DefaultLoadingMode>`](self::LoadConnection)
496/// implementation.
497#[derive(Debug, Copy, Clone)]
498pub struct DefaultLoadingMode;
499
500impl<DB: Backend + 'static> dyn BoxableConnection<DB> {
501    /// Downcast the current connection to a specific connection
502    /// type.
503    ///
504    /// This will return `None` if the underlying
505    /// connection does not match the corresponding
506    /// type, otherwise a reference to the underlying connection is returned
507    pub fn downcast_ref<T>(&self) -> Option<&T>
508    where
509        T: Connection<Backend = DB> + 'static,
510    {
511        self.as_any().downcast_ref::<T>()
512    }
513
514    /// Downcast the current connection to a specific mutable connection
515    /// type.
516    ///
517    /// This will return `None` if the underlying
518    /// connection does not match the corresponding
519    /// type, otherwise a mutable reference to the underlying connection is returned
520    pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
521    where
522        T: Connection<Backend = DB> + 'static,
523    {
524        self.as_any_mut().downcast_mut::<T>()
525    }
526
527    /// Check if the current connection is
528    /// a specific connection type
529    pub fn is<T>(&self) -> bool
530    where
531        T: Connection<Backend = DB> + 'static,
532    {
533        self.as_any().is::<T>()
534    }
535}
536
537// These traits are considered private for different reasons:
538//
539// `ConnectionSealed` to control who can implement `Connection`,
540// so that we can later change the `Connection` trait
541//
542// `MultiConnectionHelper` is a workaround needed for the
543// `MultiConnection` derive. We might stabilize this trait with
544// the corresponding derive
545//
546// `ConnectionHelperType` as a workaround for the `LoadRowIter`
547// type def. That trait should not be used by any user outside of diesel,
548// it purely exists for backward compatibility reasons.
549pub(crate) mod private {
550
551    /// This trait restricts who can implement `Connection`
552    #[cfg_attr(
553        docsrs,
554        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
555    )]
556    pub trait ConnectionSealed {}
557
558    /// This trait provides helper methods to convert a database lookup type
559    /// to/from an `std::any::Any` reference. This is used internally by the `#[derive(MultiConnection)]`
560    /// implementation
561    #[cfg_attr(
562        docsrs,
563        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
564    )]
565    pub trait MultiConnectionHelper: super::Connection {
566        /// Convert the lookup type to any
567        fn to_any<'a>(
568            lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
569        ) -> &mut (dyn std::any::Any + 'a);
570
571        /// Get the lookup type from any
572        fn from_any(
573            lookup: &mut dyn std::any::Any,
574        ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup>;
575    }
576
577    // These impls are only there for backward compatibility reasons
578    // Remove them on the next breaking release
579    #[allow(unreachable_pub)] // must be pub for the type def using this trait
580    #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
581    pub trait ConnectionHelperType<DB, B>: super::LoadConnection<B, Backend = DB> {
582        type Cursor<'conn, 'query>
583        where
584            Self: 'conn;
585    }
586    #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
587    impl<T, B> ConnectionHelperType<T::Backend, B> for T
588    where
589        T: super::LoadConnection<B>,
590    {
591        type Cursor<'conn, 'query>
592            = <T as super::LoadConnection<B>>::Cursor<'conn, 'query>
593        where
594            T: 'conn;
595    }
596}