From 2171feda1a91b0e77c1c0788abb3fc3183503b79 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Sat, 13 Feb 2010 22:30:41 +0100
Subject: [PATCH 2/2] Dont FATAL a IDLE IN TRANSACTIOn backend during conflict
 resolution. Instead avoid sending the error (and a later "read for
 query") to the client to avoid confusing the client state.

---
 src/backend/tcop/postgres.c |   41 ++++++++++++++++++++++++++++++++---------
 1 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 13734f0..e9c622e 100644
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
*************** static int	UseNewLine = 0;		/* Use EOF a
*** 176,181 ****
--- 176,187 ----
  static bool RecoveryConflictPending = false;
  static ProcSignalReason	RecoveryConflictReason;
  
+ /*
+  * Are we disallowed from sending a "ready for query" message right
+  * now because it would confuse the frontend?
+  */
+ bool silent_error_while_idle = false;
+ 
  /* ----------------------------------------------------------------
   *		decls for routines only used in this file
   * ----------------------------------------------------------------
*************** ProcessInterrupts(void)
*** 2917,2934 ****
  			RecoveryConflictPending = false;
  			DisableNotifyInterrupt();
  			DisableCatchupInterrupt();
! 			if (DoingCommandRead)
! 				ereport(FATAL,
! 						(errcode(ERRCODE_ADMIN_SHUTDOWN),
! 						 errmsg("terminating connection due to conflict with recovery"),
! 						 errdetail_recovery_conflict(),
! 						 errhint("In a moment you should be able to reconnect to the"
! 								 " database and repeat your command.")));
! 			else
  				ereport(ERROR,
  						(errcode(ERRCODE_QUERY_CANCELED),
  						 errmsg("canceling statement due to conflict with recovery"),
  						 errdetail_recovery_conflict()));
  		}
  
  		/*
--- 2923,2948 ----
  			RecoveryConflictPending = false;
  			DisableNotifyInterrupt();
  			DisableCatchupInterrupt();
! 			if (DoingCommandRead){
! 				/*
! 				 * We cant issue a normal ERROR here because the
! 				 * client doesnt expect the server to send an error at
! 				 * that point.
! 				 * We also may not send a "ready for query"/Z message
! 				 * because that would be unexpected as well.
! 				 */
! 				silent_error_while_idle = true;
! 				ereport(ERROR | LOG_NO_CLIENT,
! 						(errcode(ERRCODE_QUERY_CANCELED),
! 						 errmsg("canceling statement due to conflict with recovery"),
! 						 errdetail_recovery_conflict()));
! 			}
! 			else{
  				ereport(ERROR,
  						(errcode(ERRCODE_QUERY_CANCELED),
  						 errmsg("canceling statement due to conflict with recovery"),
  						 errdetail_recovery_conflict()));
+ 			}
  		}
  
  		/*
*************** PostgresMain(int argc, char *argv[], con
*** 3767,3773 ****
  		 * processing of batched messages, and because we don't want to report
  		 * uncommitted updates (that confuses autovacuum).
  		 */
! 		if (send_ready_for_query)
  		{
  			if (IsAbortedTransactionBlockState())
  			{
--- 3781,3787 ----
  		 * processing of batched messages, and because we don't want to report
  		 * uncommitted updates (that confuses autovacuum).
  		 */
! 		if (send_ready_for_query && !silent_error_while_idle)
  		{
  			if (IsAbortedTransactionBlockState())
  			{
*************** PostgresMain(int argc, char *argv[], con
*** 3792,3797 ****
--- 3806,3820 ----
  		}
  
  		/*
+ 		 * After ReadCommand continued we are sure that the frontend
+ 		 * sent a message and can handle a 'Z' message.  We cant set
+ 		 * that after ReadCommand because that will error out when in
+ 		 * an aborted transaction - which we are when
+ 		 * silent_error_while_idle was set.
+ 		 */
+ 		silent_error_while_idle = false;
+ 
+ 		/*
  		 * (2) Allow asynchronous signals to be executed immediately if they
  		 * come in while we are waiting for client input. (This must be
  		 * conditional since we don't want, say, reads on behalf of COPY FROM
-- 
1.6.5.12.gd65df24

