diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 90e7b4a..a6e2405 100644
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** AbortOutOfAnyTransaction(void)
*** 3712,3717 ****
--- 3712,3761 ----
  }
  
  /*
+  *	AbortTransactionAndAnySubtransactions
+  *
+  * Similar to AbortCurrentTransaction but if any subtransactions
+  * in progress we abort them *and* all of their parents. So this is
+  * used when the caller wishes to make the abort untrappable by the user.
+  * After this has run IsAbortedTransactionBlockState() will be true.
+  */
+ void
+ AbortTransactionAndAnySubtransactions(void)
+ {
+ 	while(true){
+ 		TransactionState s = CurrentTransactionState;
+ 
+ 		switch (s->blockState)
+ 		{
+ 			case TBLOCK_DEFAULT:
+ 			case TBLOCK_STARTED:
+ 			case TBLOCK_BEGIN:
+ 			case TBLOCK_INPROGRESS:
+ 			case TBLOCK_END:
+ 			case TBLOCK_ABORT:
+ 			case TBLOCK_SUBABORT:
+ 			case TBLOCK_ABORT_END:
+ 			case TBLOCK_ABORT_PENDING:
+ 			case TBLOCK_PREPARE:
+ 			case TBLOCK_SUBABORT_END:
+ 			case TBLOCK_SUBABORT_RESTART:
+ 				AbortCurrentTransaction();
+ 				return;
+ 				break;
+ 
+ 			case TBLOCK_SUBINPROGRESS:
+ 			case TBLOCK_SUBBEGIN:
+ 			case TBLOCK_SUBEND:
+ 			case TBLOCK_SUBABORT_PENDING:
+ 			case TBLOCK_SUBRESTART:
+ 				AbortSubTransaction();
+ 				CleanupSubTransaction();
+ 				break;
+ 		}
+ 	}
+ }
+ 
+ /*
   * IsTransactionBlock --- are we within a transaction block?
   */
  bool
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 9cb28f7..d8ea470 100644
*** a/src/backend/storage/ipc/procarray.c
--- b/src/backend/storage/ipc/procarray.c
***************
*** 51,56 ****
--- 51,57 ----
  #include "access/xact.h"
  #include "access/twophase.h"
  #include "miscadmin.h"
+ #include "storage/lmgr.h"
  #include "storage/procarray.h"
  #include "storage/standby.h"
  #include "utils/builtins.h"
*************** ProcArrayClearTransaction(PGPROC *proc)
*** 377,383 ****
  	proc->xid = InvalidTransactionId;
  	proc->lxid = InvalidLocalTransactionId;
  	proc->xmin = InvalidTransactionId;
- 	proc->recoveryConflictMode = 0;
  
  	/* redundant, but just in case */
  	proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
--- 378,383 ----
*************** GetConflictingVirtualXIDs(TransactionId 
*** 1665,1672 ****
  		if (proc->pid == 0)
  			continue;
  
! 		if (skipExistingConflicts && proc->recoveryConflictMode > 0)
! 			continue;
  
  		if (!OidIsValid(dbOid) ||
  			proc->databaseId == dbOid)
--- 1665,1677 ----
  		if (proc->pid == 0)
  			continue;
  
! 		/*
! 		 * XXX: doesn't skipExistingConflicts have the danger of
! 		 * shadowing an FATAL error?
! 		 * I.e. ERROR is signalled first and then FATAL is signalled...
! 		 * if (skipExistingConflicts && ...)
! 		 *   continue;
! 		 */
  
  		if (!OidIsValid(dbOid) ||
  			proc->databaseId == dbOid)
*************** GetConflictingVirtualXIDs(TransactionId 
*** 1704,1717 ****
   * Returns pid of the process signaled, or 0 if not found.
   */
  pid_t
! CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode)
  {
  	ProcArrayStruct *arrayP = procArray;
  	int			index;
  	pid_t		pid = 0;
  
! 	LWLockAcquire(ProcArrayLock, LW_SHARED);
  
  	for (index = 0; index < arrayP->numProcs; index++)
  	{
  		VirtualTransactionId procvxid;
--- 1709,1728 ----
   * Returns pid of the process signaled, or 0 if not found.
   */
  pid_t
! CancelVirtualTransaction(VirtualTransactionId vxid,
! 						 recovery_conflict_mode cancel_mode)
  {
  	ProcArrayStruct *arrayP = procArray;
  	int			index;
  	pid_t		pid = 0;
  
! 	ProcSignalReason  sigmode = PROCSIG_CONFLICT_ERROR_INTERRUPT;
! 	size_t num_locks = 0;
  
+ 	/*
+ 	 * Find pid
+ 	 */
+ 	LWLockAcquire(ProcArrayLock, LW_SHARED);
  	for (index = 0; index < arrayP->numProcs; index++)
  	{
  		VirtualTransactionId procvxid;
*************** CancelVirtualTransaction(VirtualTransact
*** 1722,1747 ****
  		if (procvxid.backendId == vxid.backendId &&
  			procvxid.localTransactionId == vxid.localTransactionId)
  		{
- 			/*
- 			 * Issue orders for the proc to read next time it receives SIGINT
- 			 */
- 			if (proc->recoveryConflictMode < cancel_mode)
- 				proc->recoveryConflictMode = cancel_mode;
- 
  			pid = proc->pid;
  			break;
  		}
  	}
- 
  	LWLockRelease(ProcArrayLock);
  
! 	if (pid != 0)
! 	{
  		/*
! 		 * Kill the pid if it's still here. If not, that's what we wanted
! 		 * so ignore any errors.
  		 */
! 		kill(pid, SIGINT);
  	}
  
  	return pid;
--- 1733,1782 ----
  		if (procvxid.backendId == vxid.backendId &&
  			procvxid.localTransactionId == vxid.localTransactionId)
  		{
  			pid = proc->pid;
  			break;
  		}
  	}
  	LWLockRelease(ProcArrayLock);
  
! 	if(!pid)
! 		return pid;
! 
! 	/*
! 	 * Kill the transaction. We retry 50 times - if we didnt finish
! 	 * the transaction till then, we start using FATAL.
! 	 *
! 	 * We dont need to lock while signalling as the messages contain
! 	 * only sig_atomic_t wide contents which itself identify the
! 	 * operation completely. I.e. it contains the local transaction
! 	 * id, so it can't abort the wrong transaction.
! 	 */
! 	if (cancel_mode == CONFLICT_MODE_FATAL)
! 		sigmode = PROCSIG_CONFLICT_FATAL_INTERRUPT;
! 
! 	while(!ConditionalVirtualXactLockTableWait(vxid)){
! 		if(sigmode == PROCSIG_CONFLICT_ERROR_INTERRUPT && num_locks++ > 50){
! 			sigmode = PROCSIG_CONFLICT_FATAL_INTERRUPT;
! 
! 			elog(trace_recovery(DEBUG1),
! 				 "recovery tried to cancel virtual transaction %u/%u pid %ld. No success so far. Using FATAL",
! 				 vxid.backendId,
! 				 vxid.localTransactionId,
! 				 (long) pid);
! 		}
! 
! 		if(sigmode == PROCSIG_CONFLICT_FATAL_INTERRUPT){
! 			SendProcSignal(pid, sigmode, vxid.backendId, pid);
! 		}
! 		else{
! 			SendProcSignal(pid, sigmode, vxid.backendId, vxid.localTransactionId);
! 		}
! 
  		/*
! 		 * Wait awhile for it to die so that we avoid flooding an
! 		 * unresponsive backend when system is heavily loaded.
  		 */
! 		pg_usleep(5000);
  	}
  
  	return pid;
*************** CancelDBBackends(Oid databaseid)
*** 1842,1851 ****
  	{
  		volatile PGPROC *proc = arrayP->procs[index];
  
  		if (proc->databaseId == databaseid)
  		{
! 			proc->recoveryConflictMode = CONFLICT_MODE_FATAL;
! 			kill(proc->pid, SIGINT);
  		}
  	}
  
--- 1877,1887 ----
  	{
  		volatile PGPROC *proc = arrayP->procs[index];
  
+ 
  		if (proc->databaseId == databaseid)
  		{
! 			SendProcSignal(proc->pid, PROCSIG_CONFLICT_FATAL_INTERRUPT,
! 						   InvalidBackendId, true);
  		}
  	}
  
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 2892727..1fbb886 100644
*** a/src/backend/storage/ipc/procsignal.c
--- b/src/backend/storage/ipc/procsignal.c
***************
*** 24,29 ****
--- 24,31 ----
  #include "storage/procsignal.h"
  #include "storage/shmem.h"
  #include "storage/sinval.h"
+ #include "storage/standby.h"
+ #include "tcop/tcopprot.h"
  
  
  /*
*************** void
*** 255,260 ****
--- 257,276 ----
  procsignal_sigusr1_handler(SIGNAL_ARGS)
  {
  	int		save_errno = errno;
+ 	sig_atomic_t signal_data;
+ 
+ 	/*
+ 	 * We check the possible signals in decreasing order of
+ 	 * importance. For example if were FATALing the backend there is
+ 	 * no point in sending out NOTIFYs before that.
+ 	 * XXX: Possibly we should not calll the other handlers at all when
+ 	 * receiving FATAL
+ 	 */
+ 	if ((signal_data = CheckProcSignal(PROCSIG_CONFLICT_FATAL_INTERRUPT)))
+ 		RecoveryConflictInterrupt(CONFLICT_MODE_FATAL, signal_data);
+ 
+ 	if ((signal_data = CheckProcSignal(PROCSIG_CONFLICT_ERROR_INTERRUPT)))
+ 		RecoveryConflictInterrupt(CONFLICT_MODE_ERROR, signal_data);
  
  	if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
  		HandleCatchupInterrupt();
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 227b9cc..614914d 100644
*** a/src/backend/storage/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
*************** WaitExceedsMaxStandbyDelay(void)
*** 164,170 ****
   */
  void
  ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
! 									   char *reason, int cancel_mode)
  {
  	char		waitactivitymsg[100];
  
--- 164,170 ----
   */
  void
  ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
! 									   char *reason, recovery_conflict_mode cancel_mode)
  {
  	char		waitactivitymsg[100];
  
*************** ResolveRecoveryConflictWithVirtualXIDs(V
*** 234,246 ****
  					{
  						case CONFLICT_MODE_FATAL:
  							elog(trace_recovery(DEBUG1),
! 								 "recovery disconnects session with pid %ld because of conflict with %s",
  								 (long) pid,
  								 reason);
  							break;
  						case CONFLICT_MODE_ERROR:
  							elog(trace_recovery(DEBUG1),
! 								 "recovery cancels virtual transaction %u/%u pid %ld because of conflict with %s",
  								 waitlist->backendId,
  								 waitlist->localTransactionId,
  								 (long) pid,
--- 234,246 ----
  					{
  						case CONFLICT_MODE_FATAL:
  							elog(trace_recovery(DEBUG1),
! 								 "recovery disconnected session with pid %ld because of conflict with %s",
  								 (long) pid,
  								 reason);
  							break;
  						case CONFLICT_MODE_ERROR:
  							elog(trace_recovery(DEBUG1),
! 								 "recovery canceled virtual transaction %u/%u pid %ld because of conflict with %s",
  								 waitlist->backendId,
  								 waitlist->localTransactionId,
  								 (long) pid,
*************** ResolveRecoveryConflictWithVirtualXIDs(V
*** 250,261 ****
  							/* No conflict pending, so fall through */
  							break;
  					}
- 
- 					/*
- 					 * Wait awhile for it to die so that we avoid flooding an
- 					 * unresponsive backend when system is heavily loaded.
- 					 */
- 					pg_usleep(5000);
  				}
  			}
  		}
--- 250,255 ----
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7daa5e8..3d4bd10 100644
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
*************** InitProcess(void)
*** 318,324 ****
  	MyProc->waitProcLock = NULL;
  	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
  		SHMQueueInit(&(MyProc->myProcLocks[i]));
- 	MyProc->recoveryConflictMode = 0;
  
  	/*
  	 * We might be reusing a semaphore that belonged to a failed process. So
--- 318,323 ----
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index be20bf3..919b1a3 100644
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
*************** static int	UseNewLine = 1;		/* Use newli
*** 172,177 ****
--- 172,178 ----
  static int	UseNewLine = 0;		/* Use EOF as query delimiters */
  #endif   /* TCOP_DONTUSENEWLINE */
  
+ static LocalTransactionId CanceledLocalTransaction = InvalidLocalTransactionId;
  
  /* ----------------------------------------------------------------
   *		decls for routines only used in this file
*************** StatementCancelHandler(SIGNAL_ARGS)
*** 2642,2648 ****
  		 * service the interrupt immediately
  		 */
  		if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
! 			CritSectionCount == 0)
  		{
  			/* bump holdoff count to make ProcessInterrupts() a no-op */
  			/* until we are done getting ready for it */
--- 2643,2649 ----
  		 * service the interrupt immediately
  		 */
  		if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
! 			CritSectionCount == 0 && !DoingCommandRead)
  		{
  			/* bump holdoff count to make ProcessInterrupts() a no-op */
  			/* until we are done getting ready for it */
*************** ProcessInterrupts(void)
*** 2711,2819 ****
  					(errcode(ERRCODE_ADMIN_SHUTDOWN),
  			 errmsg("terminating connection due to administrator command")));
  	}
  	if (QueryCancelPending)
  	{
  		QueryCancelPending = false;
  		if (ClientAuthInProgress)
- 		{
- 			ImmediateInterruptOK = false;	/* not idle anymore */
- 			DisableNotifyInterrupt();
- 			DisableCatchupInterrupt();
- 			/* As in quickdie, don't risk sending to client during auth */
- 			if (whereToSendOutput == DestRemote)
- 				whereToSendOutput = DestNone;
  			ereport(ERROR,
  					(errcode(ERRCODE_QUERY_CANCELED),
  					 errmsg("canceling authentication due to timeout")));
! 		}
! 		if (cancel_from_timeout)
! 		{
! 			ImmediateInterruptOK = false;	/* not idle anymore */
! 			DisableNotifyInterrupt();
! 			DisableCatchupInterrupt();
  			ereport(ERROR,
  					(errcode(ERRCODE_QUERY_CANCELED),
  					 errmsg("canceling statement due to statement timeout")));
! 		}
! 		if (IsAutoVacuumWorkerProcess())
! 		{
! 			ImmediateInterruptOK = false;	/* not idle anymore */
! 			DisableNotifyInterrupt();
! 			DisableCatchupInterrupt();
  			ereport(ERROR,
  					(errcode(ERRCODE_QUERY_CANCELED),
  					 errmsg("canceling autovacuum task")));
! 		}
! 		{
! 			int cancelMode = MyProc->recoveryConflictMode;
  
  			/*
! 			 * XXXHS: We don't yet have a clean way to cancel an
! 			 * idle-in-transaction session, so make it FATAL instead.
! 			 * This isn't as bad as it looks because we don't issue a
! 			 * CONFLICT_MODE_ERROR for a session with proc->xmin == 0
! 			 * on cleanup conflicts. There's a possibility that we
! 			 * marked somebody as a conflict and then they go idle.
  			 */
! 			if (DoingCommandRead && IsTransactionBlock() &&
! 				cancelMode == CONFLICT_MODE_ERROR)
! 			{
! 				cancelMode = CONFLICT_MODE_FATAL;
  			}
  
- 			switch (cancelMode)
- 			{
- 				case CONFLICT_MODE_FATAL:
- 					ImmediateInterruptOK = false;	/* not idle anymore */
- 					DisableNotifyInterrupt();
- 					DisableCatchupInterrupt();
- 					Assert(RecoveryInProgress());
- 					ereport(FATAL,
- 							(errcode(ERRCODE_QUERY_CANCELED),
- 							 errmsg("canceling session due to conflict with recovery")));
  
! 				case CONFLICT_MODE_ERROR:
! 					/*
! 					 * We are aborting because we need to release
! 					 * locks. So we need to abort out of all
! 					 * subtransactions to make sure we release
! 					 * all locks at whatever their level.
! 					 *
! 					 * XXX Should we try to examine the
! 					 * transaction tree and cancel just enough
! 					 * subxacts to remove locks? Doubt it.
! 					 */
! 					ImmediateInterruptOK = false;	/* not idle anymore */
! 					DisableNotifyInterrupt();
! 					DisableCatchupInterrupt();
! 					Assert(RecoveryInProgress());
! 					AbortOutOfAnyTransaction();
! 					ereport(ERROR,
! 							(errcode(ERRCODE_QUERY_CANCELED),
! 							 errmsg("canceling statement due to conflict with recovery")));
  
! 				default:
! 					/* No conflict pending, so fall through */
! 					break;
! 			}
  		}
  
  		/*
! 		 * If we are reading a command from the client, just ignore the
! 		 * cancel request --- sending an extra error message won't
! 		 * accomplish anything.  Otherwise, go ahead and throw the error.
  		 */
! 		if (!DoingCommandRead)
  		{
! 			ImmediateInterruptOK = false;	/* not idle anymore */
  			DisableNotifyInterrupt();
  			DisableCatchupInterrupt();
! 			ereport(ERROR,
! 					(errcode(ERRCODE_QUERY_CANCELED),
! 					 errmsg("canceling statement due to user request")));
  		}
  	}
! 	/* If we get here, do nothing (probably, QueryCancelPending was reset) */
  }
  
  
--- 2712,2818 ----
  					(errcode(ERRCODE_ADMIN_SHUTDOWN),
  			 errmsg("terminating connection due to administrator command")));
  	}
+ 
  	if (QueryCancelPending)
  	{
  		QueryCancelPending = false;
+ 		ImmediateInterruptOK = false;	/* not idle anymore */
+ 		DisableNotifyInterrupt();
+ 		DisableCatchupInterrupt();
+ 		/* As in quickdie, don't risk sending to client during auth */
+ 		if (ClientAuthInProgress && whereToSendOutput == DestRemote)
+ 			whereToSendOutput = DestNone;
  		if (ClientAuthInProgress)
  			ereport(ERROR,
  					(errcode(ERRCODE_QUERY_CANCELED),
  					 errmsg("canceling authentication due to timeout")));
! 		else if (cancel_from_timeout)
  			ereport(ERROR,
  					(errcode(ERRCODE_QUERY_CANCELED),
  					 errmsg("canceling statement due to statement timeout")));
! 		else if (IsAutoVacuumWorkerProcess())
  			ereport(ERROR,
  					(errcode(ERRCODE_QUERY_CANCELED),
  					 errmsg("canceling autovacuum task")));
! 		else
! 			ereport(ERROR,
! 					(errcode(ERRCODE_QUERY_CANCELED),
! 					 errmsg("canceling statement due to user request")));
! 	}
! 
  
+ 	{
+ 		LocalTransactionId current_canceled = CanceledLocalTransaction;
+ 
+ 		/*
+ 		 * To avoid cancelling the wrong transaction because the
+ 		 * normal transaction already finished and generated a new
+ 		 * error before the signal handler or ProcessInterrupts has
+ 		 * run we recheck the current LocalTransactionId.
+ 		 */
+ 
+ 		if(CanceledLocalTransaction != InvalidLocalTransactionId)
+ 		{
+ 			ImmediateInterruptOK = false;	/* not idle anymore */
  			/*
! 			 * Cancel the transaction whether or not it was idle, so don't mention
! 			 * the word idle in the message.
  			 */
! 			if (current_canceled == MyProc->lxid){
! 				ereport(ERROR,
! 						(errcode(ERRCODE_QUERY_CANCELED_HS),
! 						 errmsg("canceling transaction due to conflict with recovery")));
  			}
+ 		}
+ 	}
+ }
  
  
! void
! RecoveryConflictInterrupt(recovery_conflict_mode conflict_mode, sig_atomic_t signal_data)
! {
! 	int			save_errno = errno;
  
! 	/*
! 	 * Don't joggle the elbow of proc_exit
! 	 */
! 	if (!proc_exit_inprogress)
! 	{
! 		switch (conflict_mode)
! 		{
! 			case CONFLICT_MODE_FATAL:
! 				ProcDiePending = true;
! 				break;
! 
! 			case CONFLICT_MODE_ERROR:
! 				CanceledLocalTransaction = (LocalTransactionId)signal_data;
! 				break;
! 
! 			default:
! 				elog(ERROR, "Unknown conflict mode");
  		}
  
+ 		InterruptPending = true;
+ 
  		/*
! 		 * If it's safe to interrupt, and we're waiting for input or a lock,
! 		 * service the interrupt immediately. Same as in die()
  		 */
! 		if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
! 			CritSectionCount == 0)
  		{
! 			/* bump holdoff count to make ProcessInterrupts() a no-op */
! 			/* until we are done getting ready for it */
! 			InterruptHoldoffCount++;
! 			LockWaitCancel();	/* prevent CheckDeadLock from running */
  			DisableNotifyInterrupt();
  			DisableCatchupInterrupt();
! 			InterruptHoldoffCount--;
! 			ProcessInterrupts();
  		}
  	}
! 
! 	errno = save_errno;
  }
  
  
*************** PostgresMain(int argc, char *argv[], con
*** 3560,3568 ****
  		debug_query_string = NULL;
  
  		/*
! 		 * Abort the current transaction in order to recover.
  		 */
! 		AbortCurrentTransaction();
  
  		/*
  		 * Now return to normal top-level context and clear ErrorContext for
--- 3559,3593 ----
  		debug_query_string = NULL;
  
  		/*
! 		 * Abort the current transaction in order to recover. If were
! 		 * in HS this is the only safe point where we can abort not
! 		 * only the current transaction but also all transaction above
! 		 * the current as there exists no higher point to jump to and
! 		 * thus were not playing around with somebodys execution context.
! 		 *
! 		 * To avoid cancelling the wrong transaction because the
! 		 * normal transaction already finished and generated a new
! 		 * error before the signal handler has run we recheck the
! 		 * current LocalTransactionId.
! 		 *
! 		 * XXX: Possibly this should use the new error code for a
! 		 * transaction canceled by HS instead.
  		 */
! 		{
! 			LocalTransactionId current_canceled = CanceledLocalTransaction;
! 			if(current_canceled != InvalidLocalTransactionId &&
! 			   current_canceled == MyProc->lxid)
! 				AbortTransactionAndAnySubtransactions();
! 			else
! 				AbortCurrentTransaction();
! 		}
! 
! 		/*
! 		 * We cannot overwrite a newly canceled LocalTransactionId
! 		 * here because we would have to leave that block to start a
! 		 * new transaction.
! 		 */
! 		CanceledLocalTransaction = InvalidLocalTransactionId;
  
  		/*
  		 * Now return to normal top-level context and clear ErrorContext for
*************** PostgresMain(int argc, char *argv[], con
*** 3598,3603 ****
--- 3623,3630 ----
  
  	for (;;)
  	{
+ 		CanceledLocalTransaction = InvalidLocalTransactionId;
+ 
  		/*
  		 * At top of loop, reset extended-query-message flag, so that any
  		 * errors encountered in "idle" state don't provoke skip.
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 4c67be5..47b325a 100644
*** a/src/include/access/xact.h
--- b/src/include/access/xact.h
*************** extern bool IsTransactionBlock(void);
*** 204,209 ****
--- 204,210 ----
  extern bool IsTransactionOrTransactionBlock(void);
  extern char TransactionBlockStatusCode(void);
  extern void AbortOutOfAnyTransaction(void);
+ extern void AbortTransactionAndAnySubtransactions(void);
  extern void PreventTransactionChain(bool isTopLevel, const char *stmtType);
  extern void RequireTransactionChain(bool isTopLevel, const char *stmtType);
  extern bool IsInTransactionChain(bool isTopLevel);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index de0df3b..46c74ef 100644
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
*************** struct PGPROC
*** 95,107 ****
  
  	uint8		vacuumFlags;	/* vacuum-related flags, see above */
  
- 	/*
- 	 * While in hot standby mode, setting recoveryConflictMode instructs
- 	 * the backend to commit suicide. Possible values are the same as those
- 	 * passed to ResolveRecoveryConflictWithVirtualXIDs().
- 	 */
- 	int			recoveryConflictMode;
- 
  	/* Info about LWLock the process is currently waiting for, if any. */
  	bool		lwWaiting;		/* true if waiting for an LW lock */
  	bool		lwExclusive;	/* true if waiting for exclusive access */
--- 95,100 ----
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index 314491d..868058b 100644
*** a/src/include/storage/procarray.h
--- b/src/include/storage/procarray.h
***************
*** 17,22 ****
--- 17,23 ----
  #include "storage/lock.h"
  #include "storage/standby.h"
  #include "utils/snapshot.h"
+ #include "storage/procsignal.h"
  
  
  extern Size ProcArrayShmemSize(void);
*************** extern VirtualTransactionId *GetCurrentV
*** 59,65 ****
  extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin,
  					Oid dbOid, bool skipExistingConflicts);
  extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid,
! 						 int cancel_mode);
  
  extern int	CountActiveBackends(void);
  extern int	CountDBBackends(Oid databaseid);
--- 60,66 ----
  extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin,
  					Oid dbOid, bool skipExistingConflicts);
  extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid,
! 									  recovery_conflict_mode cancel_mode);
  
  extern int	CountActiveBackends(void);
  extern int	CountDBBackends(Oid databaseid);
diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h
index 3b0d56d..795346c 100644
*** a/src/include/storage/procsignal.h
--- b/src/include/storage/procsignal.h
***************
*** 30,35 ****
--- 30,38 ----
   */
  typedef enum
  {
+ 	PROCSIG_CONFLICT_FATAL_INTERRUPT,	/* recovery conflict fatal */
+ 	PROCSIG_CONFLICT_ERROR_INTERRUPT,	/* recovery conflict error */
+ 
  	PROCSIG_CATCHUP_INTERRUPT,	/* sinval catchup interrupt */
  	PROCSIG_NOTIFY_INTERRUPT,	/* listen/notify interrupt */
  
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index 7a1c41f..ac950b7 100644
*** a/src/include/storage/standby.h
--- b/src/include/storage/standby.h
***************
*** 20,31 ****
  extern int	vacuum_defer_cleanup_age;
  
  /* cancel modes for ResolveRecoveryConflictWithVirtualXIDs */
! #define CONFLICT_MODE_NOT_SET		0
! #define CONFLICT_MODE_ERROR			1	/* Conflict can be resolved by canceling query */
! #define CONFLICT_MODE_FATAL			2	/* Conflict can only be resolved by disconnecting session */
  
  extern void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
! 									   char *reason, int cancel_mode);
  
  extern void InitRecoveryTransactionEnvironment(void);
  extern void ShutdownRecoveryTransactionEnvironment(void);
--- 20,33 ----
  extern int	vacuum_defer_cleanup_age;
  
  /* cancel modes for ResolveRecoveryConflictWithVirtualXIDs */
! typedef enum {
! 	CONFLICT_MODE_NOT_SET, /* No conflict */
! 	CONFLICT_MODE_FATAL, /* Conflict can only be resolved by disconnecting session */
! 	CONFLICT_MODE_ERROR /* Conflict can be resolved by canceling query */
! } recovery_conflict_mode;
  
  extern void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
! 									   char *reason, recovery_conflict_mode cancel_mode);
  
  extern void InitRecoveryTransactionEnvironment(void);
  extern void ShutdownRecoveryTransactionEnvironment(void);
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 1298f7d..b901b6a 100644
*** a/src/include/tcop/tcopprot.h
--- b/src/include/tcop/tcopprot.h
***************
*** 19,27 ****
--- 19,30 ----
  #ifndef TCOPPROT_H
  #define TCOPPROT_H
  
+ #include <signal.h>
  #include "executor/execdesc.h"
  #include "nodes/parsenodes.h"
  #include "utils/guc.h"
+ #include "storage/standby.h"
+ 
  
  
  /* Required daylight between max_stack_depth and the kernel limit, in bytes */
*************** extern bool assign_max_stack_depth(int n
*** 63,68 ****
--- 66,73 ----
  extern void die(SIGNAL_ARGS);
  extern void quickdie(SIGNAL_ARGS);
  extern void StatementCancelHandler(SIGNAL_ARGS);
+ 
+ extern void RecoveryConflictInterrupt(recovery_conflict_mode conflict_mode, sig_atomic_t signal_data);
  extern void FloatExceptionHandler(SIGNAL_ARGS);
  extern void prepare_for_client_read(void);
  extern void client_read_ended(void);
diff --git a/src/include/utils/errcodes.h b/src/include/utils/errcodes.h
index 52c09ca..279f0e4 100644
*** a/src/include/utils/errcodes.h
--- b/src/include/utils/errcodes.h
***************
*** 328,333 ****
--- 328,334 ----
  /* Class 57 - Operator Intervention (class borrowed from DB2) */
  #define ERRCODE_OPERATOR_INTERVENTION		MAKE_SQLSTATE('5','7', '0','0','0')
  #define ERRCODE_QUERY_CANCELED				MAKE_SQLSTATE('5','7', '0','1','4')
+ #define ERRCODE_QUERY_CANCELED_HS			MAKE_SQLSTATE('5','7', '0','1','5')
  #define ERRCODE_ADMIN_SHUTDOWN				MAKE_SQLSTATE('5','7', 'P','0','1')
  #define ERRCODE_CRASH_SHUTDOWN				MAKE_SQLSTATE('5','7', 'P','0','2')
  #define ERRCODE_CANNOT_CONNECT_NOW			MAKE_SQLSTATE('5','7', 'P','0','3')
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index b9ca54f..810ef8c 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** exception_matches_conditions(ErrorData *
*** 897,903 ****
  		 * OTHERS matches everything *except* query-canceled; if you're
  		 * foolish enough, you can match that explicitly.
  		 */
! 		if (sqlerrstate == 0)
  		{
  			if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED)
  				return true;
--- 897,905 ----
  		 * OTHERS matches everything *except* query-canceled; if you're
  		 * foolish enough, you can match that explicitly.
  		 */
! 		if (edata->sqlerrcode == ERRCODE_QUERY_CANCELED_HS)
! 			;
! 		else if (sqlerrstate == 0)
  		{
  			if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED)
  				return true;
