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