Skip to main content

diesel/pg/connection/
mod.rs

1pub(super) mod copy;
2pub(crate) mod cursor;
3mod raw;
4mod result;
5mod row;
6mod stmt;
7
8use self::copy::{CopyFromSink, CopyToBuffer};
9use self::cursor::*;
10use self::private::{ConnectionAndTransactionManager, CopyFromWrapper, QueryFragmentHelper};
11use self::raw::{PgTransactionStatus, RawConnection};
12use self::stmt::Statement;
13use crate::RunQueryDsl;
14use crate::connection::instrumentation::{DynInstrumentation, Instrumentation, StrQueryHelper};
15use crate::connection::statement_cache::{MaybeCached, StatementCache};
16use crate::connection::*;
17use crate::expression::QueryMetadata;
18use crate::pg::backend::PgNotification;
19use crate::pg::metadata_lookup::{GetPgMetadataCache, PgMetadataCache};
20use crate::pg::query_builder::copy::InternalCopyFromQuery;
21use crate::pg::{Pg, TransactionBuilder};
22use crate::query_builder::bind_collector::RawBytesBindCollector;
23use crate::query_builder::*;
24use crate::result::ConnectionError::CouldntSetupConfiguration;
25use crate::result::*;
26use alloc::ffi::CString;
27use core::ffi as libc;
28use core::fmt::Debug;
29
30use super::query_builder::copy::{CopyFromExpression, CopyTarget, CopyToCommand};
31
32pub(super) use self::result::PgResult;
33
34/// The connection string expected by `PgConnection::establish`
35/// should be a PostgreSQL connection string, as documented at
36/// <https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING>
37///
38/// Every error the server reports carries its SQLSTATE in
39/// [`DatabaseErrorInformation::sqlstate`], including custom codes raised with
40/// [`RAISE`](https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html).
41/// Errors that happen before the server answers, such as a failure to send a
42/// query, carry none. The codes PostgreSQL defines are constants in
43/// [`sql_state`](crate::pg::sql_state).
44///
45/// # Supported loading model implementations
46///
47/// * [`DefaultLoadingMode`]
48/// * [`PgRowByRowLoadingMode`]
49///
50/// If you are unsure which loading mode is the correct one for your application,
51/// you likely want to use the `DefaultLoadingMode` as it's simpler and more intuitive.
52/// However, if you plan to process each row on its own, you should use the `PgRowByRowLoadingMode` and
53/// you can also expect a performance boost.
54///
55/// Due to the fact that `PgConnection` supports multiple loading modes
56/// it is **required** to always specify the used loading mode
57/// when calling [`RunQueryDsl::load_iter`]
58///
59/// ## `DefaultLoadingMode`
60///
61/// By using this mode `PgConnection` defaults to loading all response values at **once**
62/// and only performs deserialization afterward for the `DefaultLoadingMode`.
63///
64/// This loading mode allows users to perform hold more than one iterator at once using
65/// the same connection:
66/// ```rust,dejadoc
67/// # include!("../../doctest_setup.rs");
68/// #
69/// # fn main() {
70/// #     run_test().unwrap();
71/// # }
72/// #
73/// # fn run_test() -> QueryResult<()> {
74/// #     use schema::users;
75/// #     let connection = &mut establish_connection();
76/// use diesel::connection::DefaultLoadingMode;
77///
78/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
79/// let iter2 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
80///
81/// for r in iter1 {
82///     let (id, name) = r?;
83///     println!("Id: {} Name: {}", id, name);
84/// }
85///
86/// for r in iter2 {
87///     let (id, name) = r?;
88///     println!("Id: {} Name: {}", id, name);
89/// }
90/// #   Ok(())
91/// # }
92/// ```
93///
94/// ## `PgRowByRowLoadingMode`
95///
96/// By using this mode `PgConnection` defaults to loading each row of the result set
97/// separately. This might be desired for huge result sets.
98///
99/// This loading mode **prevents** creating more than one iterator at once using
100/// the same connection. The following code is **not** allowed:
101///
102/// ```compile_fail
103/// # include!("../../doctest_setup.rs");
104/// #
105/// # fn main() {
106/// #     run_test().unwrap();
107/// # }
108/// #
109/// # fn run_test() -> QueryResult<()> {
110/// #     use schema::users;
111/// #     let connection = &mut establish_connection();
112/// use diesel::pg::PgRowByRowLoadingMode;
113///
114/// let iter1 = users::table.load_iter::<(i32, String), PgRowByRowLoadingMode>(connection)?;
115/// // creating a second iterator generates an compiler error
116/// let iter2 = users::table.load_iter::<(i32, String), PgRowByRowLoadingMode>(connection)?;
117///
118/// for r in iter1 {
119///     let (id, name) = r?;
120///     println!("Id: {} Name: {}", id, name);
121/// }
122///
123/// for r in iter2 {
124///     let (id, name) = r?;
125///     println!("Id: {} Name: {}", id, name);
126/// }
127/// #   Ok(())
128/// # }
129/// ```
130#[allow(missing_debug_implementations)]
131#[cfg(feature = "postgres")]
132pub struct PgConnection {
133    statement_cache: StatementCache<Pg, Statement>,
134    metadata_cache: PgMetadataCache,
135    connection_and_transaction_manager: ConnectionAndTransactionManager,
136}
137
138// according to libpq documentation a connection can be transferred to other threads
139#[allow(unsafe_code)]
140unsafe impl Send for PgConnection {}
141
142impl SimpleConnection for PgConnection {
143    #[allow(unsafe_code)] // use of unsafe function
144    fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
145        self.connection_and_transaction_manager
146            .instrumentation
147            .on_connection_event(InstrumentationEvent::StartQuery {
148                query: &StrQueryHelper::new(query),
149            });
150        let c_query = CString::new(query)?;
151        let inner_result = unsafe {
152            self.connection_and_transaction_manager
153                .raw_connection
154                .exec(c_query.as_ptr())
155        };
156        update_transaction_manager_status(
157            inner_result.and_then(|raw_result| {
158                PgResult::new(
159                    raw_result,
160                    &self.connection_and_transaction_manager.raw_connection,
161                )
162                .and_then(|r| {
163                    self::stmt::handle_copy_in_normal_stmt(
164                        &mut self.connection_and_transaction_manager.raw_connection,
165                        true,
166                        r,
167                    )
168                })
169            }),
170            &mut self.connection_and_transaction_manager,
171            &|callback| callback(&StrQueryHelper::new(query)),
172            true,
173        )?;
174        Ok(())
175    }
176}
177
178/// A [`PgConnection`] specific loading mode to load rows one by one
179///
180/// See the documentation of [`PgConnection`] for details
181#[derive(#[automatically_derived]impl ::core::fmt::Debug for PgRowByRowLoadingMode {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "PgRowByRowLoadingMode")
    }
}Debug, #[automatically_derived]impl ::core::marker::Copy for PgRowByRowLoadingMode {
}Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for PgRowByRowLoadingMode {
}
#[automatically_derived]impl ::core::clone::Clone for PgRowByRowLoadingMode {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone)]
182pub struct PgRowByRowLoadingMode;
183
184impl ConnectionSealed for PgConnection {}
185
186impl Connection for PgConnection {
187    type Backend = Pg;
188    type TransactionManager = AnsiTransactionManager;
189
190    fn establish(database_url: &str) -> ConnectionResult<PgConnection> {
191        let mut instrumentation = DynInstrumentation::default_instrumentation();
192        instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
193            url: database_url,
194        });
195        let r = RawConnection::establish(database_url).and_then(|raw_conn| {
196            let mut conn = PgConnection {
197                connection_and_transaction_manager: ConnectionAndTransactionManager {
198                    raw_connection: raw_conn,
199                    transaction_state: AnsiTransactionManager::default(),
200                    instrumentation: DynInstrumentation::none(),
201                },
202                statement_cache: StatementCache::new(),
203                metadata_cache: PgMetadataCache::new(),
204            };
205            conn.set_config_options()
206                .map_err(CouldntSetupConfiguration)?;
207            Ok(conn)
208        });
209        instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
210            url: database_url,
211            error: r.as_ref().err(),
212        });
213        let mut conn = r?;
214        conn.connection_and_transaction_manager.instrumentation = instrumentation;
215        Ok(conn)
216    }
217
218    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
219    where
220        T: QueryFragment<Pg> + QueryId,
221    {
222        update_transaction_manager_status(
223            self.with_prepared_query(
224                Box::new(source),
225                true,
226                &mut |query, params, conn, _source| {
227                    let res = query
228                        .execute(&mut conn.raw_connection, &params, false, true)
229                        .and_then(|r| r.rows_affected());
230                    // according to https://www.postgresql.org/docs/current/libpq-async.html
231                    // `PQgetResult` needs to be called till a null pointer is returned
232                    while conn.raw_connection.get_next_result()?.is_some() {}
233                    res
234                },
235            ),
236            &mut self.connection_and_transaction_manager,
237            &|callback| source.instrumentation(callback),
238            true,
239        )
240    }
241
242    fn transaction_state(&mut self) -> &mut AnsiTransactionManager
243    where
244        Self: Sized,
245    {
246        &mut self.connection_and_transaction_manager.transaction_state
247    }
248
249    fn instrumentation(&mut self) -> &mut dyn Instrumentation {
250        &mut *self.connection_and_transaction_manager.instrumentation
251    }
252
253    fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
254        self.connection_and_transaction_manager.instrumentation = instrumentation.into();
255    }
256
257    fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
258        self.statement_cache.set_cache_size(size);
259    }
260}
261
262impl<B> LoadConnection<B> for PgConnection
263where
264    Self: self::private::PgLoadingMode<B>,
265{
266    type Cursor<'conn, 'query> = <Self as self::private::PgLoadingMode<B>>::Cursor<'conn, 'query>;
267    type Row<'conn, 'query> = <Self as self::private::PgLoadingMode<B>>::Row<'conn, 'query>;
268
269    fn load<'conn, 'query, T>(
270        &'conn mut self,
271        source: T,
272    ) -> QueryResult<Self::Cursor<'conn, 'query>>
273    where
274        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
275        Self::Backend: QueryMetadata<T::SqlType>,
276    {
277        self.with_prepared_query(
278            Box::new(source),
279            false,
280            &mut |stmt, params, conn, source| {
281                use self::private::PgLoadingMode;
282                let result = inner_load(stmt, params, conn, &*source, Self::USE_ROW_BY_ROW_MODE)?;
283                Self::get_cursor(conn, result, source)
284            },
285        )
286    }
287}
288
289fn inner_load(
290    stmt: MaybeCached<'_, Statement>,
291    params: Vec<Option<Vec<u8>>>,
292    conn: &mut ConnectionAndTransactionManager,
293    source: &dyn QueryFragmentHelper<crate::result::Error>,
294    row_by_row: bool,
295) -> Result<PgResult, Error> {
296    let result = stmt.execute(&mut conn.raw_connection, &params, row_by_row, true);
297    update_transaction_manager_status(
298        result,
299        conn,
300        &|callback| source.instrumentation(callback),
301        false,
302    )
303}
304
305impl GetPgMetadataCache for PgConnection {
306    fn get_metadata_cache(&mut self) -> &mut PgMetadataCache {
307        &mut self.metadata_cache
308    }
309}
310
311#[inline(always)]
312fn update_transaction_manager_status<T>(
313    query_result: QueryResult<T>,
314    conn: &mut ConnectionAndTransactionManager,
315    instrumentation_callback: &dyn Fn(
316        &mut dyn FnMut(&dyn crate::connection::instrumentation::DebugQuery),
317    ),
318    final_call: bool,
319) -> QueryResult<T> {
320    /// avoid monomorphizing for every result type - this part will not be inlined
321    fn non_generic_inner(conn: &mut ConnectionAndTransactionManager, is_err: bool) {
322        let raw_conn: &mut RawConnection = &mut conn.raw_connection;
323        let tm: &mut AnsiTransactionManager = &mut conn.transaction_state;
324        // libpq keeps track of the transaction status internally, and that is accessible
325        // via `transaction_status`. We can use that to update the AnsiTransactionManager
326        // status
327        match raw_conn.transaction_status() {
328            PgTransactionStatus::InError => {
329                tm.status.set_requires_rollback_maybe_up_to_top_level(true)
330            }
331            PgTransactionStatus::Unknown => tm.status.set_in_error(),
332            PgTransactionStatus::Idle => {
333                // This is useful in particular for commit attempts (even
334                // if `COMMIT` errors it still exits transaction)
335
336                // This may repair the transaction manager
337                tm.status = TransactionManagerStatus::Valid(Default::default())
338            }
339            PgTransactionStatus::InTransaction => {
340                let transaction_status = &mut tm.status;
341                // If we weren't an error, it is possible that we were a transaction start
342                // -> we should tolerate any state
343                if is_err {
344                    // An error may not have us enter a transaction, so if we weren't in one
345                    // we may not be in one now
346                    if !#[allow(non_exhaustive_omitted_patterns)] match transaction_status {
    TransactionManagerStatus::Valid(valid_tm) if
        valid_tm.transaction_depth().is_some() => true,
    _ => false,
}matches!(transaction_status, TransactionManagerStatus::Valid(valid_tm) if valid_tm.transaction_depth().is_some())
347                    {
348                        // -> transaction manager is broken
349                        transaction_status.set_in_error()
350                    }
351                } else {
352                    // If transaction was InError before, but now it's not (because we attempted
353                    // a rollback), we may pretend it's fixed because
354                    // if it isn't Postgres *will* tell us again.
355
356                    // Fun fact: if we have not received an `InTransaction` status however,
357                    // postgres will *not* warn us that transaction is broken when attempting to
358                    // commit, so we may think that commit has succeeded but in fact it hasn't.
359                    tm.status.set_requires_rollback_maybe_up_to_top_level(false)
360                }
361            }
362            PgTransactionStatus::Active => {
363                // This is a transient state for libpq - nothing we can deduce here.
364            }
365        }
366    }
367
368    fn non_generic_instrumentation(
369        query_result: Result<(), &Error>,
370        conn: &mut ConnectionAndTransactionManager,
371        instrumentation_callback: &dyn Fn(
372            &mut dyn FnMut(&dyn crate::connection::instrumentation::DebugQuery),
373        ),
374        final_call: bool,
375    ) {
376        if let Err(e) = query_result {
377            instrumentation_callback(&mut |query| {
378                conn.instrumentation
379                    .on_connection_event(InstrumentationEvent::FinishQuery {
380                        query,
381                        error: Some(e),
382                    })
383            });
384        } else if final_call {
385            instrumentation_callback(&mut |query| {
386                conn.instrumentation
387                    .on_connection_event(InstrumentationEvent::FinishQuery { query, error: None });
388            });
389        }
390    }
391
392    non_generic_inner(conn, query_result.is_err());
393    non_generic_instrumentation(
394        query_result.as_ref().map(|_| ()),
395        conn,
396        instrumentation_callback,
397        final_call,
398    );
399    query_result
400}
401
402#[cfg(feature = "r2d2")]
403impl crate::r2d2::R2D2Connection for PgConnection {
404    fn ping(&mut self) -> QueryResult<()> {
405        crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
406    }
407
408    fn is_broken(&mut self) -> bool {
409        AnsiTransactionManager::is_broken_transaction_manager(self)
410    }
411}
412
413impl MultiConnectionHelper for PgConnection {
414    fn to_any<'a>(
415        lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
416    ) -> &mut (dyn core::any::Any + 'a) {
417        lookup.as_any()
418    }
419
420    fn from_any(
421        lookup: &mut dyn core::any::Any,
422    ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
423        lookup
424            .downcast_mut::<Self>()
425            .map(|conn| conn as &mut dyn super::PgMetadataLookup)
426    }
427}
428
429impl PgConnection {
430    /// Build a transaction, specifying additional details such as isolation level
431    ///
432    /// See [`TransactionBuilder`] for more examples.
433    ///
434    /// [`TransactionBuilder`]: crate::pg::TransactionBuilder
435    ///
436    /// ```rust
437    /// # include!("../../doctest_setup.rs");
438    /// #
439    /// # fn main() {
440    /// #     run_test().unwrap();
441    /// # }
442    /// #
443    /// # fn run_test() -> QueryResult<()> {
444    /// #     use schema::users::dsl::*;
445    /// #     let conn = &mut connection_no_transaction();
446    /// conn.build_transaction()
447    ///     .read_only()
448    ///     .serializable()
449    ///     .deferrable()
450    ///     .run(|conn| Ok(()))
451    /// # }
452    /// ```
453    pub fn build_transaction(&mut self) -> TransactionBuilder<'_, Self> {
454        TransactionBuilder::new(self)
455    }
456
457    /// Returns the version of the server this connection is connected to, with a patch of zero since PostgreSQL 10 numbers releases `major.minor`.
458    ///
459    /// # Errors
460    ///
461    /// Fails with [`DatabaseErrorKind::ClosedConnection`] once the connection is lost.
462    ///
463    /// # Example
464    ///
465    /// ```rust
466    /// # include!("../../doctest_setup.rs");
467    /// use diesel::connection::DatabaseVersion;
468    /// #
469    /// # fn main() {
470    /// #     run_test().unwrap();
471    /// # }
472    /// #
473    /// # fn run_test() -> QueryResult<()> {
474    /// #     let conn = &mut establish_connection();
475    /// let supports_returning_old = conn.version()? >= DatabaseVersion::new(18, 0, 0);
476    /// #     Ok(())
477    /// # }
478    /// ```
479    pub fn version(&self) -> QueryResult<DatabaseVersion> {
480        let raw_connection = &self.connection_and_transaction_manager.raw_connection;
481        decode_server_version(raw_connection.server_version()).ok_or_else(|| {
482            Error::DatabaseError(
483                DatabaseErrorKind::ClosedConnection,
484                Box::new(raw_connection.last_error_message()),
485            )
486        })
487    }
488
489    pub(crate) fn copy_from<S, T>(&mut self, target: S) -> Result<usize, S::Error>
490    where
491        S: CopyFromExpression<T>,
492    {
493        let query = CopyFromWrapper(core::cell::RefCell::new(InternalCopyFromQuery::new(target)));
494        let res =
495            self.with_prepared_query(Box::new(query), false, &mut |stmt, binds, conn, source| {
496                fn inner_copy_in<S, T>(
497                    stmt: MaybeCached<'_, Statement>,
498                    conn: &mut ConnectionAndTransactionManager,
499                    binds: Vec<Option<Vec<u8>>>,
500                    source: &dyn QueryFragmentHelper<S::Error>,
501                ) -> Result<usize, S::Error>
502                where
503                    S: CopyFromExpression<T>,
504                {
505                    let _res = stmt.execute(&mut conn.raw_connection, &binds, false, false)?;
506                    let mut copy_in = CopyFromSink::new(&mut conn.raw_connection);
507                    let r = source.write_copy_from(&mut copy_in);
508                    copy_in.finish(r.as_ref().err().map(|e| e.to_string()))?;
509                    let next_res = conn.raw_connection.get_next_result()?.ok_or_else(|| {
510                        crate::result::Error::DeserializationError(
511                            "Failed to receive result from the database".into(),
512                        )
513                    })?;
514                    let rows = next_res.rows_affected();
515                    while let Some(_r) = conn.raw_connection.get_next_result()? {}
516                    r?;
517                    rows.map_err(Into::into)
518                }
519
520                let rows = inner_copy_in::<S, T>(stmt, conn, binds, &*source);
521                if let Err(ref e) = rows {
522                    let database_error = crate::result::Error::DatabaseError(
523                        crate::result::DatabaseErrorKind::Unknown,
524                        Box::new(e.to_string()),
525                    );
526                    source.instrumentation(&mut |query| {
527                        conn.instrumentation.on_connection_event(
528                            InstrumentationEvent::FinishQuery {
529                                query,
530                                error: Some(&database_error),
531                            },
532                        );
533                    });
534                } else {
535                    source.instrumentation(&mut |query| {
536                        conn.instrumentation.on_connection_event(
537                            InstrumentationEvent::FinishQuery { query, error: None },
538                        );
539                    });
540                }
541
542                rows
543            })?;
544
545        Ok(res)
546    }
547
548    pub(crate) fn copy_to<T>(&mut self, command: CopyToCommand<T>) -> QueryResult<CopyToBuffer<'_>>
549    where
550        T: CopyTarget,
551    {
552        let res = self.with_prepared_query::<_, Error>(
553            Box::new(command),
554            false,
555            &mut |stmt, binds, conn, source| {
556                let res = stmt.execute(&mut conn.raw_connection, &binds, false, false);
557                source.instrumentation(&mut |query| {
558                    conn.instrumentation
559                        .on_connection_event(InstrumentationEvent::FinishQuery {
560                            query,
561                            error: res.as_ref().err(),
562                        });
563                });
564                Ok(CopyToBuffer::new(&mut conn.raw_connection, res?))
565            },
566        )?;
567        Ok(res)
568    }
569
570    fn with_prepared_query<'conn, 'query, R, E>(
571        &'conn mut self,
572        source: Box<dyn QueryFragmentHelper<E> + 'query>,
573        execute_returning_count: bool,
574        f: &mut dyn FnMut(
575            MaybeCached<'_, Statement>,
576            Vec<Option<Vec<u8>>>,
577            &'conn mut ConnectionAndTransactionManager,
578            Box<dyn QueryFragmentHelper<E> + 'query>,
579        ) -> Result<R, E>,
580    ) -> Result<R, E>
581    where
582        E: From<crate::result::Error>,
583    {
584        fn prepare_query_non_generic_inner<'a, E>(
585            connection_and_transaction_manager: &mut ConnectionAndTransactionManager,
586            cache: &'a mut StatementCache<Pg, Statement>,
587            source: &dyn QueryFragmentHelper<E>,
588            execute_returning_count: bool,
589            bind_collector: RawBytesBindCollector<Pg>,
590        ) -> QueryResult<(
591            Vec<Option<Vec<u8>>>,
592            Result<MaybeCached<'a, Statement>, Error>,
593        )> {
594            let binds = bind_collector.binds;
595            let metadata = bind_collector.metadata;
596            let query = cache.cached_statement_non_generic(
597                source.query_id(),
598                source,
599                &Pg,
600                &metadata,
601                &mut connection_and_transaction_manager.raw_connection,
602                Statement::prepare,
603                &mut *connection_and_transaction_manager.instrumentation,
604            );
605            if !execute_returning_count && let Err(ref e) = query {
606                source.instrumentation(&mut |query| {
607                    connection_and_transaction_manager
608                        .instrumentation
609                        .on_connection_event(InstrumentationEvent::FinishQuery {
610                            query,
611                            error: Some(e),
612                        });
613                });
614            }
615            Ok((binds, query))
616        }
617
618        let bind_collector = self.collect_binds(&*source)?;
619        let (binds, query) = prepare_query_non_generic_inner(
620            &mut self.connection_and_transaction_manager,
621            &mut self.statement_cache,
622            &*source,
623            execute_returning_count,
624            bind_collector,
625        )?;
626
627        f(
628            query?,
629            binds,
630            &mut self.connection_and_transaction_manager,
631            source,
632        )
633    }
634
635    fn collect_binds<E>(
636        &mut self,
637        source: &dyn QueryFragmentHelper<E>,
638    ) -> Result<RawBytesBindCollector<Pg>, crate::result::Error> {
639        source.instrumentation(&mut |query| {
640            self.connection_and_transaction_manager
641                .instrumentation
642                .on_connection_event(InstrumentationEvent::StartQuery { query });
643        });
644        let mut bind_collector = RawBytesBindCollector::<Pg>::new();
645        source.collect_binds(&mut bind_collector, self)?;
646        Ok(bind_collector)
647    }
648
649    fn set_config_options(&mut self) -> QueryResult<()> {
650        crate::sql_query("SET TIME ZONE 'UTC'").execute(self)?;
651        crate::sql_query("SET CLIENT_ENCODING TO 'UTF8'").execute(self)?;
652        self.connection_and_transaction_manager
653            .raw_connection
654            .set_notice_processor(noop_notice_processor);
655        Ok(())
656    }
657
658    /// See Postgres documentation for SQL commands [NOTIFY][] and [LISTEN][]
659    ///
660    /// The returned iterator can yield items even after a None value when new notifications have been received.
661    /// The iterator can be polled again after a `None` value was received as new notifications might have
662    /// been send in the mean time.
663    ///
664    /// [NOTIFY]: https://www.postgresql.org/docs/current/sql-notify.html
665    /// [LISTEN]: https://www.postgresql.org/docs/current/sql-listen.html
666    ///
667    /// ## Example
668    ///
669    /// ```
670    /// # include!("../../doctest_setup.rs");
671    /// #
672    /// # fn main() {
673    /// #     run_test().unwrap();
674    /// # }
675    /// #
676    /// # fn run_test() -> QueryResult<()> {
677    /// #     let connection = &mut establish_connection();
678    ///
679    /// // register the notifications channel we want to receive notifications for
680    /// diesel::sql_query("LISTEN example_channel").execute(connection)?;
681    /// // send some notification
682    /// // this is usually done from a different connection/thread/application
683    /// diesel::sql_query("NOTIFY example_channel, 'additional data'").execute(connection)?;
684    ///
685    /// for result in connection.notifications_iter() {
686    ///     let notification = result.unwrap();
687    ///     assert_eq!(notification.channel, "example_channel");
688    ///     assert_eq!(notification.payload, "additional data");
689    ///
690    ///     println!(
691    ///         "Notification received from server process with id {}.",
692    ///         notification.process_id
693    ///     );
694    /// }
695    /// # Ok(())
696    /// # }
697    /// ```
698    pub fn notifications_iter(&mut self) -> impl Iterator<Item = QueryResult<PgNotification>> + '_ {
699        let conn = &self.connection_and_transaction_manager.raw_connection;
700        core::iter::from_fn(move || conn.pq_notifies().transpose())
701    }
702}
703
704/// Decodes `PQserverVersion`, which packs two digits per part before PostgreSQL 10 and is zero for a bad connection.
705fn decode_server_version(version: libc::c_int) -> Option<DatabaseVersion> {
706    let version = u32::try_from(version)
707        .ok()
708        .filter(|&version| version != 0)?;
709    Some(if version >= 100_000 {
710        DatabaseVersion::new(version / 10_000, version % 10_000, 0)
711    } else {
712        DatabaseVersion::new(version / 10_000, version / 100 % 100, version % 100)
713    })
714}
715
716extern "C" fn noop_notice_processor(_: *mut libc::c_void, _message: *const libc::c_char) {}
717
718mod private {
719    use super::*;
720
721    #[allow(missing_debug_implementations)]
722    pub struct ConnectionAndTransactionManager {
723        pub(super) raw_connection: RawConnection,
724        pub(super) transaction_state: AnsiTransactionManager,
725        pub(super) instrumentation: DynInstrumentation,
726    }
727
728    pub trait PgLoadingMode<B> {
729        const USE_ROW_BY_ROW_MODE: bool;
730        type Cursor<'conn, 'query>: Iterator<Item = QueryResult<Self::Row<'conn, 'query>>>;
731        type Row<'conn, 'query>: crate::row::Row<'conn, Pg>;
732
733        fn get_cursor<'conn, 'query>(
734            raw_connection: &'conn mut ConnectionAndTransactionManager,
735            result: PgResult,
736            source: Box<dyn QueryFragmentHelper<crate::result::Error> + 'query>,
737        ) -> QueryResult<Self::Cursor<'conn, 'query>>;
738    }
739
740    impl PgLoadingMode<DefaultLoadingMode> for PgConnection {
741        const USE_ROW_BY_ROW_MODE: bool = false;
742        type Cursor<'conn, 'query> = Cursor;
743        type Row<'conn, 'query> = self::row::PgRow;
744
745        fn get_cursor<'conn, 'query>(
746            conn: &'conn mut ConnectionAndTransactionManager,
747            result: PgResult,
748            source: Box<dyn QueryFragmentHelper<crate::result::Error> + 'query>,
749        ) -> QueryResult<Self::Cursor<'conn, 'query>> {
750            update_transaction_manager_status(
751                Cursor::new(result, &mut conn.raw_connection),
752                conn,
753                &|callback| source.instrumentation(callback),
754                true,
755            )
756        }
757    }
758
759    impl PgLoadingMode<PgRowByRowLoadingMode> for PgConnection {
760        const USE_ROW_BY_ROW_MODE: bool = true;
761        type Cursor<'conn, 'query> = RowByRowCursor<'conn, 'query>;
762        type Row<'conn, 'query> = self::row::PgRow;
763
764        fn get_cursor<'conn, 'query>(
765            raw_connection: &'conn mut ConnectionAndTransactionManager,
766            result: PgResult,
767            source: Box<dyn QueryFragmentHelper<crate::result::Error> + 'query>,
768        ) -> QueryResult<Self::Cursor<'conn, 'query>> {
769            Ok(RowByRowCursor::new(result, raw_connection, source))
770        }
771    }
772
773    // this trait exists to turn generic query types
774    // into trait objects to deduplicate the connection code
775    pub trait QueryFragmentHelper<E>:
776        crate::connection::statement_cache::QueryFragmentForCachedStatement<crate::pg::Pg>
777    {
778        fn query_id(&self) -> Option<core::any::TypeId>;
779
780        fn instrumentation(
781            &self,
782            callback: &mut dyn FnMut(&dyn crate::connection::instrumentation::DebugQuery),
783        );
784
785        fn collect_binds(
786            &self,
787            bind_collector: &mut RawBytesBindCollector<crate::pg::Pg>,
788            conn: &mut PgConnection,
789        ) -> QueryResult<()>;
790
791        fn write_copy_from(&self, _sink: &mut CopyFromSink<'_>) -> Result<(), E> {
792            Ok(())
793        }
794    }
795
796    // any type that implement `QueryFragment` and `QueryId` works in this location
797    impl<T> QueryFragmentHelper<diesel::result::Error> for T
798    where
799        T: QueryFragment<crate::pg::Pg> + QueryId,
800    {
801        fn query_id(&self) -> Option<core::any::TypeId> {
802            <T as QueryId>::query_id()
803        }
804
805        fn instrumentation(
806            &self,
807            callback: &mut dyn FnMut(&dyn crate::connection::instrumentation::DebugQuery),
808        ) {
809            callback(&crate::debug_query(self))
810        }
811
812        fn collect_binds(
813            &self,
814            bind_collector: &mut RawBytesBindCollector<crate::pg::Pg>,
815            conn: &mut PgConnection,
816        ) -> QueryResult<()> {
817            <Self as QueryFragment<diesel::pg::Pg>>::collect_binds(
818                self,
819                bind_collector,
820                conn,
821                &crate::pg::Pg,
822            )
823        }
824    }
825
826    // This wrapper exists as we need to have custom behavior for copy from
827    // statements (fn write_copy_from is relevant)
828    pub(super) struct CopyFromWrapper<S, T>(
829        pub(super) core::cell::RefCell<InternalCopyFromQuery<S, T>>,
830    );
831
832    impl<S, T> crate::connection::statement_cache::QueryFragmentForCachedStatement<Pg>
833        for CopyFromWrapper<S, T>
834    where
835        InternalCopyFromQuery<S, T>:
836            crate::connection::statement_cache::QueryFragmentForCachedStatement<Pg>,
837    {
838        fn construct_sql(&self, backend: &Pg) -> QueryResult<String> {
839            self.0.borrow().construct_sql(backend)
840        }
841
842        fn is_safe_to_cache_prepared(&self, backend: &Pg) -> QueryResult<bool> {
843            self.0.borrow().is_safe_to_cache_prepared(backend)
844        }
845    }
846
847    impl<S, T> QueryFragmentHelper<S::Error> for CopyFromWrapper<S, T>
848    where
849        S: CopyFromExpression<T>,
850        InternalCopyFromQuery<S, T>: QueryFragmentHelper<crate::result::Error>,
851        Self: crate::connection::statement_cache::QueryFragmentForCachedStatement<Pg>,
852    {
853        fn query_id(&self) -> Option<core::any::TypeId> {
854            self.0.borrow().query_id()
855        }
856
857        fn instrumentation(
858            &self,
859            callback: &mut dyn FnMut(&dyn crate::connection::instrumentation::DebugQuery),
860        ) {
861            callback(&crate::debug_query(&*self.0.borrow()))
862        }
863
864        fn collect_binds(
865            &self,
866            bind_collector: &mut RawBytesBindCollector<crate::pg::Pg>,
867            conn: &mut PgConnection,
868        ) -> QueryResult<()> {
869            <InternalCopyFromQuery<S, T> as QueryFragmentHelper<crate::result::Error>>::collect_binds(
870            &*self.0.borrow(),
871            bind_collector,
872            conn,
873        )
874        }
875
876        fn write_copy_from(&self, sink: &mut CopyFromSink<'_>) -> Result<(), S::Error> {
877            self.0.borrow_mut().target.callback(sink)
878        }
879    }
880}
881
882#[cfg(test)]
883// that's a false positive for `panic!`/`assert!` on rust 2018
884#[allow(clippy::uninlined_format_args)]
885mod tests {
886    extern crate dotenvy;
887
888    use super::*;
889    use crate::prelude::*;
890    use crate::result::Error::DatabaseError;
891    use std::num::NonZeroU32;
892
893    fn connection() -> PgConnection {
894        crate::test_helpers::pg_connection_no_transaction()
895    }
896
897    #[diesel_test_helper::test]
898    fn notifications_arrive() {
899        use crate::sql_query;
900
901        let conn = &mut connection();
902        sql_query("LISTEN test_notifications")
903            .execute(conn)
904            .unwrap();
905        sql_query("NOTIFY test_notifications, 'first'")
906            .execute(conn)
907            .unwrap();
908        sql_query("NOTIFY test_notifications, 'second'")
909            .execute(conn)
910            .unwrap();
911
912        let notifications = conn
913            .notifications_iter()
914            .map(Result::unwrap)
915            .collect::<Vec<_>>();
916
917        assert_eq!(2, notifications.len());
918        assert_eq!(notifications[0].channel, "test_notifications");
919        assert_eq!(notifications[1].channel, "test_notifications");
920        assert_eq!(notifications[0].payload, "first");
921        assert_eq!(notifications[1].payload, "second");
922
923        let next_notification = conn.notifications_iter().next();
924        assert!(
925            next_notification.is_none(),
926            "Got a next notification, while not expecting one: {next_notification:?}"
927        );
928
929        sql_query("NOTIFY test_notifications")
930            .execute(conn)
931            .unwrap();
932        assert_eq!(
933            conn.notifications_iter().next().unwrap().unwrap().payload,
934            ""
935        );
936    }
937
938    #[diesel_test_helper::test]
939    fn malformed_sql_query() {
940        let connection = &mut connection();
941        let query =
942            crate::sql_query("SELECT not_existent FROM also_not_there;").execute(connection);
943
944        if let Err(DatabaseError(_, string)) = query {
945            assert_eq!(Some(26), string.statement_position());
946        } else {
947            unreachable!();
948        }
949    }
950
951    table! {
952        users {
953            id -> Integer,
954            name -> Text,
955        }
956    }
957
958    #[diesel_test_helper::test]
959    fn transaction_manager_returns_an_error_when_attempting_to_commit_outside_of_a_transaction() {
960        use crate::PgConnection;
961        use crate::connection::{AnsiTransactionManager, TransactionManager};
962        use crate::result::Error;
963
964        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
965        assert_eq!(
966            None,
967            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
968                conn
969            ).transaction_depth().expect("Transaction depth")
970        );
971        let result = AnsiTransactionManager::commit_transaction(conn);
972        assert!(matches!(result, Err(Error::NotInTransaction)))
973    }
974
975    #[diesel_test_helper::test]
976    fn transaction_manager_returns_an_error_when_attempting_to_rollback_outside_of_a_transaction() {
977        use crate::PgConnection;
978        use crate::connection::{AnsiTransactionManager, TransactionManager};
979        use crate::result::Error;
980
981        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
982        assert_eq!(
983            None,
984            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
985                conn
986            ).transaction_depth().expect("Transaction depth")
987        );
988        let result = AnsiTransactionManager::rollback_transaction(conn);
989        assert!(matches!(result, Err(Error::NotInTransaction)))
990    }
991
992    #[diesel_test_helper::test]
993    fn postgres_transaction_is_rolled_back_upon_syntax_error() {
994        use std::num::NonZeroU32;
995
996        use crate::connection::{AnsiTransactionManager, TransactionManager};
997        use crate::pg::connection::raw::PgTransactionStatus;
998        use crate::*;
999        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1000        assert_eq!(
1001            None,
1002            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1003                conn
1004            ).transaction_depth().expect("Transaction depth")
1005        );
1006        let _result = conn.build_transaction().run(|conn| {
1007            assert_eq!(
1008                NonZeroU32::new(1),
1009                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1010                    conn
1011                ).transaction_depth().expect("Transaction depth")
1012            );
1013            // In Postgres, a syntax error breaks the transaction block
1014            let query_result = sql_query("SELECT_SYNTAX_ERROR 1").execute(conn);
1015            assert!(query_result.is_err());
1016            assert_eq!(
1017                PgTransactionStatus::InError,
1018                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1019            );
1020            query_result
1021        });
1022        assert_eq!(
1023            None,
1024            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1025                conn
1026            ).transaction_depth().expect("Transaction depth")
1027        );
1028        assert_eq!(
1029            PgTransactionStatus::Idle,
1030            conn.connection_and_transaction_manager
1031                .raw_connection
1032                .transaction_status()
1033        );
1034    }
1035
1036    #[diesel_test_helper::test]
1037    fn nested_postgres_transaction_is_rolled_back_upon_syntax_error() {
1038        use std::num::NonZeroU32;
1039
1040        use crate::connection::{AnsiTransactionManager, TransactionManager};
1041        use crate::pg::connection::raw::PgTransactionStatus;
1042        use crate::*;
1043        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1044        assert_eq!(
1045            None,
1046            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1047                conn
1048            ).transaction_depth().expect("Transaction depth")
1049        );
1050        let result = conn.build_transaction().run(|conn| {
1051            assert_eq!(
1052                NonZeroU32::new(1),
1053                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1054                    conn
1055            ).transaction_depth().expect("Transaction depth")
1056            );
1057            let result = conn.build_transaction().run(|conn| {
1058                assert_eq!(
1059                    NonZeroU32::new(2),
1060                    <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1061                        conn
1062            ).transaction_depth().expect("Transaction depth")
1063                );
1064                sql_query("SELECT_SYNTAX_ERROR 1").execute(conn)
1065            });
1066            assert!(result.is_err());
1067            assert_eq!(
1068                NonZeroU32::new(1),
1069                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1070                    conn
1071            ).transaction_depth().expect("Transaction depth")
1072            );
1073            let query_result = sql_query("SELECT 1").execute(conn);
1074            assert!(query_result.is_ok());
1075            assert_eq!(
1076                PgTransactionStatus::InTransaction,
1077                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1078            );
1079            query_result
1080        });
1081        assert!(result.is_ok());
1082        assert_eq!(
1083            PgTransactionStatus::Idle,
1084            conn.connection_and_transaction_manager
1085                .raw_connection
1086                .transaction_status()
1087        );
1088        assert_eq!(
1089            None,
1090            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1091                conn
1092            ).transaction_depth().expect("Transaction depth")
1093        );
1094    }
1095
1096    #[diesel_test_helper::test]
1097    // This function uses collect with an side effect (spawning threads)
1098    // so this is a false positive from clippy
1099    #[allow(clippy::needless_collect)]
1100    fn postgres_transaction_depth_is_tracked_properly_on_serialization_failure() {
1101        use crate::pg::connection::raw::PgTransactionStatus;
1102        use crate::result::DatabaseErrorKind::SerializationFailure;
1103        use crate::result::Error::DatabaseError;
1104        use crate::*;
1105        use std::sync::{Arc, Barrier};
1106        use std::thread;
1107
1108        table! {
1109            #[sql_name = "pg_transaction_depth_is_tracked_properly_on_commit_failure"]
1110            serialization_example {
1111                id -> Serial,
1112                class -> Integer,
1113            }
1114        }
1115
1116        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1117
1118        sql_query(
1119            "DROP TABLE IF EXISTS pg_transaction_depth_is_tracked_properly_on_commit_failure;",
1120        )
1121        .execute(conn)
1122        .unwrap();
1123        sql_query(
1124            r#"
1125            CREATE TABLE pg_transaction_depth_is_tracked_properly_on_commit_failure (
1126                id SERIAL PRIMARY KEY,
1127                class INTEGER NOT NULL
1128            )
1129        "#,
1130        )
1131        .execute(conn)
1132        .unwrap();
1133
1134        insert_into(serialization_example::table)
1135            .values(&vec![
1136                serialization_example::class.eq(1),
1137                serialization_example::class.eq(2),
1138            ])
1139            .execute(conn)
1140            .unwrap();
1141
1142        let before_barrier = Arc::new(Barrier::new(2));
1143        let after_barrier = Arc::new(Barrier::new(2));
1144        let threads = (1..3)
1145            .map(|i| {
1146                let before_barrier = before_barrier.clone();
1147                let after_barrier = after_barrier.clone();
1148                thread::spawn(move || {
1149                    use crate::connection::AnsiTransactionManager;
1150                    use crate::connection::TransactionManager;
1151                    let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1152                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1153
1154                    let result = conn.build_transaction().serializable().run(|conn| {
1155                        assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1156
1157                        let _ = serialization_example::table
1158                            .filter(serialization_example::class.eq(i))
1159                            .count()
1160                            .execute(conn)?;
1161
1162                        let other_i = if i == 1 { 2 } else { 1 };
1163                        let q = insert_into(serialization_example::table)
1164                            .values(serialization_example::class.eq(other_i));
1165                        before_barrier.wait();
1166
1167                        let r = q.execute(conn);
1168                        after_barrier.wait();
1169                        r
1170                    });
1171                    assert_eq!(
1172                        PgTransactionStatus::Idle,
1173                        conn.connection_and_transaction_manager.raw_connection.transaction_status()
1174                    );
1175
1176                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1177                    result
1178                })
1179            })
1180            .collect::<Vec<_>>();
1181
1182        let mut results = threads
1183            .into_iter()
1184            .map(|t| t.join().unwrap())
1185            .collect::<Vec<_>>();
1186
1187        results.sort_by_key(|r| r.is_err());
1188
1189        assert!(results[0].is_ok(), "Got {:?} instead", results);
1190        assert!(
1191            matches!(&results[1], Err(DatabaseError(SerializationFailure, _))),
1192            "Got {:?} instead",
1193            results
1194        );
1195        assert_eq!(
1196            PgTransactionStatus::Idle,
1197            conn.connection_and_transaction_manager
1198                .raw_connection
1199                .transaction_status()
1200        );
1201    }
1202
1203    #[diesel_test_helper::test]
1204    // This function uses collect with an side effect (spawning threads)
1205    // so this is a false positive from clippy
1206    #[allow(clippy::needless_collect)]
1207    fn postgres_transaction_depth_is_tracked_properly_on_nested_serialization_failure() {
1208        use crate::pg::connection::raw::PgTransactionStatus;
1209        use crate::result::DatabaseErrorKind::SerializationFailure;
1210        use crate::result::Error::DatabaseError;
1211        use crate::*;
1212        use std::sync::{Arc, Barrier};
1213        use std::thread;
1214
1215        table! {
1216            #[sql_name = "pg_nested_transaction_depth_is_tracked_properly_on_commit_failure"]
1217            serialization_example {
1218                id -> Serial,
1219                class -> Integer,
1220            }
1221        }
1222
1223        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1224
1225        sql_query(
1226            "DROP TABLE IF EXISTS pg_nested_transaction_depth_is_tracked_properly_on_commit_failure;",
1227        )
1228        .execute(conn)
1229        .unwrap();
1230        sql_query(
1231            r#"
1232            CREATE TABLE pg_nested_transaction_depth_is_tracked_properly_on_commit_failure (
1233                id SERIAL PRIMARY KEY,
1234                class INTEGER NOT NULL
1235            )
1236        "#,
1237        )
1238        .execute(conn)
1239        .unwrap();
1240
1241        insert_into(serialization_example::table)
1242            .values(&vec![
1243                serialization_example::class.eq(1),
1244                serialization_example::class.eq(2),
1245            ])
1246            .execute(conn)
1247            .unwrap();
1248
1249        let before_barrier = Arc::new(Barrier::new(2));
1250        let after_barrier = Arc::new(Barrier::new(2));
1251        let threads = (1..3)
1252            .map(|i| {
1253                let before_barrier = before_barrier.clone();
1254                let after_barrier = after_barrier.clone();
1255                thread::spawn(move || {
1256                    use crate::connection::AnsiTransactionManager;
1257                    use crate::connection::TransactionManager;
1258                    let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1259                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1260
1261                    let result = conn.build_transaction().serializable().run(|conn| {
1262                        assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1263                        let r = conn.transaction(|conn| {
1264                            assert_eq!(NonZeroU32::new(2), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1265
1266                            let _ = serialization_example::table
1267                                .filter(serialization_example::class.eq(i))
1268                                .count()
1269                                .execute(conn)?;
1270
1271                            let other_i = if i == 1 { 2 } else { 1 };
1272                            let q = insert_into(serialization_example::table)
1273                                .values(serialization_example::class.eq(other_i));
1274                            before_barrier.wait();
1275
1276                            let r = q.execute(conn);
1277                            after_barrier.wait();
1278                            r
1279                        });
1280                        assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1281                        assert_eq!(
1282                            PgTransactionStatus::InTransaction,
1283                            conn.connection_and_transaction_manager.raw_connection.transaction_status()
1284                        );
1285                        r
1286                    });
1287                    assert_eq!(
1288                        PgTransactionStatus::Idle,
1289                        conn.connection_and_transaction_manager.raw_connection.transaction_status()
1290                    );
1291
1292                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1293                    result
1294                })
1295            })
1296            .collect::<Vec<_>>();
1297
1298        let mut results = threads
1299            .into_iter()
1300            .map(|t| t.join().unwrap())
1301            .collect::<Vec<_>>();
1302
1303        results.sort_by_key(|r| r.is_err());
1304
1305        assert!(results[0].is_ok(), "Got {:?} instead", results);
1306        assert!(
1307            matches!(&results[1], Err(DatabaseError(SerializationFailure, _))),
1308            "Got {:?} instead",
1309            results
1310        );
1311        assert_eq!(
1312            PgTransactionStatus::Idle,
1313            conn.connection_and_transaction_manager
1314                .raw_connection
1315                .transaction_status()
1316        );
1317    }
1318
1319    #[diesel_test_helper::test]
1320    fn postgres_transaction_is_rolled_back_upon_deferred_constraint_failure() {
1321        use crate::connection::{AnsiTransactionManager, TransactionManager};
1322        use crate::pg::connection::raw::PgTransactionStatus;
1323        use crate::result::Error;
1324        use crate::*;
1325
1326        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1327        assert_eq!(
1328            None,
1329            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1330                conn
1331            ).transaction_depth().expect("Transaction depth")
1332        );
1333        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1334            assert_eq!(
1335                NonZeroU32::new(1),
1336                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1337                    conn
1338            ).transaction_depth().expect("Transaction depth")
1339            );
1340            sql_query("DROP TABLE IF EXISTS deferred_constraint_commit").execute(conn)?;
1341            sql_query("CREATE TABLE deferred_constraint_commit(id INT UNIQUE INITIALLY DEFERRED)")
1342                .execute(conn)?;
1343            sql_query("INSERT INTO deferred_constraint_commit VALUES(1)").execute(conn)?;
1344            let result =
1345                sql_query("INSERT INTO deferred_constraint_commit VALUES(1)").execute(conn);
1346            assert!(result.is_ok());
1347            assert_eq!(
1348                PgTransactionStatus::InTransaction,
1349                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1350            );
1351            Ok(())
1352        });
1353        assert_eq!(
1354            None,
1355            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1356                conn
1357            ).transaction_depth().expect("Transaction depth")
1358        );
1359        assert_eq!(
1360            PgTransactionStatus::Idle,
1361            conn.connection_and_transaction_manager
1362                .raw_connection
1363                .transaction_status()
1364        );
1365        assert!(result.is_err());
1366    }
1367
1368    #[diesel_test_helper::test]
1369    fn postgres_transaction_is_rolled_back_upon_deferred_trigger_failure() {
1370        use crate::connection::{AnsiTransactionManager, TransactionManager};
1371        use crate::pg::connection::raw::PgTransactionStatus;
1372        use crate::result::Error;
1373        use crate::*;
1374
1375        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1376        assert_eq!(
1377            None,
1378            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1379                conn
1380            ).transaction_depth().expect("Transaction depth")
1381        );
1382        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1383            assert_eq!(
1384                NonZeroU32::new(1),
1385                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1386                    conn
1387            ).transaction_depth().expect("Transaction depth")
1388            );
1389            sql_query("DROP TABLE IF EXISTS deferred_trigger_commit").execute(conn)?;
1390            sql_query("CREATE TABLE deferred_trigger_commit(id INT UNIQUE INITIALLY DEFERRED)")
1391                .execute(conn)?;
1392            sql_query(
1393                r#"
1394                    CREATE OR REPLACE FUNCTION transaction_depth_blow_up()
1395                        RETURNS trigger
1396                        LANGUAGE plpgsql
1397                        AS $$
1398                    DECLARE
1399                    BEGIN
1400                        IF NEW.value = 42 THEN
1401                            RAISE EXCEPTION 'Transaction kaboom';
1402                        END IF;
1403                    RETURN NEW;
1404
1405                    END;$$;
1406                "#,
1407            )
1408            .execute(conn)?;
1409
1410            sql_query(
1411                r#"
1412                    CREATE CONSTRAINT TRIGGER transaction_depth_trigger
1413                        AFTER INSERT ON "deferred_trigger_commit"
1414                        DEFERRABLE INITIALLY DEFERRED
1415                        FOR EACH ROW
1416                        EXECUTE PROCEDURE transaction_depth_blow_up()
1417            "#,
1418            )
1419            .execute(conn)?;
1420            let result = sql_query("INSERT INTO deferred_trigger_commit VALUES(42)").execute(conn);
1421            assert!(result.is_ok());
1422            assert_eq!(
1423                PgTransactionStatus::InTransaction,
1424                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1425            );
1426            Ok(())
1427        });
1428        assert_eq!(
1429            None,
1430            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1431                conn
1432            ).transaction_depth().expect("Transaction depth")
1433        );
1434        assert_eq!(
1435            PgTransactionStatus::Idle,
1436            conn.connection_and_transaction_manager
1437                .raw_connection
1438                .transaction_status()
1439        );
1440        assert!(result.is_err());
1441    }
1442
1443    #[diesel_test_helper::test]
1444    fn nested_postgres_transaction_is_rolled_back_upon_deferred_trigger_failure() {
1445        use crate::connection::{AnsiTransactionManager, TransactionManager};
1446        use crate::pg::connection::raw::PgTransactionStatus;
1447        use crate::result::Error;
1448        use crate::*;
1449
1450        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1451        assert_eq!(
1452            None,
1453            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1454                conn
1455            ).transaction_depth().expect("Transaction depth")
1456        );
1457        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1458            assert_eq!(
1459                NonZeroU32::new(1),
1460                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1461                    conn
1462            ).transaction_depth().expect("Transaction depth")
1463            );
1464            sql_query("DROP TABLE IF EXISTS deferred_trigger_nested_commit").execute(conn)?;
1465            sql_query(
1466                "CREATE TABLE deferred_trigger_nested_commit(id INT UNIQUE INITIALLY DEFERRED)",
1467            )
1468            .execute(conn)?;
1469            sql_query(
1470                r#"
1471                    CREATE OR REPLACE FUNCTION transaction_depth_blow_up()
1472                        RETURNS trigger
1473                        LANGUAGE plpgsql
1474                        AS $$
1475                    DECLARE
1476                    BEGIN
1477                        IF NEW.value = 42 THEN
1478                            RAISE EXCEPTION 'Transaction kaboom';
1479                        END IF;
1480                    RETURN NEW;
1481
1482                    END;$$;
1483                "#,
1484            )
1485            .execute(conn)?;
1486
1487            sql_query(
1488                r#"
1489                    CREATE CONSTRAINT TRIGGER transaction_depth_trigger
1490                        AFTER INSERT ON "deferred_trigger_nested_commit"
1491                        DEFERRABLE INITIALLY DEFERRED
1492                        FOR EACH ROW
1493                        EXECUTE PROCEDURE transaction_depth_blow_up()
1494            "#,
1495            )
1496            .execute(conn)?;
1497            let inner_result: Result<_, Error> = conn.build_transaction().run(|conn| {
1498                let result = sql_query("INSERT INTO deferred_trigger_nested_commit VALUES(42)")
1499                    .execute(conn);
1500                assert!(result.is_ok());
1501                Ok(())
1502            });
1503            assert!(inner_result.is_err());
1504            assert_eq!(
1505                PgTransactionStatus::InTransaction,
1506                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1507            );
1508            Ok(())
1509        });
1510        assert_eq!(
1511            None,
1512            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1513                conn
1514            ).transaction_depth().expect("Transaction depth")
1515        );
1516        assert_eq!(
1517            PgTransactionStatus::Idle,
1518            conn.connection_and_transaction_manager
1519                .raw_connection
1520                .transaction_status()
1521        );
1522        assert!(result.is_ok(), "Expected success, got {:?}", result);
1523    }
1524
1525    #[diesel_test_helper::test]
1526    fn nested_postgres_transaction_is_rolled_back_upon_deferred_constraint_failure() {
1527        use crate::connection::{AnsiTransactionManager, TransactionManager};
1528        use crate::pg::connection::raw::PgTransactionStatus;
1529        use crate::result::Error;
1530        use crate::*;
1531
1532        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1533        assert_eq!(
1534            None,
1535            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1536                conn
1537            ).transaction_depth().expect("Transaction depth")
1538        );
1539        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1540            assert_eq!(
1541                NonZeroU32::new(1),
1542                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1543                    conn
1544            ).transaction_depth().expect("Transaction depth")
1545            );
1546            sql_query("DROP TABLE IF EXISTS deferred_constraint_nested_commit").execute(conn)?;
1547            sql_query("CREATE TABLE deferred_constraint_nested_commit(id INT UNIQUE INITIALLY DEFERRED)").execute(conn)?;
1548            let inner_result: Result<_, Error> = conn.build_transaction().run(|conn| {
1549                assert_eq!(
1550                    NonZeroU32::new(2),
1551                    <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1552                        conn
1553                    ).transaction_depth().expect("Transaction depth")
1554                );
1555                sql_query("INSERT INTO deferred_constraint_nested_commit VALUES(1)").execute(conn)?;
1556                let result = sql_query("INSERT INTO deferred_constraint_nested_commit VALUES(1)").execute(conn);
1557                assert!(result.is_ok());
1558                Ok(())
1559            });
1560            assert!(inner_result.is_err());
1561            assert_eq!(
1562                PgTransactionStatus::InTransaction,
1563                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1564            );
1565            assert_eq!(
1566                NonZeroU32::new(1),
1567                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1568                    conn
1569            ).transaction_depth().expect("Transaction depth")
1570            );
1571            sql_query("INSERT INTO deferred_constraint_nested_commit VALUES(1)").execute(conn)
1572        });
1573        assert_eq!(
1574            None,
1575            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1576                conn
1577            ).transaction_depth().expect("Transaction depth")
1578        );
1579        assert_eq!(
1580            PgTransactionStatus::Idle,
1581            conn.connection_and_transaction_manager
1582                .raw_connection
1583                .transaction_status()
1584        );
1585        assert!(result.is_ok());
1586    }
1587
1588    #[crate::declare_sql_function]
1589    extern "SQL" {
1590        fn current_setting(setting_name: crate::sql_types::Text) -> crate::sql_types::Text;
1591        fn pg_backend_pid() -> crate::sql_types::Integer;
1592        fn pg_terminate_backend(
1593            pid: crate::sql_types::Integer,
1594            timeout: crate::sql_types::BigInt,
1595        ) -> crate::sql_types::Bool;
1596    }
1597
1598    #[diesel_test_helper::test]
1599    fn decode_server_version_reads_both_numbering_schemes() {
1600        assert_eq!(
1601            decode_server_version(180004),
1602            Some(DatabaseVersion::new(18, 4, 0))
1603        );
1604        assert_eq!(
1605            decode_server_version(100001),
1606            Some(DatabaseVersion::new(10, 1, 0))
1607        );
1608        assert_eq!(
1609            decode_server_version(90620),
1610            Some(DatabaseVersion::new(9, 6, 20))
1611        );
1612        assert_eq!(decode_server_version(0), None);
1613    }
1614
1615    #[diesel_test_helper::test]
1616    fn version_matches_the_server_reported_version() {
1617        let conn = &mut connection();
1618        let version = conn.version().unwrap();
1619        let reported = crate::select(current_setting("server_version"))
1620            .get_result::<String>(conn)
1621            .unwrap();
1622        let numeric = reported
1623            .split(|c: char| !c.is_ascii_digit() && c != '.')
1624            .next()
1625            .unwrap();
1626        assert_eq!(numeric, format!("{}.{}", version.major(), version.minor()));
1627        assert_eq!(version.patch(), 0);
1628    }
1629
1630    #[diesel_test_helper::test]
1631    fn version_fails_once_the_connection_is_closed() {
1632        let conn = &mut connection();
1633        let pid = crate::select(pg_backend_pid())
1634            .get_result::<i32>(conn)
1635            .unwrap();
1636        assert!(
1637            crate::select(pg_terminate_backend(pid, 5000_i64))
1638                .get_result::<bool>(&mut connection())
1639                .unwrap()
1640        );
1641        assert!(
1642            crate::select(1.into_sql::<crate::sql_types::Integer>())
1643                .get_result::<i32>(conn)
1644                .is_err()
1645        );
1646
1647        assert!(matches!(
1648            conn.version(),
1649            Err(DatabaseError(DatabaseErrorKind::ClosedConnection, _))
1650        ));
1651    }
1652}