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#[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#[allow(unsafe_code)]
140unsafe impl Send for PgConnection {}
141
142impl SimpleConnection for PgConnection {
143 #[allow(unsafe_code)] 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#[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, ¶ms, false, true)
229 .and_then(|r| r.rows_affected());
230 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, ¶ms, 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 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 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 tm.status = TransactionManagerStatus::Valid(Default::default())
338 }
339 PgTransactionStatus::InTransaction => {
340 let transaction_status = &mut tm.status;
341 if is_err {
344 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_status.set_in_error()
350 }
351 } else {
352 tm.status.set_requires_rollback_maybe_up_to_top_level(false)
360 }
361 }
362 PgTransactionStatus::Active => {
363 }
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 pub fn build_transaction(&mut self) -> TransactionBuilder<'_, Self> {
454 TransactionBuilder::new(self)
455 }
456
457 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 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
704fn 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 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 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 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#[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 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 #[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 #[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}