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]
    #[rustc_trivial_field_reads]
    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]
    #[rustc_trivial_field_reads]
    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        fn parameter_count(&self, backend: &Pg) -> QueryResult<usize> {
847            self.0.borrow().parameter_count(backend)
848        }
849    }
850
851    impl<S, T> QueryFragmentHelper<S::Error> for CopyFromWrapper<S, T>
852    where
853        S: CopyFromExpression<T>,
854        InternalCopyFromQuery<S, T>: QueryFragmentHelper<crate::result::Error>,
855        Self: crate::connection::statement_cache::QueryFragmentForCachedStatement<Pg>,
856    {
857        fn query_id(&self) -> Option<core::any::TypeId> {
858            self.0.borrow().query_id()
859        }
860
861        fn instrumentation(
862            &self,
863            callback: &mut dyn FnMut(&dyn crate::connection::instrumentation::DebugQuery),
864        ) {
865            callback(&crate::debug_query(&*self.0.borrow()))
866        }
867
868        fn collect_binds(
869            &self,
870            bind_collector: &mut RawBytesBindCollector<crate::pg::Pg>,
871            conn: &mut PgConnection,
872        ) -> QueryResult<()> {
873            <InternalCopyFromQuery<S, T> as QueryFragmentHelper<crate::result::Error>>::collect_binds(
874            &*self.0.borrow(),
875            bind_collector,
876            conn,
877        )
878        }
879
880        fn write_copy_from(&self, sink: &mut CopyFromSink<'_>) -> Result<(), S::Error> {
881            self.0.borrow_mut().target.callback(sink)
882        }
883    }
884}
885
886#[cfg(test)]
887// that's a false positive for `panic!`/`assert!` on rust 2018
888#[allow(clippy::uninlined_format_args)]
889mod tests {
890    extern crate dotenvy;
891
892    use super::*;
893    use crate::prelude::*;
894    use crate::result::Error::DatabaseError;
895    use std::num::NonZeroU32;
896
897    fn connection() -> PgConnection {
898        crate::test_helpers::pg_connection_no_transaction()
899    }
900
901    #[diesel_test_helper::test]
902    fn notifications_arrive() {
903        use crate::sql_query;
904
905        let conn = &mut connection();
906        sql_query("LISTEN test_notifications")
907            .execute(conn)
908            .unwrap();
909        sql_query("NOTIFY test_notifications, 'first'")
910            .execute(conn)
911            .unwrap();
912        sql_query("NOTIFY test_notifications, 'second'")
913            .execute(conn)
914            .unwrap();
915
916        let notifications = conn
917            .notifications_iter()
918            .map(Result::unwrap)
919            .collect::<Vec<_>>();
920
921        assert_eq!(2, notifications.len());
922        assert_eq!(notifications[0].channel, "test_notifications");
923        assert_eq!(notifications[1].channel, "test_notifications");
924        assert_eq!(notifications[0].payload, "first");
925        assert_eq!(notifications[1].payload, "second");
926
927        let next_notification = conn.notifications_iter().next();
928        assert!(
929            next_notification.is_none(),
930            "Got a next notification, while not expecting one: {next_notification:?}"
931        );
932
933        sql_query("NOTIFY test_notifications")
934            .execute(conn)
935            .unwrap();
936        assert_eq!(
937            conn.notifications_iter().next().unwrap().unwrap().payload,
938            ""
939        );
940    }
941
942    #[diesel_test_helper::test]
943    fn malformed_sql_query() {
944        let connection = &mut connection();
945        let query =
946            crate::sql_query("SELECT not_existent FROM also_not_there;").execute(connection);
947
948        if let Err(DatabaseError(_, string)) = query {
949            assert_eq!(Some(26), string.statement_position());
950        } else {
951            unreachable!();
952        }
953    }
954
955    table! {
956        users {
957            id -> Integer,
958            name -> Text,
959        }
960    }
961
962    #[diesel_test_helper::test]
963    fn transaction_manager_returns_an_error_when_attempting_to_commit_outside_of_a_transaction() {
964        use crate::PgConnection;
965        use crate::connection::{AnsiTransactionManager, TransactionManager};
966        use crate::result::Error;
967
968        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
969        assert_eq!(
970            None,
971            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
972                conn
973            ).transaction_depth().expect("Transaction depth")
974        );
975        let result = AnsiTransactionManager::commit_transaction(conn);
976        assert!(matches!(result, Err(Error::NotInTransaction)))
977    }
978
979    #[diesel_test_helper::test]
980    fn transaction_manager_returns_an_error_when_attempting_to_rollback_outside_of_a_transaction() {
981        use crate::PgConnection;
982        use crate::connection::{AnsiTransactionManager, TransactionManager};
983        use crate::result::Error;
984
985        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
986        assert_eq!(
987            None,
988            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
989                conn
990            ).transaction_depth().expect("Transaction depth")
991        );
992        let result = AnsiTransactionManager::rollback_transaction(conn);
993        assert!(matches!(result, Err(Error::NotInTransaction)))
994    }
995
996    #[diesel_test_helper::test]
997    fn postgres_transaction_is_rolled_back_upon_syntax_error() {
998        use std::num::NonZeroU32;
999
1000        use crate::connection::{AnsiTransactionManager, TransactionManager};
1001        use crate::pg::connection::raw::PgTransactionStatus;
1002        use crate::*;
1003        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1004        assert_eq!(
1005            None,
1006            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1007                conn
1008            ).transaction_depth().expect("Transaction depth")
1009        );
1010        let _result = conn.build_transaction().run(|conn| {
1011            assert_eq!(
1012                NonZeroU32::new(1),
1013                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1014                    conn
1015                ).transaction_depth().expect("Transaction depth")
1016            );
1017            // In Postgres, a syntax error breaks the transaction block
1018            let query_result = sql_query("SELECT_SYNTAX_ERROR 1").execute(conn);
1019            assert!(query_result.is_err());
1020            assert_eq!(
1021                PgTransactionStatus::InError,
1022                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1023            );
1024            query_result
1025        });
1026        assert_eq!(
1027            None,
1028            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1029                conn
1030            ).transaction_depth().expect("Transaction depth")
1031        );
1032        assert_eq!(
1033            PgTransactionStatus::Idle,
1034            conn.connection_and_transaction_manager
1035                .raw_connection
1036                .transaction_status()
1037        );
1038    }
1039
1040    #[diesel_test_helper::test]
1041    fn nested_postgres_transaction_is_rolled_back_upon_syntax_error() {
1042        use std::num::NonZeroU32;
1043
1044        use crate::connection::{AnsiTransactionManager, TransactionManager};
1045        use crate::pg::connection::raw::PgTransactionStatus;
1046        use crate::*;
1047        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1048        assert_eq!(
1049            None,
1050            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1051                conn
1052            ).transaction_depth().expect("Transaction depth")
1053        );
1054        let result = conn.build_transaction().run(|conn| {
1055            assert_eq!(
1056                NonZeroU32::new(1),
1057                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1058                    conn
1059            ).transaction_depth().expect("Transaction depth")
1060            );
1061            let result = conn.build_transaction().run(|conn| {
1062                assert_eq!(
1063                    NonZeroU32::new(2),
1064                    <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1065                        conn
1066            ).transaction_depth().expect("Transaction depth")
1067                );
1068                sql_query("SELECT_SYNTAX_ERROR 1").execute(conn)
1069            });
1070            assert!(result.is_err());
1071            assert_eq!(
1072                NonZeroU32::new(1),
1073                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1074                    conn
1075            ).transaction_depth().expect("Transaction depth")
1076            );
1077            let query_result = sql_query("SELECT 1").execute(conn);
1078            assert!(query_result.is_ok());
1079            assert_eq!(
1080                PgTransactionStatus::InTransaction,
1081                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1082            );
1083            query_result
1084        });
1085        assert!(result.is_ok());
1086        assert_eq!(
1087            PgTransactionStatus::Idle,
1088            conn.connection_and_transaction_manager
1089                .raw_connection
1090                .transaction_status()
1091        );
1092        assert_eq!(
1093            None,
1094            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1095                conn
1096            ).transaction_depth().expect("Transaction depth")
1097        );
1098    }
1099
1100    #[diesel_test_helper::test]
1101    // This function uses collect with an side effect (spawning threads)
1102    // so this is a false positive from clippy
1103    #[allow(clippy::needless_collect)]
1104    fn postgres_transaction_depth_is_tracked_properly_on_serialization_failure() {
1105        use crate::pg::connection::raw::PgTransactionStatus;
1106        use crate::result::DatabaseErrorKind::SerializationFailure;
1107        use crate::result::Error::DatabaseError;
1108        use crate::*;
1109        use std::sync::{Arc, Barrier};
1110        use std::thread;
1111
1112        table! {
1113            #[sql_name = "pg_transaction_depth_is_tracked_properly_on_commit_failure"]
1114            serialization_example {
1115                id -> Serial,
1116                class -> Integer,
1117            }
1118        }
1119
1120        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1121
1122        sql_query(
1123            "DROP TABLE IF EXISTS pg_transaction_depth_is_tracked_properly_on_commit_failure;",
1124        )
1125        .execute(conn)
1126        .unwrap();
1127        sql_query(
1128            r#"
1129            CREATE TABLE pg_transaction_depth_is_tracked_properly_on_commit_failure (
1130                id SERIAL PRIMARY KEY,
1131                class INTEGER NOT NULL
1132            )
1133        "#,
1134        )
1135        .execute(conn)
1136        .unwrap();
1137
1138        insert_into(serialization_example::table)
1139            .values(&vec![
1140                serialization_example::class.eq(1),
1141                serialization_example::class.eq(2),
1142            ])
1143            .execute(conn)
1144            .unwrap();
1145
1146        let before_barrier = Arc::new(Barrier::new(2));
1147        let after_barrier = Arc::new(Barrier::new(2));
1148        let threads = (1..3)
1149            .map(|i| {
1150                let before_barrier = before_barrier.clone();
1151                let after_barrier = after_barrier.clone();
1152                thread::spawn(move || {
1153                    use crate::connection::AnsiTransactionManager;
1154                    use crate::connection::TransactionManager;
1155                    let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1156                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1157
1158                    let result = conn.build_transaction().serializable().run(|conn| {
1159                        assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1160
1161                        let _ = serialization_example::table
1162                            .filter(serialization_example::class.eq(i))
1163                            .count()
1164                            .execute(conn)?;
1165
1166                        let other_i = if i == 1 { 2 } else { 1 };
1167                        let q = insert_into(serialization_example::table)
1168                            .values(serialization_example::class.eq(other_i));
1169                        before_barrier.wait();
1170
1171                        let r = q.execute(conn);
1172                        after_barrier.wait();
1173                        r
1174                    });
1175                    assert_eq!(
1176                        PgTransactionStatus::Idle,
1177                        conn.connection_and_transaction_manager.raw_connection.transaction_status()
1178                    );
1179
1180                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1181                    result
1182                })
1183            })
1184            .collect::<Vec<_>>();
1185
1186        let mut results = threads
1187            .into_iter()
1188            .map(|t| t.join().unwrap())
1189            .collect::<Vec<_>>();
1190
1191        results.sort_by_key(|r| r.is_err());
1192
1193        assert!(results[0].is_ok(), "Got {:?} instead", results);
1194        assert!(
1195            matches!(&results[1], Err(DatabaseError(SerializationFailure, _))),
1196            "Got {:?} instead",
1197            results
1198        );
1199        assert_eq!(
1200            PgTransactionStatus::Idle,
1201            conn.connection_and_transaction_manager
1202                .raw_connection
1203                .transaction_status()
1204        );
1205    }
1206
1207    #[diesel_test_helper::test]
1208    // This function uses collect with an side effect (spawning threads)
1209    // so this is a false positive from clippy
1210    #[allow(clippy::needless_collect)]
1211    fn postgres_transaction_depth_is_tracked_properly_on_nested_serialization_failure() {
1212        use crate::pg::connection::raw::PgTransactionStatus;
1213        use crate::result::DatabaseErrorKind::SerializationFailure;
1214        use crate::result::Error::DatabaseError;
1215        use crate::*;
1216        use std::sync::{Arc, Barrier};
1217        use std::thread;
1218
1219        table! {
1220            #[sql_name = "pg_nested_transaction_depth_is_tracked_properly_on_commit_failure"]
1221            serialization_example {
1222                id -> Serial,
1223                class -> Integer,
1224            }
1225        }
1226
1227        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1228
1229        sql_query(
1230            "DROP TABLE IF EXISTS pg_nested_transaction_depth_is_tracked_properly_on_commit_failure;",
1231        )
1232        .execute(conn)
1233        .unwrap();
1234        sql_query(
1235            r#"
1236            CREATE TABLE pg_nested_transaction_depth_is_tracked_properly_on_commit_failure (
1237                id SERIAL PRIMARY KEY,
1238                class INTEGER NOT NULL
1239            )
1240        "#,
1241        )
1242        .execute(conn)
1243        .unwrap();
1244
1245        insert_into(serialization_example::table)
1246            .values(&vec![
1247                serialization_example::class.eq(1),
1248                serialization_example::class.eq(2),
1249            ])
1250            .execute(conn)
1251            .unwrap();
1252
1253        let before_barrier = Arc::new(Barrier::new(2));
1254        let after_barrier = Arc::new(Barrier::new(2));
1255        let threads = (1..3)
1256            .map(|i| {
1257                let before_barrier = before_barrier.clone();
1258                let after_barrier = after_barrier.clone();
1259                thread::spawn(move || {
1260                    use crate::connection::AnsiTransactionManager;
1261                    use crate::connection::TransactionManager;
1262                    let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1263                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1264
1265                    let result = conn.build_transaction().serializable().run(|conn| {
1266                        assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1267                        let r = conn.transaction(|conn| {
1268                            assert_eq!(NonZeroU32::new(2), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1269
1270                            let _ = serialization_example::table
1271                                .filter(serialization_example::class.eq(i))
1272                                .count()
1273                                .execute(conn)?;
1274
1275                            let other_i = if i == 1 { 2 } else { 1 };
1276                            let q = insert_into(serialization_example::table)
1277                                .values(serialization_example::class.eq(other_i));
1278                            before_barrier.wait();
1279
1280                            let r = q.execute(conn);
1281                            after_barrier.wait();
1282                            r
1283                        });
1284                        assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1285                        assert_eq!(
1286                            PgTransactionStatus::InTransaction,
1287                            conn.connection_and_transaction_manager.raw_connection.transaction_status()
1288                        );
1289                        r
1290                    });
1291                    assert_eq!(
1292                        PgTransactionStatus::Idle,
1293                        conn.connection_and_transaction_manager.raw_connection.transaction_status()
1294                    );
1295
1296                    assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
1297                    result
1298                })
1299            })
1300            .collect::<Vec<_>>();
1301
1302        let mut results = threads
1303            .into_iter()
1304            .map(|t| t.join().unwrap())
1305            .collect::<Vec<_>>();
1306
1307        results.sort_by_key(|r| r.is_err());
1308
1309        assert!(results[0].is_ok(), "Got {:?} instead", results);
1310        assert!(
1311            matches!(&results[1], Err(DatabaseError(SerializationFailure, _))),
1312            "Got {:?} instead",
1313            results
1314        );
1315        assert_eq!(
1316            PgTransactionStatus::Idle,
1317            conn.connection_and_transaction_manager
1318                .raw_connection
1319                .transaction_status()
1320        );
1321    }
1322
1323    #[diesel_test_helper::test]
1324    fn postgres_transaction_is_rolled_back_upon_deferred_constraint_failure() {
1325        use crate::connection::{AnsiTransactionManager, TransactionManager};
1326        use crate::pg::connection::raw::PgTransactionStatus;
1327        use crate::result::Error;
1328        use crate::*;
1329
1330        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1331        assert_eq!(
1332            None,
1333            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1334                conn
1335            ).transaction_depth().expect("Transaction depth")
1336        );
1337        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1338            assert_eq!(
1339                NonZeroU32::new(1),
1340                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1341                    conn
1342            ).transaction_depth().expect("Transaction depth")
1343            );
1344            sql_query("DROP TABLE IF EXISTS deferred_constraint_commit").execute(conn)?;
1345            sql_query("CREATE TABLE deferred_constraint_commit(id INT UNIQUE INITIALLY DEFERRED)")
1346                .execute(conn)?;
1347            sql_query("INSERT INTO deferred_constraint_commit VALUES(1)").execute(conn)?;
1348            let result =
1349                sql_query("INSERT INTO deferred_constraint_commit VALUES(1)").execute(conn);
1350            assert!(result.is_ok());
1351            assert_eq!(
1352                PgTransactionStatus::InTransaction,
1353                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1354            );
1355            Ok(())
1356        });
1357        assert_eq!(
1358            None,
1359            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1360                conn
1361            ).transaction_depth().expect("Transaction depth")
1362        );
1363        assert_eq!(
1364            PgTransactionStatus::Idle,
1365            conn.connection_and_transaction_manager
1366                .raw_connection
1367                .transaction_status()
1368        );
1369        assert!(result.is_err());
1370    }
1371
1372    #[diesel_test_helper::test]
1373    fn postgres_transaction_is_rolled_back_upon_deferred_trigger_failure() {
1374        use crate::connection::{AnsiTransactionManager, TransactionManager};
1375        use crate::pg::connection::raw::PgTransactionStatus;
1376        use crate::result::Error;
1377        use crate::*;
1378
1379        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1380        assert_eq!(
1381            None,
1382            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1383                conn
1384            ).transaction_depth().expect("Transaction depth")
1385        );
1386        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1387            assert_eq!(
1388                NonZeroU32::new(1),
1389                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1390                    conn
1391            ).transaction_depth().expect("Transaction depth")
1392            );
1393            sql_query("DROP TABLE IF EXISTS deferred_trigger_commit").execute(conn)?;
1394            sql_query("CREATE TABLE deferred_trigger_commit(id INT UNIQUE INITIALLY DEFERRED)")
1395                .execute(conn)?;
1396            sql_query(
1397                r#"
1398                    CREATE OR REPLACE FUNCTION transaction_depth_blow_up()
1399                        RETURNS trigger
1400                        LANGUAGE plpgsql
1401                        AS $$
1402                    DECLARE
1403                    BEGIN
1404                        IF NEW.value = 42 THEN
1405                            RAISE EXCEPTION 'Transaction kaboom';
1406                        END IF;
1407                    RETURN NEW;
1408
1409                    END;$$;
1410                "#,
1411            )
1412            .execute(conn)?;
1413
1414            sql_query(
1415                r#"
1416                    CREATE CONSTRAINT TRIGGER transaction_depth_trigger
1417                        AFTER INSERT ON "deferred_trigger_commit"
1418                        DEFERRABLE INITIALLY DEFERRED
1419                        FOR EACH ROW
1420                        EXECUTE PROCEDURE transaction_depth_blow_up()
1421            "#,
1422            )
1423            .execute(conn)?;
1424            let result = sql_query("INSERT INTO deferred_trigger_commit VALUES(42)").execute(conn);
1425            assert!(result.is_ok());
1426            assert_eq!(
1427                PgTransactionStatus::InTransaction,
1428                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1429            );
1430            Ok(())
1431        });
1432        assert_eq!(
1433            None,
1434            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1435                conn
1436            ).transaction_depth().expect("Transaction depth")
1437        );
1438        assert_eq!(
1439            PgTransactionStatus::Idle,
1440            conn.connection_and_transaction_manager
1441                .raw_connection
1442                .transaction_status()
1443        );
1444        assert!(result.is_err());
1445    }
1446
1447    #[diesel_test_helper::test]
1448    fn nested_postgres_transaction_is_rolled_back_upon_deferred_trigger_failure() {
1449        use crate::connection::{AnsiTransactionManager, TransactionManager};
1450        use crate::pg::connection::raw::PgTransactionStatus;
1451        use crate::result::Error;
1452        use crate::*;
1453
1454        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1455        assert_eq!(
1456            None,
1457            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1458                conn
1459            ).transaction_depth().expect("Transaction depth")
1460        );
1461        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1462            assert_eq!(
1463                NonZeroU32::new(1),
1464                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1465                    conn
1466            ).transaction_depth().expect("Transaction depth")
1467            );
1468            sql_query("DROP TABLE IF EXISTS deferred_trigger_nested_commit").execute(conn)?;
1469            sql_query(
1470                "CREATE TABLE deferred_trigger_nested_commit(id INT UNIQUE INITIALLY DEFERRED)",
1471            )
1472            .execute(conn)?;
1473            sql_query(
1474                r#"
1475                    CREATE OR REPLACE FUNCTION transaction_depth_blow_up()
1476                        RETURNS trigger
1477                        LANGUAGE plpgsql
1478                        AS $$
1479                    DECLARE
1480                    BEGIN
1481                        IF NEW.value = 42 THEN
1482                            RAISE EXCEPTION 'Transaction kaboom';
1483                        END IF;
1484                    RETURN NEW;
1485
1486                    END;$$;
1487                "#,
1488            )
1489            .execute(conn)?;
1490
1491            sql_query(
1492                r#"
1493                    CREATE CONSTRAINT TRIGGER transaction_depth_trigger
1494                        AFTER INSERT ON "deferred_trigger_nested_commit"
1495                        DEFERRABLE INITIALLY DEFERRED
1496                        FOR EACH ROW
1497                        EXECUTE PROCEDURE transaction_depth_blow_up()
1498            "#,
1499            )
1500            .execute(conn)?;
1501            let inner_result: Result<_, Error> = conn.build_transaction().run(|conn| {
1502                let result = sql_query("INSERT INTO deferred_trigger_nested_commit VALUES(42)")
1503                    .execute(conn);
1504                assert!(result.is_ok());
1505                Ok(())
1506            });
1507            assert!(inner_result.is_err());
1508            assert_eq!(
1509                PgTransactionStatus::InTransaction,
1510                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1511            );
1512            Ok(())
1513        });
1514        assert_eq!(
1515            None,
1516            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1517                conn
1518            ).transaction_depth().expect("Transaction depth")
1519        );
1520        assert_eq!(
1521            PgTransactionStatus::Idle,
1522            conn.connection_and_transaction_manager
1523                .raw_connection
1524                .transaction_status()
1525        );
1526        assert!(result.is_ok(), "Expected success, got {:?}", result);
1527    }
1528
1529    #[diesel_test_helper::test]
1530    fn nested_postgres_transaction_is_rolled_back_upon_deferred_constraint_failure() {
1531        use crate::connection::{AnsiTransactionManager, TransactionManager};
1532        use crate::pg::connection::raw::PgTransactionStatus;
1533        use crate::result::Error;
1534        use crate::*;
1535
1536        let conn = &mut crate::test_helpers::pg_connection_no_transaction();
1537        assert_eq!(
1538            None,
1539            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1540                conn
1541            ).transaction_depth().expect("Transaction depth")
1542        );
1543        let result: Result<_, Error> = conn.build_transaction().run(|conn| {
1544            assert_eq!(
1545                NonZeroU32::new(1),
1546                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1547                    conn
1548            ).transaction_depth().expect("Transaction depth")
1549            );
1550            sql_query("DROP TABLE IF EXISTS deferred_constraint_nested_commit").execute(conn)?;
1551            sql_query("CREATE TABLE deferred_constraint_nested_commit(id INT UNIQUE INITIALLY DEFERRED)").execute(conn)?;
1552            let inner_result: Result<_, Error> = conn.build_transaction().run(|conn| {
1553                assert_eq!(
1554                    NonZeroU32::new(2),
1555                    <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1556                        conn
1557                    ).transaction_depth().expect("Transaction depth")
1558                );
1559                sql_query("INSERT INTO deferred_constraint_nested_commit VALUES(1)").execute(conn)?;
1560                let result = sql_query("INSERT INTO deferred_constraint_nested_commit VALUES(1)").execute(conn);
1561                assert!(result.is_ok());
1562                Ok(())
1563            });
1564            assert!(inner_result.is_err());
1565            assert_eq!(
1566                PgTransactionStatus::InTransaction,
1567                conn.connection_and_transaction_manager.raw_connection.transaction_status()
1568            );
1569            assert_eq!(
1570                NonZeroU32::new(1),
1571                <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1572                    conn
1573            ).transaction_depth().expect("Transaction depth")
1574            );
1575            sql_query("INSERT INTO deferred_constraint_nested_commit VALUES(1)").execute(conn)
1576        });
1577        assert_eq!(
1578            None,
1579            <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(
1580                conn
1581            ).transaction_depth().expect("Transaction depth")
1582        );
1583        assert_eq!(
1584            PgTransactionStatus::Idle,
1585            conn.connection_and_transaction_manager
1586                .raw_connection
1587                .transaction_status()
1588        );
1589        assert!(result.is_ok());
1590    }
1591
1592    #[crate::declare_sql_function]
1593    extern "SQL" {
1594        fn current_setting(setting_name: crate::sql_types::Text) -> crate::sql_types::Text;
1595        fn pg_backend_pid() -> crate::sql_types::Integer;
1596        fn pg_terminate_backend(
1597            pid: crate::sql_types::Integer,
1598            timeout: crate::sql_types::BigInt,
1599        ) -> crate::sql_types::Bool;
1600    }
1601
1602    #[diesel_test_helper::test]
1603    fn decode_server_version_reads_both_numbering_schemes() {
1604        assert_eq!(
1605            decode_server_version(180004),
1606            Some(DatabaseVersion::new(18, 4, 0))
1607        );
1608        assert_eq!(
1609            decode_server_version(100001),
1610            Some(DatabaseVersion::new(10, 1, 0))
1611        );
1612        assert_eq!(
1613            decode_server_version(90620),
1614            Some(DatabaseVersion::new(9, 6, 20))
1615        );
1616        assert_eq!(decode_server_version(0), None);
1617    }
1618
1619    #[diesel_test_helper::test]
1620    fn version_matches_the_server_reported_version() {
1621        let conn = &mut connection();
1622        let version = conn.version().unwrap();
1623        let reported = crate::select(current_setting("server_version"))
1624            .get_result::<String>(conn)
1625            .unwrap();
1626        let numeric = reported
1627            .split(|c: char| !c.is_ascii_digit() && c != '.')
1628            .next()
1629            .unwrap();
1630        assert_eq!(numeric, format!("{}.{}", version.major(), version.minor()));
1631        assert_eq!(version.patch(), 0);
1632    }
1633
1634    #[diesel_test_helper::test]
1635    fn version_fails_once_the_connection_is_closed() {
1636        let conn = &mut connection();
1637        let pid = crate::select(pg_backend_pid())
1638            .get_result::<i32>(conn)
1639            .unwrap();
1640        assert!(
1641            crate::select(pg_terminate_backend(pid, 5000_i64))
1642                .get_result::<bool>(&mut connection())
1643                .unwrap()
1644        );
1645        assert!(
1646            crate::select(1.into_sql::<crate::sql_types::Integer>())
1647                .get_result::<i32>(conn)
1648                .is_err()
1649        );
1650
1651        assert!(matches!(
1652            conn.version(),
1653            Err(DatabaseError(DatabaseErrorKind::ClosedConnection, _))
1654        ));
1655    }
1656}