Skip to main content

diesel/
r2d2.rs

1//! Connection pooling via r2d2.
2//!
3//! Note: This module requires enabling the `r2d2` feature
4//!
5//! # Example
6//!
7//! The below snippet is a contrived example emulating a web application,
8//! where one would first initialize the pool in the `main()` function
9//! (at the start of a long-running process). One would then pass this
10//! pool struct around as shared state, which, here, we've emulated using
11//! threads instead of routes.
12//!
13//! ```rust
14//! # include!("doctest_setup.rs");
15//! use diesel::prelude::*;
16//! use diesel::r2d2::ConnectionManager;
17//! # use diesel::r2d2::CustomizeConnection;
18//! # use diesel::r2d2::Error as R2D2Error;
19//! use diesel::r2d2::Pool;
20//! use diesel::result::Error;
21//! use std::thread;
22//!
23//! # #[derive(Copy, Clone, Debug)]
24//! # pub struct SetupUserTableCustomizer;
25//! #
26//! # impl CustomizeConnection<DbConnection, R2D2Error> for SetupUserTableCustomizer
27//! # {
28//! #     fn on_acquire(&self, conn: &mut DbConnection) -> Result<(), R2D2Error> {
29//! #         setup_database(conn);
30//! #         Ok(())
31//! #     }
32//! # }
33//!
34//! pub fn get_connection_pool() -> Pool<ConnectionManager<DbConnection>> {
35//!     let url = database_url_for_env();
36//!     let manager = ConnectionManager::<DbConnection>::new(url);
37//!     // Refer to the `r2d2` documentation for more methods to use
38//!     // when building a connection pool
39//!     Pool::builder()
40//! #         .max_size(1)
41//!         .test_on_check_out(true)
42//! #         .connection_customizer(Box::new(SetupUserTableCustomizer))
43//!         .build(manager)
44//!         .expect("Could not build connection pool")
45//! }
46//!
47//! pub fn create_user(conn: &mut DbConnection, user_name: &str) -> Result<usize, Error> {
48//!     use schema::users::dsl::*;
49//!
50//!     diesel::insert_into(users)
51//!         .values(name.eq(user_name))
52//!         .execute(conn)
53//! }
54//!
55//! # // This test uses synchronization primitives that are unsupported under miri.
56//! #[cfg(miri)]
57//! fn main() {}
58//! #[cfg(not(miri))]
59//! fn main() {
60//!     let pool = get_connection_pool();
61//!     let mut threads = vec![];
62//!     let max_users_to_create = 1;
63//!
64//!     for i in 0..max_users_to_create {
65//!         let pool = pool.clone();
66//!         threads.push(thread::spawn({
67//!             move || {
68//!                 let conn = &mut pool.get().unwrap();
69//!                 let name = format!("Person {}", i);
70//!                 create_user(conn, &name).unwrap();
71//!             }
72//!         }))
73//!     }
74//!
75//!     for handle in threads {
76//!         handle.join().unwrap();
77//!     }
78//! }
79//! ```
80//!
81//! # A note on error handling
82//!
83//! When used inside a pool, if an individual connection becomes
84//! broken (as determined by the [R2D2Connection::is_broken] method)
85//! then, when the connection goes out of scope, `r2d2` will close
86//! and return the connection to the DB.
87//!
88//! `diesel` determines broken connections by whether or not the current
89//! thread is panicking or if individual `Connection` structs are
90//! broken (determined by the `is_broken()` method). Generically, these
91//! are left to individual backends to implement themselves.
92//!
93//! For SQLite, PG, and MySQL backends `is_broken()` is determined
94//! by whether or not the `TransactionManagerStatus` (as a part
95//! of the `AnsiTransactionManager` struct) is in an `InError` state
96//! or contains an open transaction when the connection goes out of scope.
97//!
98//!
99//! # Testing with connections pools
100//!
101//! When testing with connection pools, it is recommended to set the pool size to 1,
102//! and use a customizer to ensure that the transactions are never committed.
103//! The tests using a pool prepared this way can be run in parallel, because
104//! the changes are never committed to the database and are local to each test.
105//!
106//! # Example
107//!
108//! ```rust
109//! # include!("doctest_setup.rs");
110//! use diesel::prelude::*;
111//! use diesel::r2d2::ConnectionManager;
112//! use diesel::r2d2::CustomizeConnection;
113//! use diesel::r2d2::TestCustomizer;
114//! # use diesel::r2d2::Error as R2D2Error;
115//! use diesel::r2d2::Pool;
116//! use diesel::result::Error;
117//! use std::thread;
118//!
119//! # fn main() {}
120//!
121//! pub fn get_testing_pool() -> Pool<ConnectionManager<DbConnection>> {
122//!     let url = database_url_for_env();
123//!     let manager = ConnectionManager::<DbConnection>::new(url);
124//!
125//!     Pool::builder()
126//!         .test_on_check_out(true)
127//!         .max_size(1) // Max pool size set to 1
128//!         .connection_customizer(Box::new(TestCustomizer)) // Test customizer
129//!         .build(manager)
130//!         .expect("Could not build connection pool")
131//! }
132//!
133//! table! {
134//!     users {
135//!         id -> Integer,
136//!         name -> Text,
137//!     }
138//! }
139//!
140//! #[cfg(test)]
141//! mod tests {
142//!     use super::*;
143//!
144//!     #[diesel_test_helper::test]
145//!     fn test_1() {
146//!         let pool = get_testing_pool();
147//!         let mut conn = pool.get().unwrap();
148//!
149//!         crate::sql_query(
150//!             "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)",
151//!         )
152//!         .execute(&mut conn)
153//!         .unwrap();
154//!
155//!         crate::insert_into(users::table)
156//!             .values(users::name.eq("John"))
157//!             .execute(&mut conn)
158//!             .unwrap();
159//!     }
160//!
161//!     #[diesel_test_helper::test]
162//!     fn test_2() {
163//!         let pool = get_testing_pool();
164//!         let mut conn = pool.get().unwrap();
165//!
166//!         crate::sql_query(
167//!             "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)",
168//!         )
169//!         .execute(&mut conn)
170//!         .unwrap();
171//!
172//!         let user_count = users::table.count().get_result::<i64>(&mut conn).unwrap();
173//!         assert_eq!(user_count, 0); // Because the transaction from test_1 was never committed
174//!     }
175//! }
176//! ```
177pub use r2d2::*;
178
179/// A re-export of [`r2d2::Error`], which is only used by methods on [`r2d2::Pool`].
180///
181/// [`r2d2::Error`]: r2d2::Error
182/// [`r2d2::Pool`]: r2d2::Pool
183pub type PoolError = r2d2::Error;
184
185use alloc::fmt;
186use core::marker::PhantomData;
187
188use crate::backend::Backend;
189use crate::connection::{
190    ConnectionSealed, LoadConnection, SimpleConnection, TransactionManager,
191    TransactionManagerStatus,
192};
193use crate::expression::QueryMetadata;
194use crate::prelude::*;
195use crate::query_builder::{Query, QueryFragment, QueryId};
196use crate::query_dsl::RunQueryDslSupport;
197
198/// An r2d2 connection manager for use with Diesel.
199///
200/// See the [r2d2 documentation](https://docs.rs/r2d2/latest/r2d2/) for usage examples.
201#[derive(#[automatically_derived]impl<T: ::core::clone::Clone> ::core::clone::Clone for
    ConnectionManager<T> {
    #[inline]
    fn clone(&self) -> Self {
        ConnectionManager {
            database_url: ::core::clone::Clone::clone(&self.database_url),
            _marker: ::core::clone::Clone::clone(&self._marker),
        }
    }
}Clone)]
202pub struct ConnectionManager<T> {
203    database_url: String,
204    _marker: PhantomData<T>,
205}
206
207impl<T> fmt::Debug for ConnectionManager<T> {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        f.write_fmt(format_args!("ConnectionManager<{0}>",
        core::any::type_name::<T>()))write!(f, "ConnectionManager<{}>", core::any::type_name::<T>())
210    }
211}
212
213#[allow(unsafe_code)] // we do not actually hold a reference to `T`
214unsafe impl<T: Send + 'static> Sync for ConnectionManager<T> {}
215
216impl<T> ConnectionManager<T> {
217    /// Returns a new connection manager,
218    /// which establishes connections to the given database URL.
219    pub fn new<S: Into<String>>(database_url: S) -> Self {
220        ConnectionManager {
221            database_url: database_url.into(),
222            _marker: PhantomData,
223        }
224    }
225
226    /// Modifies the URL which was supplied at initialization.
227    ///
228    /// This does not update any state for existing connections,
229    /// but this new URL is used for new connections that are created.
230    pub fn update_database_url<S: Into<String>>(&mut self, database_url: S) {
231        self.database_url = database_url.into();
232    }
233}
234
235/// The error used when managing connections with `r2d2`.
236#[derive(#[automatically_derived]impl ::core::fmt::Debug for Error {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::ConnectionError(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ConnectionError", &__self_0),
            Self::QueryError(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "QueryError", &__self_0),
        }
    }
}Debug)]
237pub enum Error {
238    /// An error occurred establishing the connection
239    ConnectionError(ConnectionError),
240
241    /// An error occurred pinging the database
242    QueryError(crate::result::Error),
243}
244
245impl fmt::Display for Error {
246    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247        match *self {
248            Error::ConnectionError(ref e) => e.fmt(f),
249            Error::QueryError(ref e) => e.fmt(f),
250        }
251    }
252}
253
254impl ::core::error::Error for Error {}
255
256impl From<crate::result::Error> for Error {
257    fn from(other: crate::result::Error) -> Self {
258        Self::QueryError(other)
259    }
260}
261
262impl From<ConnectionError> for Error {
263    fn from(other: ConnectionError) -> Self {
264        Self::ConnectionError(other)
265    }
266}
267
268/// A trait indicating a connection could be used inside a r2d2 pool
269pub trait R2D2Connection: Connection {
270    /// Check if a connection is still valid
271    fn ping(&mut self) -> QueryResult<()>;
272
273    /// Checks if the connection is broken and should not be reused
274    ///
275    /// This method should return only contain a fast non-blocking check
276    /// if the connection is considered to be broken or not. See
277    /// [ManageConnection::has_broken] for details.
278    ///
279    /// The default implementation does not consider any connection as broken
280    fn is_broken(&mut self) -> bool {
281        false
282    }
283}
284
285impl<T> ManageConnection for ConnectionManager<T>
286where
287    T: R2D2Connection + Send + 'static,
288{
289    type Connection = T;
290    type Error = Error;
291
292    fn connect(&self) -> Result<T, Error> {
293        T::establish(&self.database_url).map_err(Error::ConnectionError)
294    }
295
296    fn is_valid(&self, conn: &mut T) -> Result<(), Error> {
297        conn.ping().map_err(Error::QueryError)
298    }
299
300    fn has_broken(&self, conn: &mut T) -> bool {
301        std::thread::panicking() || conn.is_broken()
302    }
303}
304
305impl<M> SimpleConnection for PooledConnection<M>
306where
307    M: ManageConnection,
308    M::Connection: R2D2Connection + Send + 'static,
309{
310    fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
311        (**self).batch_execute(query)
312    }
313}
314
315impl<M> ConnectionSealed for PooledConnection<M>
316where
317    M: ManageConnection,
318    M::Connection: ConnectionSealed,
319{
320}
321
322impl<M> Connection for PooledConnection<M>
323where
324    M: ManageConnection,
325    M::Connection: Connection + R2D2Connection + Send + 'static,
326{
327    type Backend = <M::Connection as Connection>::Backend;
328    type TransactionManager =
329        PoolTransactionManager<<M::Connection as Connection>::TransactionManager>;
330
331    fn establish(_: &str) -> ConnectionResult<Self> {
332        Err(ConnectionError::BadConnection(String::from(
333            "Cannot directly establish a pooled connection",
334        )))
335    }
336
337    fn begin_test_transaction(&mut self) -> QueryResult<()> {
338        (**self).begin_test_transaction()
339    }
340
341    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
342    where
343        T: QueryFragment<Self::Backend> + QueryId,
344    {
345        (**self).execute_returning_count(source)
346    }
347
348    fn transaction_state(
349        &mut self,
350    ) -> &mut <Self::TransactionManager as TransactionManager<Self>>::TransactionStateData {
351        (**self).transaction_state()
352    }
353
354    fn instrumentation(&mut self) -> &mut dyn crate::connection::Instrumentation {
355        (**self).instrumentation()
356    }
357
358    fn set_instrumentation(&mut self, instrumentation: impl crate::connection::Instrumentation) {
359        (**self).set_instrumentation(instrumentation)
360    }
361
362    fn set_prepared_statement_cache_size(&mut self, size: crate::connection::CacheSize) {
363        (**self).set_prepared_statement_cache_size(size)
364    }
365}
366
367impl<B, M> LoadConnection<B> for PooledConnection<M>
368where
369    M: ManageConnection,
370    M::Connection: LoadConnection<B> + R2D2Connection,
371{
372    type Cursor<'conn, 'query> = <M::Connection as LoadConnection<B>>::Cursor<'conn, 'query>;
373    type Row<'conn, 'query> = <M::Connection as LoadConnection<B>>::Row<'conn, 'query>;
374
375    fn load<'conn, 'query, T>(
376        &'conn mut self,
377        source: T,
378    ) -> QueryResult<Self::Cursor<'conn, 'query>>
379    where
380        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
381        Self::Backend: QueryMetadata<T::SqlType>,
382    {
383        (**self).load(source)
384    }
385}
386
387#[doc(hidden)]
388#[allow(missing_debug_implementations)]
389pub struct PoolTransactionManager<T>(core::marker::PhantomData<T>);
390
391impl<M, T> TransactionManager<PooledConnection<M>> for PoolTransactionManager<T>
392where
393    M: ManageConnection,
394    M::Connection: Connection<TransactionManager = T> + R2D2Connection,
395    T: TransactionManager<M::Connection>,
396{
397    type TransactionStateData = T::TransactionStateData;
398
399    fn begin_transaction(conn: &mut PooledConnection<M>) -> QueryResult<()> {
400        T::begin_transaction(&mut **conn)
401    }
402
403    fn rollback_transaction(conn: &mut PooledConnection<M>) -> QueryResult<()> {
404        T::rollback_transaction(&mut **conn)
405    }
406
407    fn commit_transaction(conn: &mut PooledConnection<M>) -> QueryResult<()> {
408        T::commit_transaction(&mut **conn)
409    }
410
411    fn transaction_manager_status_mut(
412        conn: &mut PooledConnection<M>,
413    ) -> &mut TransactionManagerStatus {
414        T::transaction_manager_status_mut(&mut **conn)
415    }
416}
417
418impl<M> crate::migration::MigrationConnection for PooledConnection<M>
419where
420    M: ManageConnection,
421    M::Connection: crate::migration::MigrationConnection,
422    Self: Connection,
423{
424    fn setup(&mut self) -> QueryResult<usize> {
425        (**self).setup()
426    }
427}
428
429impl<Changes, Output, M> crate::query_dsl::UpdateAndFetchResults<Changes, Output>
430    for PooledConnection<M>
431where
432    M: ManageConnection,
433    M::Connection: crate::query_dsl::UpdateAndFetchResults<Changes, Output>,
434    Self: Connection,
435{
436    fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult<Output> {
437        (**self).update_and_fetch(changeset)
438    }
439}
440
441#[derive(const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl diesel::query_builder::QueryId for CheckConnectionQuery {
            type QueryId = CheckConnectionQuery<>;
            const HAS_STATIC_QUERY_ID: bool = true;
            const IS_WINDOW_FUNCTION: bool = false;
        }
    };QueryId)]
442pub(crate) struct CheckConnectionQuery;
443
444impl<DB> QueryFragment<DB> for CheckConnectionQuery
445where
446    DB: Backend,
447{
448    fn walk_ast<'b>(
449        &'b self,
450        mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
451    ) -> QueryResult<()> {
452        pass.push_sql("SELECT 1");
453        Ok(())
454    }
455}
456
457impl Query for CheckConnectionQuery {
458    type SqlType = crate::sql_types::Integer;
459}
460
461impl RunQueryDslSupport for CheckConnectionQuery {}
462
463/// A connection customizer designed for use in tests. Implements
464/// [CustomizeConnection] in a way that ensures transactions
465/// in a pool customized by it are never committed.
466#[derive(#[automatically_derived]impl ::core::fmt::Debug for TestCustomizer {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "TestCustomizer")
    }
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for TestCustomizer {
}
#[automatically_derived]impl ::core::clone::Clone for TestCustomizer {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for TestCustomizer { }Copy)]
467pub struct TestCustomizer;
468
469impl<C: Connection> CustomizeConnection<C, crate::r2d2::Error> for TestCustomizer {
470    fn on_acquire(&self, conn: &mut C) -> Result<(), crate::r2d2::Error> {
471        conn.begin_test_transaction()
472            .map_err(crate::r2d2::Error::QueryError)
473    }
474}
475
476// The r2d2 pool spawns worker threads via `scheduled-thread-pool`, which
477// relies on `parking_lot_core`'s futex usage. Miri flags that futex call as
478// undefined behavior (incorrect c-variadic argument type), which is a known
479// issue in `parking_lot_core` rather than in diesel, so these tests are
480// excluded from miri runs.
481#[cfg(all(
482    test,
483    not(miri),
484    not(all(target_family = "wasm", target_os = "unknown"))
485))]
486mod tests {
487    use std::sync::Arc;
488    use std::sync::mpsc;
489    use std::thread;
490    use std::time::Duration;
491
492    use crate::r2d2::*;
493    use crate::test_helpers::*;
494
495    #[diesel_test_helper::test]
496    fn establish_basic_connection() {
497        let manager = ConnectionManager::<TestConnection>::new(database_url());
498        let pool = Arc::new(Pool::builder().max_size(2).build(manager).unwrap());
499
500        let (s1, r1) = mpsc::channel();
501        let (s2, r2) = mpsc::channel();
502
503        let pool1 = Arc::clone(&pool);
504        let t1 = thread::spawn(move || {
505            let conn = pool1.get().unwrap();
506            s1.send(()).unwrap();
507            r2.recv().unwrap();
508            drop(conn);
509        });
510
511        let pool2 = Arc::clone(&pool);
512        let t2 = thread::spawn(move || {
513            let conn = pool2.get().unwrap();
514            s2.send(()).unwrap();
515            r1.recv().unwrap();
516            drop(conn);
517        });
518
519        t1.join().unwrap();
520        t2.join().unwrap();
521
522        pool.get().unwrap();
523    }
524
525    #[diesel_test_helper::test]
526    fn is_valid() {
527        let manager = ConnectionManager::<TestConnection>::new(database_url());
528        let pool = Pool::builder()
529            .max_size(1)
530            .test_on_check_out(true)
531            .build(manager)
532            .unwrap();
533
534        pool.get().unwrap();
535    }
536
537    #[diesel_test_helper::test]
538    fn pooled_connection_impls_connection() {
539        use crate::select;
540        use crate::sql_types::Text;
541
542        let manager = ConnectionManager::<TestConnection>::new(database_url());
543        let pool = Pool::builder()
544            .max_size(1)
545            .test_on_check_out(true)
546            .build(manager)
547            .unwrap();
548        let mut conn = pool.get().unwrap();
549
550        let query = select("foo".into_sql::<Text>());
551        assert_eq!("foo", query.get_result::<String>(&mut conn).unwrap());
552    }
553
554    #[diesel_test_helper::test]
555    fn check_pool_does_actually_hold_connections() {
556        use std::sync::atomic::{AtomicU32, Ordering};
557
558        #[derive(Debug)]
559        struct TestEventHandler {
560            acquire_count: Arc<AtomicU32>,
561            release_count: Arc<AtomicU32>,
562            checkin_count: Arc<AtomicU32>,
563            checkout_count: Arc<AtomicU32>,
564        }
565
566        impl r2d2::HandleEvent for TestEventHandler {
567            fn handle_acquire(&self, _event: r2d2::event::AcquireEvent) {
568                self.acquire_count.fetch_add(1, Ordering::Relaxed);
569            }
570            fn handle_release(&self, _event: r2d2::event::ReleaseEvent) {
571                self.release_count.fetch_add(1, Ordering::Relaxed);
572            }
573            fn handle_checkout(&self, _event: r2d2::event::CheckoutEvent) {
574                self.checkout_count.fetch_add(1, Ordering::Relaxed);
575            }
576            fn handle_checkin(&self, _event: r2d2::event::CheckinEvent) {
577                self.checkin_count.fetch_add(1, Ordering::Relaxed);
578            }
579        }
580
581        let acquire_count = Arc::new(AtomicU32::new(0));
582        let release_count = Arc::new(AtomicU32::new(0));
583        let checkin_count = Arc::new(AtomicU32::new(0));
584        let checkout_count = Arc::new(AtomicU32::new(0));
585
586        let handler = Box::new(TestEventHandler {
587            acquire_count: acquire_count.clone(),
588            release_count: release_count.clone(),
589            checkin_count: checkin_count.clone(),
590            checkout_count: checkout_count.clone(),
591        });
592
593        let manager = ConnectionManager::<TestConnection>::new(database_url());
594        let pool = Pool::builder()
595            .max_size(1)
596            .test_on_check_out(true)
597            .event_handler(handler)
598            .build(manager)
599            .unwrap();
600
601        assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
602        assert_eq!(release_count.load(Ordering::Relaxed), 0);
603        assert_eq!(checkin_count.load(Ordering::Relaxed), 0);
604        assert_eq!(checkout_count.load(Ordering::Relaxed), 0);
605
606        // check that we reuse connections with the pool
607        {
608            let conn = pool.get().unwrap();
609
610            assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
611            assert_eq!(release_count.load(Ordering::Relaxed), 0);
612            assert_eq!(checkin_count.load(Ordering::Relaxed), 0);
613            assert_eq!(checkout_count.load(Ordering::Relaxed), 1);
614            std::mem::drop(conn);
615        }
616
617        assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
618        assert_eq!(release_count.load(Ordering::Relaxed), 0);
619        assert_eq!(checkin_count.load(Ordering::Relaxed), 1);
620        assert_eq!(checkout_count.load(Ordering::Relaxed), 1);
621
622        // check that we remove a connection with open transactions from the pool
623        {
624            let mut conn = pool.get().unwrap();
625
626            assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
627            assert_eq!(release_count.load(Ordering::Relaxed), 0);
628            assert_eq!(checkin_count.load(Ordering::Relaxed), 1);
629            assert_eq!(checkout_count.load(Ordering::Relaxed), 2);
630
631            <TestConnection as Connection>::TransactionManager::begin_transaction(&mut *conn)
632                .unwrap();
633        }
634
635        // we are not interested in the acquire count here
636        // as the pool opens a new connection in the background
637        // that could lead to this test failing if that happens to fast
638        // (which is sometimes the case for sqlite)
639        //assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
640        assert_eq!(release_count.load(Ordering::Relaxed), 1);
641        assert_eq!(checkin_count.load(Ordering::Relaxed), 2);
642        assert_eq!(checkout_count.load(Ordering::Relaxed), 2);
643
644        // check that we remove a connection from the pool that was
645        // open during panicking
646        #[allow(unreachable_code, unused_variables)]
647        std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
648            let conn = pool.get();
649            assert_eq!(acquire_count.load(Ordering::Relaxed), 2);
650            assert_eq!(release_count.load(Ordering::Relaxed), 1);
651            assert_eq!(checkin_count.load(Ordering::Relaxed), 2);
652            assert_eq!(checkout_count.load(Ordering::Relaxed), 3);
653            panic!();
654            std::mem::drop(conn);
655        }))
656        .unwrap_err();
657
658        // we are not interested in the acquire count here
659        // as the pool opens a new connection in the background
660        // that could lead to this test failing if that happens to fast
661        // (which is sometimes the case for sqlite)
662        //assert_eq!(acquire_count.load(Ordering::Relaxed), 2);
663        assert_eq!(release_count.load(Ordering::Relaxed), 2);
664        assert_eq!(checkin_count.load(Ordering::Relaxed), 3);
665        assert_eq!(checkout_count.load(Ordering::Relaxed), 3);
666        // this is required to workaround a segfault while shutting down
667        // the pool
668        std::thread::sleep(Duration::from_millis(100));
669    }
670
671    #[cfg(feature = "postgres")]
672    #[diesel_test_helper::test]
673    fn verify_that_begin_test_transaction_works_with_pools() {
674        use crate::prelude::*;
675        use crate::r2d2::*;
676
677        table! {
678            users {
679                id -> Integer,
680                name -> Text,
681            }
682        }
683
684        #[derive(Debug)]
685        struct TestConnectionCustomizer;
686
687        impl<E> CustomizeConnection<PgConnection, E> for TestConnectionCustomizer {
688            fn on_acquire(&self, conn: &mut PgConnection) -> Result<(), E> {
689                conn.begin_test_transaction()
690                    .expect("Failed to start test transaction");
691
692                Ok(())
693            }
694        }
695
696        let manager = ConnectionManager::<PgConnection>::new(database_url());
697        let pool = Pool::builder()
698            .max_size(1)
699            .connection_customizer(Box::new(TestConnectionCustomizer))
700            .build(manager)
701            .unwrap();
702
703        let mut conn = pool.get().unwrap();
704
705        crate::sql_query(
706            "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)",
707        )
708        .execute(&mut conn)
709        .unwrap();
710
711        crate::insert_into(users::table)
712            .values(users::name.eq("John"))
713            .execute(&mut conn)
714            .unwrap();
715
716        std::mem::drop(conn);
717
718        let mut conn2 = pool.get().unwrap();
719
720        let user_count = users::table.count().get_result::<i64>(&mut conn2).unwrap();
721        assert_eq!(user_count, 1);
722    }
723}