*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
***************
*** 901,907 **** StartPrepare(GlobalTransaction gxact)
  	hdr.ncommitrels = smgrGetPendingDeletes(true, &commitrels);
  	hdr.nabortrels = smgrGetPendingDeletes(false, &abortrels);
  	hdr.ninvalmsgs = xactGetCommittedInvalidationMessages(&invalmsgs,
! 														  &hdr.initfileinval);
  	StrNCpy(hdr.gid, gxact->gid, GIDSIZE);
  
  	save_state_data(&hdr, sizeof(TwoPhaseFileHeader));
--- 901,907 ----
  	hdr.ncommitrels = smgrGetPendingDeletes(true, &commitrels);
  	hdr.nabortrels = smgrGetPendingDeletes(false, &abortrels);
  	hdr.ninvalmsgs = xactGetCommittedInvalidationMessages(&invalmsgs,
! 														  &hdr.initfileinval, false);
  	StrNCpy(hdr.gid, gxact->gid, GIDSIZE);
  
  	save_state_data(&hdr, sizeof(TwoPhaseFileHeader));
*** a/src/backend/access/transam/varsup.c
--- b/src/backend/access/transam/varsup.c
***************
*** 43,49 **** VariableCache ShmemVariableCache = NULL;
   * issue a warning about XID wrap.
   */
  TransactionId
! GetNewTransactionId(bool isSubXact)
  {
  	TransactionId xid;
  
--- 43,49 ----
   * issue a warning about XID wrap.
   */
  TransactionId
! GetNewTransactionId(bool isSubXact, int stateNestinglevel, int autotxlevel)
  {
  	TransactionId xid;
  
***************
*** 212,217 **** GetNewTransactionId(bool isSubXact)
--- 212,249 ----
  		volatile PGPROC *myproc = MyProc;
  		volatile PGXACT *mypgxact = MyPgXact;
  
+ 		if (autotxlevel > 0)
+ 		{
+ 			int		 nxids = 0;
+ 			int		 autoNestingLevel = 0;
+ 			volatile PGAutonomousXACT *mypgautonomoustx;
+ 			mypgautonomoustx = &MyPgAutonomousXact[autotxlevel-1];
+ 			autoNestingLevel = mypgautonomoustx->nestingLevel;
+ 
+ 			/* In top auto tx*/
+ 			if (stateNestinglevel == autoNestingLevel)
+ 			{
+ 				mypgautonomoustx->xid = xid;
+ 				LWLockRelease(XidGenLock);
+ 				return xid;
+ 			}
+ 
+ 			/* Subtransaction in auto tx */
+ 			Assert(autoNestingLevel < stateNestinglevel);
+ 
+ 			nxids = mypgautonomoustx->nxids;
+ 			if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
+ 			{
+ 				mypgautonomoustx->subxids.xids[nxids] = xid;
+ 				mypgautonomoustx->nxids++;
+ 			}
+ 			else
+ 				mypgautonomoustx->overflowed = true;
+ 
+ 			LWLockRelease(XidGenLock);
+ 			return xid;
+ 		}
+ 
  		if (!isSubXact)
  			mypgxact->xid = xid;
  		else
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 123,129 **** typedef enum TBlockState
  	TBLOCK_SUBABORT_END,		/* failed subxact, ROLLBACK received */
  	TBLOCK_SUBABORT_PENDING,	/* live subxact, ROLLBACK received */
  	TBLOCK_SUBRESTART,			/* live subxact, ROLLBACK TO received */
! 	TBLOCK_SUBABORT_RESTART		/* failed subxact, ROLLBACK TO received */
  } TBlockState;
  
  /*
--- 123,137 ----
  	TBLOCK_SUBABORT_END,		/* failed subxact, ROLLBACK received */
  	TBLOCK_SUBABORT_PENDING,	/* live subxact, ROLLBACK received */
  	TBLOCK_SUBRESTART,			/* live subxact, ROLLBACK TO received */
! 	TBLOCK_SUBABORT_RESTART,	/* failed subxact, ROLLBACK TO received */
! 
! 	TBLOCK_AUTOBEGIN,
! 	TBLOCK_AUTOINPROGRESS,
! 	TBLOCK_AUTOCOMMIT,
! 	TBLOCK_AUTOABORT,
! 	TBLOCK_AUTOABORT_END,
! 	TBLOCK_AUTOABORT_PENDING
! 
  } TBlockState;
  
  /*
***************
*** 149,154 **** typedef struct TransactionStateData
--- 157,164 ----
  	bool		prevXactReadOnly;		/* entry-time xact r/o state */
  	bool		startedInRecovery;		/* did we start in recovery? */
  	bool		didLogXid;		/* has xid been included in WAL record? */
+ 	MemoryContext preMemoryContext; /* previous memory context */
+ 	ResourceOwner preResourceOwner; /* previous resource owner */
  	struct TransactionStateData *parent;		/* back link to parent */
  } TransactionStateData;
  
***************
*** 279,285 **** static void StartSubTransaction(void);
  static void CommitSubTransaction(void);
  static void AbortSubTransaction(void);
  static void CleanupSubTransaction(void);
! static void PushTransaction(void);
  static void PopTransaction(void);
  
  static void AtSubAbort_Memory(void);
--- 289,296 ----
  static void CommitSubTransaction(void);
  static void AbortSubTransaction(void);
  static void CleanupSubTransaction(void);
! static void PushTransaction(bool isAutoTX);
! static TransactionId GetTopAutonomousTransactionID(void);
  static void PopTransaction(void);
  
  static void AtSubAbort_Memory(void);
***************
*** 332,338 **** IsAbortedTransactionBlockState(void)
  	TransactionState s = CurrentTransactionState;
  
  	if (s->blockState == TBLOCK_ABORT ||
! 		s->blockState == TBLOCK_SUBABORT)
  		return true;
  
  	return false;
--- 343,350 ----
  	TransactionState s = CurrentTransactionState;
  
  	if (s->blockState == TBLOCK_ABORT ||
! 		s->blockState == TBLOCK_SUBABORT ||
! 		s->blockState == TBLOCK_AUTOABORT)
  		return true;
  
  	return false;
***************
*** 348,354 **** IsAbortedTransactionBlockState(void)
  TransactionId
  GetTopTransactionId(void)
  {
! 	if (!TransactionIdIsValid(TopTransactionStateData.transactionId))
  		AssignTransactionId(&TopTransactionStateData);
  	return TopTransactionStateData.transactionId;
  }
--- 360,370 ----
  TransactionId
  GetTopTransactionId(void)
  {
! 	if (MyProc->inAutoTXLevel)
! 	{
! 		return GetTopAutonomousTransactionID();
! 	}
! 	else if (!TransactionIdIsValid(TopTransactionStateData.transactionId))
  		AssignTransactionId(&TopTransactionStateData);
  	return TopTransactionStateData.transactionId;
  }
***************
*** 363,368 **** GetTopTransactionId(void)
--- 379,402 ----
  TransactionId
  GetTopTransactionIdIfAny(void)
  {
+ 	if ((MyProc != NULL) && (MyProc->inAutoTXLevel)
+ 							&& (MyPgAutonomousXact != NULL))
+ 	{
+ 		TransactionId result = InvalidTransactionId;
+ 		TransactionState s = CurrentTransactionState;
+ 		TransactionState target = s;
+ 
+ 		for (;PointerIsValid(target) ; target=target->parent)
+ 		{
+ 		 	if (IS_TOP_AUTO_TX_STATE(target))
+ 		 	{
+ 				result = target->transactionId;
+ 				break;
+ 		 	}
+ 		}
+ 		return result;
+ 	}
+ 
  	return TopTransactionStateData.transactionId;
  }
  
***************
*** 451,461 **** AssignTransactionId(TransactionState s)
--- 485,515 ----
  	bool		isSubXact = (s->parent != NULL);
  	ResourceOwner currentOwner;
  	bool log_unknown_top = false;
+ 	int			autotxlevel = 0;
+ 	bool		inAutoTx = false;
+ 	PGAutonomousXACT	*currentautotx = NULL;
+ 	int 		i = 0;
+ 
  
  	/* Assert that caller didn't screw up */
  	Assert(!TransactionIdIsValid(s->transactionId));
  	Assert(s->state == TRANS_INPROGRESS);
  
+ 
+ 	for (i=0; i < MyProc->inAutoTXLevel; i++)
+ 	{
+ 		currentautotx = &MyPgAutonomousXact[i];
+ 		if (currentautotx->nestingLevel <= s->nestingLevel)
+ 		{
+ 			autotxlevel = i+1;
+ 			if (currentautotx->nestingLevel == s->nestingLevel)
+ 			{
+ 				inAutoTx = true;
+ 				break;
+ 			}
+ 		}
+ 	}
+ 
  	/*
  	 * Ensure parent(s) have XIDs, so that a child always has an XID later
  	 * than its parent.  Musn't recurse here, or we might get a stack overflow
***************
*** 507,515 **** AssignTransactionId(TransactionState s)
  	 * PG_PROC, the subtrans entry is needed to ensure that other backends see
  	 * the Xid as "running".  See GetNewTransactionId.
  	 */
! 	s->transactionId = GetNewTransactionId(isSubXact);
  
! 	if (isSubXact)
  		SubTransSetParent(s->transactionId, s->parent->transactionId, false);
  
  	/*
--- 561,569 ----
  	 * PG_PROC, the subtrans entry is needed to ensure that other backends see
  	 * the Xid as "running".  See GetNewTransactionId.
  	 */
! 	s->transactionId = GetNewTransactionId(isSubXact, s->nestingLevel, autotxlevel);
  
! 	if (isSubXact && inAutoTx)
  		SubTransSetParent(s->transactionId, s->parent->transactionId, false);
  
  	/*
***************
*** 749,759 **** TransactionIdIsCurrentTransactionId(TransactionId xid)
  	{
  		int			low,
  					high;
  
  		if (s->state == TRANS_ABORT)
! 			continue;
  		if (!TransactionIdIsValid(s->transactionId))
! 			continue;			/* it can't have any child XIDs either */
  		if (TransactionIdEquals(xid, s->transactionId))
  			return true;
  		/* As the childXids array is ordered, we can use binary search */
--- 803,826 ----
  	{
  		int			low,
  					high;
+ 		int 		isTopAutoTx = IS_TOP_AUTO_TX_STATE(s);
  
  		if (s->state == TRANS_ABORT)
! 		{
! 			if (isTopAutoTx)
! 				break;
! 			else
! 				continue;
! 		}
! 
  		if (!TransactionIdIsValid(s->transactionId))
! 		{
! 			if (isTopAutoTx)
! 				break;
! 			else
! 				continue;			/* it can't have any child XIDs either */
! 		}
! 
  		if (TransactionIdEquals(xid, s->transactionId))
  			return true;
  		/* As the childXids array is ordered, we can use binary search */
***************
*** 773,778 **** TransactionIdIsCurrentTransactionId(TransactionId xid)
--- 840,852 ----
  			else
  				high = middle - 1;
  		}
+ 
+ 		/*
+ 		 * If it was auto-tx and till now it did not match, then no need to
+ 		 * search further.
+ 		 */
+ 		if (isTopAutoTx)
+ 			break;
  	}
  
  	return false;
***************
*** 992,998 **** AtSubStart_ResourceOwner(void)
   * if the xact has no XID.	(We compute that here just because it's easier.)
   */
  static TransactionId
! RecordTransactionCommit(void)
  {
  	TransactionId xid = GetTopTransactionIdIfAny();
  	bool		markXidCommitted = TransactionIdIsValid(xid);
--- 1066,1072 ----
   * if the xact has no XID.	(We compute that here just because it's easier.)
   */
  static TransactionId
! RecordTransactionCommit(bool isAutoXact)
  {
  	TransactionId xid = GetTopTransactionIdIfAny();
  	bool		markXidCommitted = TransactionIdIsValid(xid);
***************
*** 1005,1017 **** RecordTransactionCommit(void)
  	SharedInvalidationMessage *invalMessages = NULL;
  	bool		RelcacheInitFileInval = false;
  	bool		wrote_xlog;
  
  	/* Get data needed for commit record */
  	nrels = smgrGetPendingDeletes(true, &rels);
  	nchildren = xactGetCommittedChildren(&children);
  	if (XLogStandbyInfoActive())
  		nmsgs = xactGetCommittedInvalidationMessages(&invalMessages,
! 													 &RelcacheInitFileInval);
  	wrote_xlog = (XactLastRecEnd != 0);
  
  	/*
--- 1079,1094 ----
  	SharedInvalidationMessage *invalMessages = NULL;
  	bool		RelcacheInitFileInval = false;
  	bool		wrote_xlog;
+ 	PGAutonomousXACT * currentautox = NULL;
+ 
  
  	/* Get data needed for commit record */
  	nrels = smgrGetPendingDeletes(true, &rels);
  	nchildren = xactGetCommittedChildren(&children);
  	if (XLogStandbyInfoActive())
  		nmsgs = xactGetCommittedInvalidationMessages(&invalMessages,
! 													 &RelcacheInitFileInval,
! 													 isAutoXact);
  	wrote_xlog = (XactLastRecEnd != 0);
  
  	/*
***************
*** 1039,1045 **** RecordTransactionCommit(void)
  		 * assigned is a sequence advance record due to nextval() --- we want
  		 * to flush that to disk before reporting commit.)
  		 */
! 		if (!wrote_xlog)
  			goto cleanup;
  	}
  	else
--- 1116,1122 ----
  		 * assigned is a sequence advance record due to nextval() --- we want
  		 * to flush that to disk before reporting commit.)
  		 */
! 		if (!wrote_xlog || isAutoXact)
  			goto cleanup;
  	}
  	else
***************
*** 1068,1074 **** RecordTransactionCommit(void)
  		 * a bit fuzzy, but it doesn't matter.
  		 */
  		START_CRIT_SECTION();
! 		MyPgXact->delayChkpt = true;
  
  		SetCurrentTransactionStopTimestamp();
  
--- 1145,1159 ----
  		 * a bit fuzzy, but it doesn't matter.
  		 */
  		START_CRIT_SECTION();
! 		if(isAutoXact)
! 		{
! 			currentautox = GetCurrentPGAutonomousXACT();
! 			currentautox->delayChkpt = true;
! 		}
! 		else
! 		{
! 			MyPgXact->delayChkpt = true;
! 		}
  
  		SetCurrentTransactionStopTimestamp();
  
***************
*** 1229,1240 **** RecordTransactionCommit(void)
  	 */
  	if (markXidCommitted)
  	{
! 		MyPgXact->delayChkpt = false;
  		END_CRIT_SECTION();
  	}
  
  	/* Compute latestXid while we have the child XIDs handy */
  	latestXid = TransactionIdLatest(xid, nchildren, children);
  
  	/*
  	 * Wait for synchronous replication, if required.
--- 1314,1335 ----
  	 */
  	if (markXidCommitted)
  	{
! 		if(isAutoXact)
! 		{
! 			currentautox = GetCurrentPGAutonomousXACT();
! 			currentautox->delayChkpt = false;
! 		}
! 		else
! 		{
! 			MyPgXact->delayChkpt = false;
! 		}
  		END_CRIT_SECTION();
  	}
  
  	/* Compute latestXid while we have the child XIDs handy */
  	latestXid = TransactionIdLatest(xid, nchildren, children);
+ 	if (isAutoXact)
+ 		XidCacheRemoveAutoRunningXids(xid, nchildren, children, latestXid, true);
  
  	/*
  	 * Wait for synchronous replication, if required.
***************
*** 1246,1252 **** RecordTransactionCommit(void)
  		SyncRepWaitForLSN(XactLastRecEnd);
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
! 	XactLastRecEnd = 0;
  
  cleanup:
  	/* Clean up local data */
--- 1341,1348 ----
  		SyncRepWaitForLSN(XactLastRecEnd);
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
! 	if (!isAutoXact)
! 		XactLastRecEnd = 0;
  
  cleanup:
  	/* Clean up local data */
***************
*** 1542,1552 **** RecordTransactionAbort(bool isSubXact)
  	 * subxacts, because we already have the child XID array at hand.  For
  	 * main xacts, the equivalent happens just after this function returns.
  	 */
! 	if (isSubXact)
! 		XidCacheRemoveRunningXids(xid, nchildren, children, latestXid);
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
! 	if (!isSubXact)
  		XactLastRecEnd = 0;
  
  	/* And clean up local data */
--- 1638,1679 ----
  	 * subxacts, because we already have the child XID array at hand.  For
  	 * main xacts, the equivalent happens just after this function returns.
  	 */
! 	{
! 		uint8     isAutoTX = MyProc->inAutoTXLevel;
! 		PGAutonomousXACT *currentautox = NULL;
! 
! 		int	     autoNestingLevel = 0;
! 		int	     stateNestingLevel = CurrentTransactionState->nestingLevel;
! 
! 		if (isSubXact)
! 		{
! 			if (isAutoTX)
! 			{
! 				currentautox = GetCurrentPGAutonomousXACT();
! 				autoNestingLevel = currentautox->nestingLevel;
! 
! 				if(stateNestingLevel == autoNestingLevel)
! 				{
! 					/* the top of auto TX */
! 					XidCacheRemoveAutoRunningXids(xid, nchildren, children,
! 															latestXid, true);
! 				}
! 				else
! 				{
! 					/* sub TX in auto TX */
! 					XidCacheRemoveAutoRunningXids(xid, nchildren, children,
! 															latestXid, false);
! 				}
! 			}
! 			else
! 			{
! 				XidCacheRemoveRunningXids(xid, nchildren, children, latestXid);
! 			}
! 		}
! 	}
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
! 	if (!isSubXact )
  		XactLastRecEnd = 0;
  
  	/* And clean up local data */
***************
*** 1945,1951 **** CommitTransaction(void)
  	/*
  	 * Here is where we really truly commit.
  	 */
! 	latestXid = RecordTransactionCommit();
  
  	TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->lxid);
  
--- 2072,2078 ----
  	/*
  	 * Here is where we really truly commit.
  	 */
! 	latestXid = RecordTransactionCommit(false);
  
  	TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->lxid);
  
***************
*** 2525,2530 **** StartTransactionCommand(void)
--- 2652,2658 ----
  			 */
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			break;
  
  			/*
***************
*** 2537,2542 **** StartTransactionCommand(void)
--- 2665,2671 ----
  			 */
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
+ 		case TBLOCK_AUTOABORT:
  			break;
  
  			/* These cases are invalid. */
***************
*** 2553,2558 **** StartTransactionCommand(void)
--- 2682,2691 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 		case TBLOCK_AUTOABORT_END:
  			elog(ERROR, "StartTransactionCommand: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 2688,2694 **** CommitTransactionCommand(void)
  			} while (s->blockState == TBLOCK_SUBRELEASE);
  
  			Assert(s->blockState == TBLOCK_INPROGRESS ||
! 				   s->blockState == TBLOCK_SUBINPROGRESS);
  			break;
  
  			/*
--- 2821,2828 ----
  			} while (s->blockState == TBLOCK_SUBRELEASE);
  
  			Assert(s->blockState == TBLOCK_INPROGRESS ||
! 				   s->blockState == TBLOCK_SUBINPROGRESS ||
! 				   s->blockState == TBLOCK_AUTOINPROGRESS);
  			break;
  
  			/*
***************
*** 2719,2724 **** CommitTransactionCommand(void)
--- 2853,2863 ----
  				PrepareTransaction();
  				s->blockState = TBLOCK_DEFAULT;
  			}
+ 			else if (s->blockState == TBLOCK_AUTOCOMMIT)
+ 			{
+ 				Assert(s->parent != NULL);
+ 				CommitAutonomousTransaction();
+ 			}
  			else
  				elog(ERROR, "CommitTransactionCommand: unexpected state %s",
  					 BlockStateAsString(s->blockState));
***************
*** 2800,2805 **** CommitTransactionCommand(void)
--- 2939,2968 ----
  				s->blockState = TBLOCK_SUBINPROGRESS;
  			}
  			break;
+ 		case TBLOCK_AUTOBEGIN:
+ 			BeginAutonomousTransaction();
+ 			s->blockState = TBLOCK_AUTOINPROGRESS;
+ 			break;
+ 
+ 		case TBLOCK_AUTOCOMMIT:
+ 			CommitAutonomousTransaction();
+ 			break;
+ 
+ 		case TBLOCK_AUTOABORT:
+ 			break;
+ 
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 			AbortAutonomousTransaction();
+ 			CleanupSubTransaction();
+ 			break;
+ 
+ 		case TBLOCK_AUTOINPROGRESS:
+ 			CommandCounterIncrement();
+ 			break;
+ 
+ 		case TBLOCK_AUTOABORT_END:
+ 			CleanupSubTransaction();
+ 			break;
  	}
  }
  
***************
*** 2886,2891 **** AbortCurrentTransaction(void)
--- 3049,3055 ----
  			 */
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
+ 		case TBLOCK_AUTOABORT:
  			break;
  
  			/*
***************
*** 2952,2957 **** AbortCurrentTransaction(void)
--- 3116,3137 ----
  			CleanupSubTransaction();
  			AbortCurrentTransaction();
  			break;
+ 		case 	TBLOCK_AUTOBEGIN:
+ 		case 	TBLOCK_AUTOCOMMIT:
+ 		case 	TBLOCK_AUTOABORT_PENDING:
+ 			AbortAutonomousTransaction();
+ 			CleanupSubTransaction();
+ 			break;
+ 
+ 		case 	TBLOCK_AUTOINPROGRESS:
+ 			AbortAutonomousTransaction();
+ 			s->blockState = TBLOCK_AUTOABORT;
+ 			break;
+ 
+ 
+ 		case 	TBLOCK_AUTOABORT_END:
+ 			CleanupSubTransaction();
+ 			break;
  	}
  }
  
***************
*** 3255,3260 **** BeginTransactionBlock(void)
--- 3435,3442 ----
  		case TBLOCK_SUBINPROGRESS:
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 		case TBLOCK_AUTOABORT:
  			ereport(WARNING,
  					(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
  					 errmsg("there is already a transaction in progress")));
***************
*** 3274,3279 **** BeginTransactionBlock(void)
--- 3456,3465 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 		case TBLOCK_AUTOABORT_END:
  			elog(FATAL, "BeginTransactionBlock: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 3298,3303 **** PrepareTransactionBlock(char *gid)
--- 3484,3494 ----
  	TransactionState s;
  	bool		result;
  
+ 	if(MyProc->inAutoTXLevel)
+ 	{
+ 		elog(ERROR, "Can't support twophase transaction in autonomous transaction.");
+ 	}
+ 
  	/* Set up to commit the current transaction */
  	result = EndTransactionBlock();
  
***************
*** 3373,3379 **** EndTransactionBlock(void)
  			 * open subtransactions and then commit the main transaction.
  			 */
  		case TBLOCK_SUBINPROGRESS:
! 			while (s->parent != NULL)
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBCOMMIT;
--- 3564,3570 ----
  			 * open subtransactions and then commit the main transaction.
  			 */
  		case TBLOCK_SUBINPROGRESS:
! 			while (s->parent != NULL && !IS_TOP_AUTO_TX_STATE(s))
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBCOMMIT;
***************
*** 3384,3389 **** EndTransactionBlock(void)
--- 3575,3583 ----
  			}
  			if (s->blockState == TBLOCK_INPROGRESS)
  				s->blockState = TBLOCK_END;
+ 			else if(s->blockState == TBLOCK_AUTOINPROGRESS)
+ 				s->blockState = TBLOCK_AUTOCOMMIT;
+ 
  			else
  				elog(FATAL, "EndTransactionBlock: unexpected state %s",
  					 BlockStateAsString(s->blockState));
***************
*** 3396,3402 **** EndTransactionBlock(void)
  			 * transaction.
  			 */
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL)
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
--- 3590,3596 ----
  			 * transaction.
  			 */
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL && !IS_TOP_AUTO_TX_STATE(s))
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
***************
*** 3411,3416 **** EndTransactionBlock(void)
--- 3605,3615 ----
  				s->blockState = TBLOCK_ABORT_PENDING;
  			else if (s->blockState == TBLOCK_ABORT)
  				s->blockState = TBLOCK_ABORT_END;
+ 			else if(s->blockState == TBLOCK_AUTOINPROGRESS)
+ 				s->blockState = TBLOCK_AUTOABORT_PENDING;
+ 			else if(s->blockState == TBLOCK_AUTOABORT)
+ 				s->blockState = TBLOCK_AUTOABORT_END;
+ 
  			else
  				elog(FATAL, "EndTransactionBlock: unexpected state %s",
  					 BlockStateAsString(s->blockState));
***************
*** 3429,3434 **** EndTransactionBlock(void)
--- 3628,3642 ----
  			result = true;
  			break;
  
+ 		case TBLOCK_AUTOABORT:
+ 			s->blockState = TBLOCK_AUTOABORT_END;
+ 			break;
+ 
+ 		case TBLOCK_AUTOINPROGRESS:
+ 			s->blockState = TBLOCK_AUTOCOMMIT;
+ 			result = true;
+ 			break;
+ 
  			/* These cases are invalid. */
  		case TBLOCK_DEFAULT:
  		case TBLOCK_BEGIN:
***************
*** 3443,3448 **** EndTransactionBlock(void)
--- 3651,3660 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT_END:
+ 		case TBLOCK_AUTOABORT_PENDING:
  			elog(FATAL, "EndTransactionBlock: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 3489,3495 **** UserAbortTransactionBlock(void)
  			 */
  		case TBLOCK_SUBINPROGRESS:
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL)
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
--- 3701,3707 ----
  			 */
  		case TBLOCK_SUBINPROGRESS:
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL && !IS_TOP_AUTO_TX_STATE(s))
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
***************
*** 3504,3509 **** UserAbortTransactionBlock(void)
--- 3716,3726 ----
  				s->blockState = TBLOCK_ABORT_PENDING;
  			else if (s->blockState == TBLOCK_ABORT)
  				s->blockState = TBLOCK_ABORT_END;
+ 			else if(s->blockState == TBLOCK_AUTOINPROGRESS)
+ 				s->blockState = TBLOCK_AUTOABORT_PENDING;
+ 			else if(s->blockState == TBLOCK_AUTOABORT)
+ 				s->blockState = TBLOCK_AUTOABORT_END;
+ 
  			else
  				elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
  					 BlockStateAsString(s->blockState));
***************
*** 3521,3526 **** UserAbortTransactionBlock(void)
--- 3738,3750 ----
  					 errmsg("there is no transaction in progress")));
  			s->blockState = TBLOCK_ABORT_PENDING;
  			break;
+ 		case TBLOCK_AUTOABORT:
+ 			s->blockState = TBLOCK_AUTOABORT_END;
+ 			break;
+ 
+ 		case TBLOCK_AUTOINPROGRESS:
+ 			s->blockState = TBLOCK_AUTOABORT_PENDING;
+ 			break;
  
  			/* These cases are invalid. */
  		case TBLOCK_DEFAULT:
***************
*** 3536,3541 **** UserAbortTransactionBlock(void)
--- 3760,3769 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 		case TBLOCK_AUTOABORT_END:
+ 		case TBLOCK_AUTOCOMMIT:
  			elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 3555,3563 **** DefineSavepoint(char *name)
  	{
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_SUBINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction();
! 			s = CurrentTransactionState;		/* changed by push */
  
  			/*
  			 * Savepoint names, like the TransactionState block itself, live
--- 3783,3793 ----
  	{
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction(false);
! 
!  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
  			 * Savepoint names, like the TransactionState block itself, live
***************
*** 3584,3589 **** DefineSavepoint(char *name)
--- 3814,3824 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT:
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 		case TBLOCK_AUTOABORT_END:
  			elog(FATAL, "DefineSavepoint: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 3612,3617 **** ReleaseSavepoint(List *options)
--- 3847,3854 ----
  			 * defined.
  			 */
  		case TBLOCK_INPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 
  			ereport(ERROR,
  					(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  					 errmsg("no such savepoint")));
***************
*** 3641,3646 **** ReleaseSavepoint(List *options)
--- 3878,3889 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT:
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 		case TBLOCK_AUTOABORT_END:
+ 
  			elog(FATAL, "ReleaseSavepoint: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 3656,3668 **** ReleaseSavepoint(List *options)
  
  	Assert(PointerIsValid(name));
  
! 	for (target = s; PointerIsValid(target); target = target->parent)
  	{
  		if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
  			break;
  	}
  
! 	if (!PointerIsValid(target))
  		ereport(ERROR,
  				(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  				 errmsg("no such savepoint")));
--- 3899,3911 ----
  
  	Assert(PointerIsValid(name));
  
! 	for (target = s; PointerIsValid(target) && !IS_TOP_AUTO_TX_STATE(target); target = target->parent)
  	{
  		if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
  			break;
  	}
  
! 	if (!PointerIsValid(target) || (IS_TOP_AUTO_TX_STATE(target) && target->name == NULL))
  		ereport(ERROR,
  				(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  				 errmsg("no such savepoint")));
***************
*** 3713,3718 **** RollbackToSavepoint(List *options)
--- 3956,3964 ----
  			 */
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_ABORT:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 		case TBLOCK_AUTOABORT:
+ 
  			ereport(ERROR,
  					(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  					 errmsg("no such savepoint")));
***************
*** 3740,3745 **** RollbackToSavepoint(List *options)
--- 3986,3995 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 		case TBLOCK_AUTOABORT_END:
  			elog(FATAL, "RollbackToSavepoint: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 3755,3767 **** RollbackToSavepoint(List *options)
  
  	Assert(PointerIsValid(name));
  
! 	for (target = s; PointerIsValid(target); target = target->parent)
  	{
  		if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
  			break;
  	}
  
! 	if (!PointerIsValid(target))
  		ereport(ERROR,
  				(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  				 errmsg("no such savepoint")));
--- 4005,4017 ----
  
  	Assert(PointerIsValid(name));
  
! 	for (target = s; PointerIsValid(target) && !IS_TOP_AUTO_TX_STATE(target); target = target->parent)
  	{
  		if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
  			break;
  	}
  
! 	if (!PointerIsValid(target)||(IS_TOP_AUTO_TX_STATE(target)&& target->name == NULL))
  		ereport(ERROR,
  				(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  				 errmsg("no such savepoint")));
***************
*** 3824,3831 **** BeginInternalSubTransaction(char *name)
  		case TBLOCK_END:
  		case TBLOCK_PREPARE:
  		case TBLOCK_SUBINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction();
  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
--- 4074,4082 ----
  		case TBLOCK_END:
  		case TBLOCK_PREPARE:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction(false);
  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
***************
*** 3850,3855 **** BeginInternalSubTransaction(char *name)
--- 4101,4111 ----
  		case TBLOCK_SUBABORT_PENDING:
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT:
+ 		case TBLOCK_AUTOABORT_END:
+ 		case TBLOCK_AUTOABORT_PENDING:
  			elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 3917,3922 **** RollbackAndReleaseCurrentSubTransaction(void)
--- 4173,4184 ----
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOABORT:
+ 		case TBLOCK_AUTOABORT_END:
+ 		case TBLOCK_AUTOABORT_PENDING:
  			elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
  				 BlockStateAsString(s->blockState));
  			break;
***************
*** 4015,4020 **** AbortOutOfAnyTransaction(void)
--- 4277,4297 ----
  				CleanupSubTransaction();
  				s = CurrentTransactionState;	/* changed by pop */
  				break;
+ 			case TBLOCK_AUTOBEGIN:
+ 			case TBLOCK_AUTOINPROGRESS:
+ 			case TBLOCK_AUTOCOMMIT:
+ 			case TBLOCK_AUTOABORT_PENDING:
+ 				AbortAutonomousTransaction();
+ 				CleanupSubTransaction();
+ 				s = CurrentTransactionState;	/* changed by pop */
+ 				break;
+ 
+ 			case TBLOCK_AUTOABORT:
+ 			case TBLOCK_AUTOABORT_END:
+ 				/* As above, but AbortSubTransaction already done */
+ 				CleanupSubTransaction();
+ 				s = CurrentTransactionState;	/* changed by pop */
+ 				break;
  		}
  	} while (s->blockState != TBLOCK_DEFAULT);
  
***************
*** 4075,4080 **** TransactionBlockStatusCode(void)
--- 4352,4360 ----
  		case TBLOCK_SUBRELEASE:
  		case TBLOCK_SUBCOMMIT:
  		case TBLOCK_PREPARE:
+ 		case TBLOCK_AUTOBEGIN:
+ 		case TBLOCK_AUTOCOMMIT:
+ 		case TBLOCK_AUTOINPROGRESS:
  			return 'T';			/* in transaction */
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
***************
*** 4084,4089 **** TransactionBlockStatusCode(void)
--- 4364,4372 ----
  		case TBLOCK_SUBABORT_PENDING:
  		case TBLOCK_SUBRESTART:
  		case TBLOCK_SUBABORT_RESTART:
+ 		case TBLOCK_AUTOABORT:
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 		case TBLOCK_AUTOABORT_END:
  			return 'E';			/* in failed transaction */
  	}
  
***************
*** 4398,4404 **** CleanupSubTransaction(void)
  
  	ShowTransactionState("CleanupSubTransaction");
  
! 	if (s->state != TRANS_ABORT)
  		elog(WARNING, "CleanupSubTransaction while in %s state",
  			 TransStateAsString(s->state));
  
--- 4681,4687 ----
  
  	ShowTransactionState("CleanupSubTransaction");
  
! 	if (s->state != TRANS_ABORT && !IS_TOP_AUTO_TX_STATE(s))
  		elog(WARNING, "CleanupSubTransaction while in %s state",
  			 TransStateAsString(s->state));
  
***************
*** 4425,4434 **** CleanupSubTransaction(void)
   *	if it has a local pointer to it after calling this function.
   */
  static void
! PushTransaction(void)
  {
  	TransactionState p = CurrentTransactionState;
  	TransactionState s;
  
  	/*
  	 * We keep subtransaction state nodes in TopTransactionContext.
--- 4708,4718 ----
   *	if it has a local pointer to it after calling this function.
   */
  static void
! PushTransaction(bool isAutoTX)
  {
  	TransactionState p = CurrentTransactionState;
  	TransactionState s;
+ 	PGAutonomousXACT *currentautotx = NULL;
  
  	/*
  	 * We keep subtransaction state nodes in TopTransactionContext.
***************
*** 4461,4470 **** PushTransaction(void)
  	s->gucNestLevel = NewGUCNestLevel();
  	s->savepointLevel = p->savepointLevel;
  	s->state = TRANS_DEFAULT;
- 	s->blockState = TBLOCK_SUBBEGIN;
  	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
  	s->prevXactReadOnly = XactReadOnly;
  
  	CurrentTransactionState = s;
  
  	/*
--- 4745,4766 ----
  	s->gucNestLevel = NewGUCNestLevel();
  	s->savepointLevel = p->savepointLevel;
  	s->state = TRANS_DEFAULT;
  	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
  	s->prevXactReadOnly = XactReadOnly;
  
+ 	if (isAutoTX)
+ 	{
+ 		MyProc->inAutoTXLevel++;
+ 		currentautotx = GetCurrentPGAutonomousXACT();
+ 		currentautotx->nestingLevel = s->nestingLevel;
+ 		s->blockState = TBLOCK_AUTOBEGIN;
+ 	}
+ 	else
+ 	{
+ 		s->blockState = TBLOCK_SUBBEGIN;
+ 	}
+ 
+ 
  	CurrentTransactionState = s;
  
  	/*
***************
*** 4486,4491 **** static void
--- 4782,4788 ----
  PopTransaction(void)
  {
  	TransactionState s = CurrentTransactionState;
+ 	PGAutonomousXACT *currentautox = NULL;
  
  	if (s->state != TRANS_DEFAULT)
  		elog(WARNING, "PopTransaction while in %s state",
***************
*** 4504,4509 **** PopTransaction(void)
--- 4801,4815 ----
  	CurTransactionResourceOwner = s->parent->curTransactionOwner;
  	CurrentResourceOwner = s->parent->curTransactionOwner;
  
+ 	if(IS_TOP_AUTO_TX_STATE(s))
+ 	{
+ 		currentautox = GetCurrentPGAutonomousXACT();
+ 	/*lint -e506 -e681  */
+ 		MemSet(currentautox, 0, sizeof(PGAutonomousXACT));
+ 	/*lint +e506 +e681  */
+ 		MyProc->inAutoTXLevel--;
+ 	}
+ 
  	/* Free the old child structure */
  	if (s->name)
  		pfree(s->name);
***************
*** 4608,4613 **** BlockStateAsString(TBlockState blockState)
--- 4914,4931 ----
  			return "SUB RESTART";
  		case TBLOCK_SUBABORT_RESTART:
  			return "SUB AB RESTRT";
+ 		case TBLOCK_AUTOINPROGRESS:
+ 			return "AUTO INPROGRESS";
+ 		case TBLOCK_AUTOBEGIN:
+ 			return "AUTO BEGIN";
+ 		case TBLOCK_AUTOCOMMIT:
+ 			return "AUTO COMMIT";
+ 		case TBLOCK_AUTOABORT:
+ 			return "AUTO ABORT";
+ 		case TBLOCK_AUTOABORT_END:
+ 			return "AUTO ABORT END";
+ 		case TBLOCK_AUTOABORT_PENDING:
+ 			return "AUTO ABORT PENDING";
  	}
  	return "UNRECOGNIZED";
  }
***************
*** 4980,4982 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
--- 5298,5858 ----
  	else
  		elog(PANIC, "xact_redo: unknown op code %u", info);
  }
+ 
+ 
+ void
+ DefineAutonomousTransaction(void)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 
+ 	if (MyProc->inAutoTXLevel >= MAX_AUTOX_NESTING_LEVEL)
+ 		ereport(ERROR,
+ 				(errmsg("Has reach the max autonomous nesting level.")));
+ 	switch (s->blockState)
+ 	{
+ 		case TBLOCK_INPROGRESS:
+ 		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_STARTED:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 			/* Normal subtransaction start */
+ 			PushTransaction(true);
+ 			break;
+ 
+ 			/* These cases are invalid. */
+ 
+ 		default:
+ 			ereport(FATAL,
+ 				(errmsg("DefineAutonomousTransaction: unexpected state %s",
+ 						BlockStateAsString(s->blockState))));
+ 			break;
+ 	}
+ }
+ 
+ void
+ BeginAutonomousTransaction(void)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 
+ 	if (s->state != TRANS_DEFAULT)
+ 		ereport(WARNING,
+ 				(errmsg("BeginAutonomousTransaction while in %s state",
+ 			 	TransStateAsString(s->state))));
+ 
+ 	s->state = TRANS_START;
+ 
+ 	/*
+ 	 * Initialize subsystems for new subtransaction
+ 	 *
+ 	 * must initialize resource-management stuff first
+ 	 */
+ 	AtSubStart_Memory();
+ 	AtSubStart_ResourceOwner();
+ 	AtSubStart_Inval();
+ 	AtSubStart_Notify();
+ 	AfterTriggerBeginSubXact();
+ 
+ 	s->state = TRANS_INPROGRESS;
+ 
+ 	/*
+ 	 * Call start-of-subxact callbacks
+ 	 */
+ 	CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
+ 						 s->parent->subTransactionId);
+ 
+ 	ShowTransactionState("BeginAutonomousTransaction");
+ }
+ 
+ void
+ CommitAutonomousTransaction(void)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 	TransactionId latestXid;
+ 	ShowTransactionState("CommitAutonomousTransaction");
+ 
+ 	if (s->state != TRANS_INPROGRESS)
+ 		ereport(WARNING,
+ 				(errmsg("CommitAutonomousTransaction while in %s state",
+ 				 TransStateAsString(s->state))));
+ 
+ 	/*
+ 	 * Prior to 8.4 we marked subcommit in clog at this point.	We now only
+ 	 * perform that step, if required, as part of the atomic update of the
+ 	 * whole transaction tree at top level commit or abort.
+ 	 */
+ 	for (;;)
+ 	{
+ 		/*
+ 		 * Fire all currently pending deferred triggers.
+ 		 */
+ 		AfterTriggerFireDeferredForAutoX();
+ 
+ 		/*
+ 		 * Close open portals (converting holdable ones into static portals).
+ 		 * If there weren't any, we are done ... otherwise loop back to check
+ 		 * if they queued deferred triggers.  Lather, rinse, repeat.
+ 		 */
+ 		if (!AutoPreCommit_Portals(s->subTransactionId))
+ 			break;
+ 	}
+ 
+ 
+ 
+ 	AfterTriggerEndSubXact(false);
+ 
+ 	AtSubCommit_Portals(s->subTransactionId,
+ 						s->parent->subTransactionId,
+ 						s->parent->curTransactionOwner);
+ 
+ 	PreCommit_on_commit_actions();
+ 	AtEOSubXact_LargeObject(false, s->subTransactionId,
+ 							s->parent->subTransactionId);
+ 	AtSubAbort_Notify();
+ 
+ 	/* Prevent cancel/die interrupt while cleaning up */
+ 	HOLD_INTERRUPTS();
+ 
+ 	s->state = TRANS_COMMIT;
+ 	/* Advertise the fact that we aborted in pg_clog. */
+ 	latestXid = RecordTransactionCommit(true);
+ 	ProcArrayEndAutonomousTransaction(MyProc, latestXid);
+ 	/* Post-commit cleanup */
+ 	if (TransactionIdIsValid(s->transactionId))
+ 		AtSubAbort_childXids();
+ 
+ 	CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
+ 						 s->parent->subTransactionId);
+ 
+ 	ResourceOwnerRelease(s->curTransactionOwner,
+ 						 RESOURCE_RELEASE_BEFORE_LOCKS,
+ 						 false, false);
+ 	AtEOSubXact_RelationCache(false, s->subTransactionId,
+ 							  s->parent->subTransactionId);
+ 	AtEOAutoXact_Inval(true);
+ 	smgrDoPendingDeletes(true);
+ 	/*
+ 	 * The only lock we actually release here is the subtransaction XID lock.
+ 	 */
+ 	CurrentResourceOwner = s->curTransactionOwner;
+ 	if (TransactionIdIsValid(s->transactionId))
+ 		XactLockTableDelete(s->transactionId);
+ 
+ 	/*
+ 	 * Other locks should get transferred to their parent resource owner.
+ 	 */
+ 	ResourceOwnerRelease(s->curTransactionOwner,
+ 						 RESOURCE_RELEASE_LOCKS,
+ 						 false, false);
+ 	ResourceOwnerRelease(s->curTransactionOwner,
+ 						 RESOURCE_RELEASE_AFTER_LOCKS,
+ 						 false, false);
+ 
+ 	AtEOXact_GUC(true, s->gucNestLevel);
+ 	AtEOSubXact_SPI(true, s->subTransactionId);
+ 	AtEOSubXact_on_commit_actions(false, s->subTransactionId,
+ 								  s->parent->subTransactionId);
+ 	AtEOAutoXact_Namespace(true, s->subTransactionId,
+ 						  s->parent->subTransactionId);
+ 	AtEOSubXact_Files(false, s->subTransactionId,
+ 					  s->parent->subTransactionId);
+ 	AtEOSubXact_HashTables(true, s->nestingLevel);
+ 	AtEOSubXact_PgStat(false, s->nestingLevel);
+ 	AtSubAbort_Snapshot(s->nestingLevel);
+ 
+ 	/*
+ 	 * We need to restore the upper transaction's read-only state, in case the
+ 	 * upper is read-write while the child is read-only; GUC will incorrectly
+ 	 * think it should leave the child state in place.
+ 	 */
+ 	XactReadOnly = s->prevXactReadOnly;
+ 	CleanupSubTransaction();
+ 
+ 	RESUME_INTERRUPTS();
+ }
+ 
+ void
+ AbortAutonomousTransaction(void)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 	TransactionId latestXid;
+ 
+ 	/* Prevent cancel/die interrupt while cleaning up */
+ 	HOLD_INTERRUPTS();
+ 
+ 	/* Make sure we have a valid memory context and resource owner */
+ 	AtSubAbort_Memory();
+ 	AtSubAbort_ResourceOwner();
+ 
+ 	/*
+ 	 * Release any LW locks we might be holding as quickly as possible.
+ 	 * (Regular locks, however, must be held till we finish aborting.)
+ 	 * Releasing LW locks is critical since we might try to grab them again
+ 	 * while cleaning up!
+ 	 *
+ 	 * FIXME This may be incorrect --- Are there some locks we should keep?
+ 	 * Buffer locks, for example?  I don't think so but I'm not sure.
+ 	 */
+ 	LWLockReleaseAll();
+ 
+ 	AbortBufferIO();
+ 	UnlockBuffers();
+ 
+ 	LockErrorCleanup();
+ 
+ 	/*
+ 	 * check the current transaction state
+ 	 */
+ 	ShowTransactionState("AbortInternalAutonomousTransaction");
+ 
+ 	if (s->state != TRANS_INPROGRESS)
+ 		ereport(WARNING,
+ 				(errmsg("AbortInternalAutonomousTransaction while in %s state",
+ 			 	TransStateAsString(s->state))));
+ 	s->state = TRANS_ABORT;
+ 
+ 	/*
+ 	 * Reset user ID which might have been changed transiently.  (See notes in
+ 	 * AbortTransaction.)
+ 	 */
+ 	SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
+ 
+ 	/*
+ 	 * We can skip all this stuff if the subxact failed before creating a
+ 	 * ResourceOwner...
+ 	 */
+ 	if (s->curTransactionOwner)
+ 	{
+ 		AfterTriggerEndSubXact(false);
+ 		AtSubAbort_Portals(s->subTransactionId,
+ 						   s->parent->subTransactionId,
+ 						   s->parent->curTransactionOwner);
+ 		AtEOSubXact_LargeObject(false, s->subTransactionId,
+ 								s->parent->subTransactionId);
+ 		AtSubAbort_Notify();
+ 
+ 		/* Advertise the fact that we aborted in pg_clog. */
+ 		latestXid = RecordTransactionAbort(true);
+ 		ProcArrayEndAutonomousTransaction(MyProc, latestXid);
+ 		/* Post-abort cleanup */
+ 		if (TransactionIdIsValid(s->transactionId))
+ 			AtSubAbort_childXids();
+ 
+ 		CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
+ 							 s->parent->subTransactionId);
+ 
+ 		ResourceOwnerRelease(s->curTransactionOwner,
+ 							 RESOURCE_RELEASE_BEFORE_LOCKS,
+ 							 false, false);
+ 		AtEOSubXact_RelationCache(false, s->subTransactionId,
+ 								  s->parent->subTransactionId);
+ 		AtEOAutoXact_Inval(false);
+ 		AtSubAbort_smgr();
+ 		ResourceOwnerRelease(s->curTransactionOwner,
+ 							 RESOURCE_RELEASE_LOCKS,
+ 							 false, false);
+ 		ResourceOwnerRelease(s->curTransactionOwner,
+ 							 RESOURCE_RELEASE_AFTER_LOCKS,
+ 							 false, false);
+ 
+ 		AtEOXact_GUC(false, s->gucNestLevel);
+ 		AtEOSubXact_SPI(true, s->subTransactionId);
+ 		AtEOSubXact_on_commit_actions(false, s->subTransactionId,
+ 									  s->parent->subTransactionId);
+ 		AtEOAutoXact_Namespace(false, s->subTransactionId,
+ 							  s->parent->subTransactionId);
+ 		AtEOSubXact_Files(false, s->subTransactionId,
+ 						  s->parent->subTransactionId);
+ 		AtEOSubXact_HashTables(false, s->nestingLevel);
+ 		AtEOSubXact_PgStat(false, s->nestingLevel);
+ 		AtSubAbort_Snapshot(s->nestingLevel);
+ 	}
+ 
+ 	/*
+ 	 * Restore the upper transaction's read-only state, too.  This should be
+ 	 * redundant with GUC's cleanup but we may as well do it for consistency
+ 	 * with the commit case.
+ 	 */
+ 	XactReadOnly = s->prevXactReadOnly;
+ 
+ 	RESUME_INTERRUPTS();
+ }
+ 
+ /*
+  * Brief: PLpgSQL_SetPreContextAndResource
+  * save the previous memory context and resource owner
+  * Param: preContext
+  * Param: preOwner
+  */
+ void
+ PLpgSQL_SetPreContextAndResource(MemoryContext preContext,ResourceOwner preOwner)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 
+ 	if (s)
+ 	{
+ 		s->preMemoryContext = preContext;
+ 		s->preResourceOwner = preOwner;
+ 	}
+ }
+ 
+ /*
+  * Brief: PLpgSQL_GetPreContextAndResource
+  * get  the previous memory context and resource owner
+  * Param: preContext
+  * Param: preOwner
+  */
+ static void
+ PLpgSQL_GetPreContextAndResource(MemoryContext *preContext,ResourceOwner *preOwner)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 
+ 	if (s)
+ 	{
+ 		*preContext = s->preMemoryContext;
+ 		*preOwner = s->preResourceOwner;
+ 	}
+ 	else
+ 	{
+ 		*preContext = NULL;
+ 		*preOwner = NULL;
+ 	}
+ }
+ 
+ /*****************************************************************************
+   Description    : BeginInternalAutonomousTransaction()
+   				   CommitInternalAutonomousTransaction()
+   				   AbortInternalAutonomousTransaction()
+   				   There fuctions are used to manage a internal autonomous
+   				   transaction.
+   Input          :
+   Output         :
+   Return Value   : void
+   Notes          : when use autonomous transaction internal, you should use
+   				   those functions with a block around PG_TRY()PG_CATCH()
+ 				   example:
+ 					BeginInternalAutonomousTransaction();
+ 					PG_TRY();
+ 					{
+ 						...
+ 						CommitInternalAutonomousTransaction();
+ 					}
+ 					PG_CATCH();
+ 					{
+ 						...
+ 
+ 						*Notice:
+ 						*if use PG_RE_THROW() to throw the error to the next outer
+ 						*setjmp handler, we shouldn't  call EmitErrorReport()and
+ 						*FlushErrorState().
+ 
+ 						EmitErrorReport();
+ 
+ 						AbortInternalAutonomousTransaction();
+ 
+ 						FlushErrorState();
+ 						...
+ 						*PG_RE_THROW();*
+ 					}
+ 					PG_END_TRY();
+   History        :
+ 	Modification :
+ *****************************************************************************/
+ void
+ BeginInternalAutonomousTransaction(void)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 	MemoryContext oldContext = CurrentMemoryContext;
+ 	ResourceOwner oldOwner = CurrentResourceOwner;
+ 
+ 	switch (s->blockState)
+ 	{
+ 		case TBLOCK_STARTED:
+ 		case TBLOCK_INPROGRESS:
+ 		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 			/* Normal subtransaction start */
+ 			PushTransaction(true);
+ 			break;
+ 
+ 			/* These cases are invalid. */
+ 
+ 		default:
+ 			ereport(FATAL,
+ 					(errmsg("DefineAutonomousTransaction: unexpected state %s",
+ 				 BlockStateAsString(s->blockState))));
+ 			break;
+ 	}
+ 	CommitTransactionCommand();
+ 	StartTransactionCommand();
+ 	PLpgSQL_SetPreContextAndResource(oldContext, oldOwner);
+ 	(void)MemoryContextSwitchTo(oldContext);
+ }
+ 
+ /*****************************************************************************
+   Description    : When commit the autonomous transaction, it would not transfer
+   				   resources taken previously to its parent transaction, but
+   				   release all of them.
+   Input          :
+   Output         :
+   Return Value   : TransactionId
+   Notes          :
+   History        :
+ 	Modification :
+ *****************************************************************************/
+ void
+ CommitInternalAutonomousTransaction(void)
+ {
+ 	TransactionState s = NULL;
+ 	MemoryContext	preContext  = NULL;
+ 	ResourceOwner	preOwner    = NULL;
+ 	s = CurrentTransactionState;
+ 	PLpgSQL_GetPreContextAndResource(&preContext,&preOwner);
+ 
+ 	switch (s->blockState)
+ 	{
+ 		/*
+ 		 * We are in a live subtransaction block.  Set up to subcommit all
+ 		 * open subtransactions and then commit the main transaction.
+ 		 */
+ 		case TBLOCK_SUBINPROGRESS:
+ 			while (s->parent != NULL && !IS_TOP_AUTO_TX_STATE(s))
+ 			{
+ 				if (s->blockState == TBLOCK_SUBINPROGRESS)
+ 					s->blockState = TBLOCK_SUBCOMMIT;
+ 				else
+ 					ereport(FATAL,
+ 						(errmsg("EndAutonomousTransactionBlock: unexpected state %s",
+ 						 BlockStateAsString(s->blockState))));
+ 				s = s->parent;
+ 			}
+ 			if(s->blockState == TBLOCK_AUTOINPROGRESS)
+ 				s->blockState = TBLOCK_AUTOCOMMIT;
+ 			else
+ 				ereport(FATAL,
+ 					(errmsg("EndAutonomousTransactionBlock: unexpected state %s",
+ 					 BlockStateAsString(s->blockState))));
+ 			break;
+ 
+ 			/*
+ 			 * Here we are inside an aborted subtransaction.  Treat the COMMIT
+ 			 * as ROLLBACK: set up to abort everything and exit the main
+ 			 * transaction.
+ 			 */
+ 		case TBLOCK_SUBABORT:
+ 			while (s->parent != NULL && !IS_TOP_AUTO_TX_STATE(s))
+ 			{
+ 				if (s->blockState == TBLOCK_SUBINPROGRESS)
+ 					s->blockState = TBLOCK_SUBABORT_PENDING;
+ 				else if (s->blockState == TBLOCK_SUBABORT)
+ 					s->blockState = TBLOCK_SUBABORT_END;
+ 				else
+ 					ereport(FATAL,
+ 						(errmsg("EndAutonomousTransactionBlock: unexpected state %s",
+ 						 BlockStateAsString(s->blockState))));
+ 				s = s->parent;
+ 			}
+ 			if(s->blockState == TBLOCK_AUTOINPROGRESS)
+ 				s->blockState = TBLOCK_AUTOABORT_PENDING;
+ 			else if(s->blockState == TBLOCK_AUTOABORT)
+ 				s->blockState = TBLOCK_AUTOABORT_END;
+ 			else
+ 				ereport(FATAL,
+ 					(errmsg("EndAutonomousTransactionBlock: unexpected state %s",
+ 					 BlockStateAsString(s->blockState))));
+ 			break;
+ 
+ 		case TBLOCK_AUTOABORT:
+ 			s->blockState = TBLOCK_AUTOABORT_END;
+ 			break;
+ 
+ 		case TBLOCK_AUTOINPROGRESS:
+ 			s->blockState = TBLOCK_AUTOCOMMIT;
+ 			break;
+ 
+ 			/* These cases are invalid. */
+ 
+ 		default:
+ 			ereport(FATAL,
+ 					(errmsg("EndAutonomousTransactionBlock: unexpected state %s",
+ 					 BlockStateAsString(s->blockState))));
+ 			break;
+ 	}
+ 
+ 	CommitTransactionCommand();
+ 	if (preContext)
+ 		(void)MemoryContextSwitchTo(preContext);
+ 
+ 		/* if exist previous resource owner , restore it */
+ 	if (preOwner)
+ 		CurrentResourceOwner = preOwner;
+ 
+ }
+ 
+ void
+ AbortInternalAutonomousTransaction(void)
+ {
+ 
+ 	TransactionState s = CurrentTransactionState;
+ 	MemoryContext	preContext  = NULL;
+ 	ResourceOwner	preOwner    = NULL;
+ 	PLpgSQL_GetPreContextAndResource(&preContext,&preOwner);
+ 
+ 	switch (s->blockState)
+ 	{
+ 		case 	TBLOCK_AUTOBEGIN:
+ 		case 	TBLOCK_AUTOCOMMIT:
+ 		case 	TBLOCK_AUTOABORT_PENDING:
+ 		case 	TBLOCK_AUTOINPROGRESS:
+ 				AbortAutonomousTransaction();
+ 				break;
+ 
+ 		case 	TBLOCK_AUTOABORT:
+ 		case 	TBLOCK_AUTOABORT_END:
+ 				break;
+ 
+ 		default:
+ 			ereport(FATAL,
+ 				(errmsg("AbortautonomousTransactionBlock: unexpected state %s",
+ 				 BlockStateAsString(s->blockState))));
+ 	}
+ 	CleanupSubTransaction();
+ 
+ 				/* if exist previous memory context , restore it */
+ 	if (preContext)
+ 		(void)MemoryContextSwitchTo(preContext);
+ 
+ 		/* if exist previous resource owner , restore it */
+ 	if (preOwner)
+ 		CurrentResourceOwner = preOwner;
+ }
+ 
+ TransactionId GetTopAutonomousTransactionID(void)
+ {
+ 	TransactionId result = InvalidTransactionId;
+ 	TransactionState s = CurrentTransactionState;
+ 	TransactionState target;
+ 	for (target = s; PointerIsValid(target); target = target->parent)
+ 	{
+ 		 if(IS_TOP_AUTO_TX_STATE(target))
+ 		 {
+ 			if (!TransactionIdIsValid(target->transactionId))
+ 			{
+ 				AssignTransactionId(target);
+ 			}
+ 			result = target->transactionId;
+ 			return result;
+ 		 }
+ 
+ 	}
+ 	if (!TransactionIdIsValid(result))
+ 		ereport(ERROR,
+ 			(errmsg("Not in a autonomous transaction")));
+ 
+ 	return result;
+ }
+ 
+ bool IsCurrentAutoTx()
+ {
+ 	return IS_TOP_AUTO_TX_STATE(CurrentTransactionState);
+ }
+ 
+ 
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 3789,3794 **** AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
--- 3789,3843 ----
  	}
  }
  
+ void
+ AtEOAutoXact_Namespace(bool isCommit, SubTransactionId mySubid,
+ 					  SubTransactionId parentSubid)
+ {
+ 	OverrideStackEntry *entry;
+ 
+ 	if ((myTempNamespaceSubID == mySubid) && !isCommit)
+ 	{
+ 			myTempNamespaceSubID = InvalidSubTransactionId;
+ 			/* TEMP namespace creation failed, so reset state */
+ 			myTempNamespace = InvalidOid;
+ 			myTempToastNamespace = InvalidOid;
+ 			baseSearchPathValid = false;		/* need to rebuild list */
+ 	}
+ 
+ 	/*
+ 	 * Clean up if someone failed to do PopOverrideSearchPath
+ 	 */
+ 	while (overrideStack)
+ 	{
+ 		entry = (OverrideStackEntry *) linitial(overrideStack);
+ 		if (entry->nestLevel < GetCurrentTransactionNestLevel())
+ 			break;
+ 		if (isCommit)
+ 			ereport(WARNING,
+ 				(errmsg("leaked override search path")));
+ 		overrideStack = list_delete_first(overrideStack);
+ 		list_free(entry->searchPath);
+ 		pfree(entry);
+ 	}
+ 
+ 	/* Activate the next level down. */
+ 	if (overrideStack)
+ 	{
+ 		entry = (OverrideStackEntry *) linitial(overrideStack);
+ 		activeSearchPath = entry->searchPath;
+ 		activeCreationNamespace = entry->creationNamespace;
+ 		activeTempCreationPending = false;		/* XXX is this OK? */
+ 	}
+ 	else
+ 	{
+ 		/* If not baseSearchPathValid, this is useless but harmless */
+ 		activeSearchPath = baseSearchPath;
+ 		activeCreationNamespace = baseCreationNamespace;
+ 		activeTempCreationPending = baseTempCreationPending;
+ 	}
+ }
+ 
+ 
  /*
   * Remove all relations in the specified temp namespace.
   *
*** a/src/backend/commands/sequence.c
--- b/src/backend/commands/sequence.c
***************
*** 975,981 **** open_share_lock(SeqTable seq)
  		currentOwner = CurrentResourceOwner;
  		PG_TRY();
  		{
! 			CurrentResourceOwner = TopTransactionResourceOwner;
  			LockRelationOid(seq->relid, AccessShareLock);
  		}
  		PG_CATCH();
--- 975,985 ----
  		currentOwner = CurrentResourceOwner;
  		PG_TRY();
  		{
! 			if(!MyProc->inAutoTXLevel)
! 			{
! 				CurrentResourceOwner = TopTransactionResourceOwner;
! 			}
! 
  			LockRelationOid(seq->relid, AccessShareLock);
  		}
  		PG_CATCH();
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 88,93 ****
--- 88,94 ----
  #include "utils/syscache.h"
  #include "utils/tqual.h"
  #include "utils/typcache.h"
+ #include "storage/proc.h"
  
  
  /*
***************
*** 107,112 **** typedef struct OnCommitItem
--- 108,116 ----
  	 */
  	SubTransactionId creating_subid;
  	SubTransactionId deleting_subid;
+ 
+ 	TransactionId	toptxid;	/* top tx id */
+ 
  } OnCommitItem;
  
  static List *on_commits = NIL;
***************
*** 10794,10799 **** PreCommit_on_commit_actions(void)
--- 10798,10805 ----
  				/* Do nothing (there shouldn't be such entries, actually) */
  				break;
  			case ONCOMMIT_DELETE_ROWS:
+ 				if (MyProc->inAutoTXLevel)
+ 					break;
  
  				/*
  				 * If this transaction hasn't accessed any temporary
***************
*** 10807,10812 **** PreCommit_on_commit_actions(void)
--- 10813,10821 ----
  				{
  					ObjectAddress object;
  
+ 					if (GetTopTransactionId() != oc->toptxid)
+ 						break;
+ 
  					object.classId = RelationRelationId;
  					object.objectId = oc->relid;
  					object.objectSubId = 0;
*** a/src/backend/commands/trigger.c
--- b/src/backend/commands/trigger.c
***************
*** 57,63 ****
  #include "utils/syscache.h"
  #include "utils/tqual.h"
  #include "utils/tuplestore.h"
! 
  
  /* GUC variables */
  int			SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
--- 57,63 ----
  #include "utils/syscache.h"
  #include "utils/tqual.h"
  #include "utils/tuplestore.h"
! #include "storage/proc.h"
  
  /* GUC variables */
  int			SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
***************
*** 3678,3694 **** AfterTriggerExecute(AfterTriggerEvent event,
  static bool
  afterTriggerMarkEvents(AfterTriggerEventList *events,
  					   AfterTriggerEventList *move_list,
! 					   bool immediate_only)
  {
  	bool		found = false;
  	AfterTriggerEvent event;
  	AfterTriggerEventChunk *chunk;
  
  	for_each_event_chunk(event, chunk, *events)
  	{
  		AfterTriggerShared evtshared = GetTriggerSharedData(event);
  		bool		defer_it = false;
  
  		if (!(event->ate_flags &
  			  (AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS)))
  		{
--- 3678,3700 ----
  static bool
  afterTriggerMarkEvents(AfterTriggerEventList *events,
  					   AfterTriggerEventList *move_list,
! 					   bool immediate_only, bool inAutoX)
  {
  	bool		found = false;
  	AfterTriggerEvent event;
  	AfterTriggerEventChunk *chunk;
+ 	int			my_level = GetCurrentTransactionNestLevel();
  
  	for_each_event_chunk(event, chunk, *events)
  	{
  		AfterTriggerShared evtshared = GetTriggerSharedData(event);
  		bool		defer_it = false;
  
+ 		if ((inAutoX) && (chunk == events->head) && ((char *)event < afterTriggers->events_stack[my_level].tailfree))
+ 		{
+ 			continue;
+ 		}
+ 
  		if (!(event->ate_flags &
  			  (AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS)))
  		{
***************
*** 3751,3757 **** static bool
  afterTriggerInvokeEvents(AfterTriggerEventList *events,
  						 CommandId firing_id,
  						 EState *estate,
! 						 bool delete_ok)
  {
  	bool		all_fired = true;
  	AfterTriggerEventChunk *chunk;
--- 3757,3764 ----
  afterTriggerInvokeEvents(AfterTriggerEventList *events,
  						 CommandId firing_id,
  						 EState *estate,
! 						 bool delete_ok,
! 						 bool inAutoX)
  {
  	bool		all_fired = true;
  	AfterTriggerEventChunk *chunk;
***************
*** 3763,3768 **** afterTriggerInvokeEvents(AfterTriggerEventList *events,
--- 3770,3776 ----
  	Instrumentation *instr = NULL;
  	TupleTableSlot *slot1 = NULL,
  			   *slot2 = NULL;
+ 	int			my_level = GetCurrentTransactionNestLevel();
  
  	/* Make a local EState if need be */
  	if (estate == NULL)
***************
*** 3788,3793 **** afterTriggerInvokeEvents(AfterTriggerEventList *events,
--- 3796,3805 ----
  		{
  			AfterTriggerShared evtshared = GetTriggerSharedData(event);
  
+ 			if ((inAutoX) && (chunk == events->head) && ((char *)event < afterTriggers->events_stack[my_level].tailfree))
+ 			{
+ 				continue;
+ 			}
  			/*
  			 * Is it one for me to fire?
  			 */
***************
*** 4032,4043 **** AfterTriggerEndQuery(EState *estate)
  	for (;;)
  	{
  		events = &afterTriggers->query_stack[afterTriggers->query_depth];
! 		if (afterTriggerMarkEvents(events, &afterTriggers->events, true))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
  			/* OK to delete the immediate events after processing them */
! 			if (afterTriggerInvokeEvents(events, firing_id, estate, true))
  				break;			/* all fired */
  		}
  		else
--- 4044,4055 ----
  	for (;;)
  	{
  		events = &afterTriggers->query_stack[afterTriggers->query_depth];
! 		if (afterTriggerMarkEvents(events, &afterTriggers->events, true, false))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
  			/* OK to delete the immediate events after processing them */
! 			if (afterTriggerInvokeEvents(events, firing_id, estate, true, false))
  				break;			/* all fired */
  		}
  		else
***************
*** 4096,4106 **** AfterTriggerFireDeferred(void)
  	 * Run all the remaining triggers.	Loop until they are all gone, in case
  	 * some trigger queues more for us to do.
  	 */
! 	while (afterTriggerMarkEvents(events, NULL, false))
  	{
  		CommandId	firing_id = afterTriggers->firing_counter++;
  
! 		if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
  			break;				/* all fired */
  	}
  
--- 4108,4200 ----
  	 * Run all the remaining triggers.	Loop until they are all gone, in case
  	 * some trigger queues more for us to do.
  	 */
! 	while (afterTriggerMarkEvents(events, NULL, false, false))
! 	{
! 		CommandId	firing_id = afterTriggers->firing_counter++;
! 
! 		if (afterTriggerInvokeEvents(events, firing_id, NULL, true, false))
! 			break;				/* all fired */
! 	}
! 
! 	/*
! 	 * We don't bother freeing the event list, since it will go away anyway
! 	 * (and more efficiently than via pfree) in AfterTriggerEndXact.
! 	 */
! 
! 	if (snap_pushed)
! 		PopActiveSnapshot();
! }
! 
! /* ----------
!  * AfterTriggerFireDeferredForAutoX()
!  * Called when autonomous transaction commit.
!  * It is different from AfterTriggerFireDeferred that it would
!  * only check below chunks in afterTriggers->events.
!  * We can ensure it would only mark and invoke after trigger
!  * events in current autonomous transaction in this way.
!  * ------
!  */
! void
! AfterTriggerFireDeferredForAutoX(void)
! {
! 	AfterTriggerEventList *events;
! 	bool		snap_pushed = false;
! 	int			my_level = GetCurrentTransactionNestLevel();
! 	MemoryContext old_cxt;
! 	AfterTriggerEventChunk *chunk;
! 	/* Must be inside a transaction */
! 	Assert(afterTriggers != NULL);
! 
! 	/* ... but not inside a query */
! 	Assert(afterTriggers->query_depth ==
! 			   afterTriggers->depth_stack[my_level]);
! 
! 	/*
! 	 * If there are any triggers to fire, make sure we have set a snapshot for
! 	 * them to use.  (Since PortalRunUtility doesn't set a snap for COMMIT, we
! 	 * can't assume ActiveSnapshot is valid on entry.)
! 	 */
! 
! 	if (NULL != afterTriggers->events_stack[my_level].tail)
! 	{
! 		chunk = afterTriggers->events_stack[my_level].tail;
! 	}
! 	else
! 	{
! 		chunk = afterTriggers->events.head;
! 	}
! 
! 	if (afterTriggers->events.tail == NULL || afterTriggers->events_stack[my_level].tailfree == afterTriggers->events.tailfree)
! 	{
! 		return;
! 	}
! 	else
! 	{
! 		old_cxt = MemoryContextSwitchTo(TopTransactionContext);
! 
! 		events = (AfterTriggerEventList *)palloc(sizeof(AfterTriggerEventList));
! 		events->head = chunk;
! 		events->tail = afterTriggers->events.tail;
! 		events->tailfree = afterTriggers->events.tailfree;
! 
! 		(void)MemoryContextSwitchTo(old_cxt);
! 	}
! 
! 	if (events->head != NULL)
! 	{
! 		PushActiveSnapshot(GetTransactionSnapshot());
! 		snap_pushed = true;
! 	}
! 
! 	/*
! 	 * Run all the remaining triggers.	Loop until they are all gone, in case
! 	 * some trigger queues more for us to do.
! 	 */
! 	while (afterTriggerMarkEvents(events, NULL, false, true))
  	{
  		CommandId	firing_id = afterTriggers->firing_counter++;
  
! 		if (afterTriggerInvokeEvents(events, firing_id, NULL, true, true))
  			break;				/* all fired */
  	}
  
***************
*** 4111,4116 **** AfterTriggerFireDeferred(void)
--- 4205,4211 ----
  
  	if (snap_pushed)
  		PopActiveSnapshot();
+ 	pfree(events);
  }
  
  
***************
*** 4658,4664 **** AfterTriggerSetState(ConstraintsSetStmt *stmt)
  		AfterTriggerEventList *events = &afterTriggers->events;
  		bool		snapshot_set = false;
  
! 		while (afterTriggerMarkEvents(events, NULL, true))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
--- 4753,4759 ----
  		AfterTriggerEventList *events = &afterTriggers->events;
  		bool		snapshot_set = false;
  
! 		while (afterTriggerMarkEvents(events, NULL, true, false))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
***************
*** 4683,4689 **** AfterTriggerSetState(ConstraintsSetStmt *stmt)
  			 * subtransaction could later get rolled back.
  			 */
  			if (afterTriggerInvokeEvents(events, firing_id, NULL,
! 										 !IsSubTransaction()))
  				break;			/* all fired */
  		}
  
--- 4778,4784 ----
  			 * subtransaction could later get rolled back.
  			 */
  			if (afterTriggerInvokeEvents(events, firing_id, NULL,
! 										 !IsSubTransaction(), false))
  				break;			/* all fired */
  		}
  
*** a/src/backend/executor/spi.c
--- b/src/backend/executor/spi.c
***************
*** 2074,2079 **** _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
--- 2074,2096 ----
  		 * Replan if needed, and increment plan refcount.  If it's a saved
  		 * plan, the refcount must be backed by the CurrentResourceOwner.
  		 */
+ 		if ((plansource)->raw_parse_tree &&
+ 				IsA((plansource)->raw_parse_tree, TransactionStmt))
+ 
+ 		{
+ 			if (((TransactionStmt*)(plansource->raw_parse_tree))->kind == TRANS_STMT_AUTONOMOUS)
+ 			{
+ 				BeginInternalAutonomousTransaction();
+ 				continue;
+ 			}
+ 
+ 			if (IsCurrentAutoTx())
+ 			{
+ 				CommitInternalAutonomousTransaction();
+ 				continue;
+ 			}
+ 		}
+ 
  		cplan = GetCachedPlan(plansource, paramLI, plan->saved);
  		stmt_list = cplan->stmt_list;
  
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 524,529 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
--- 524,530 ----
  %token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
  	AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
  	ASSERTION ASSIGNMENT ASYMMETRIC AT ATTRIBUTE AUTHORIZATION
+ 	AUTONOMOUS_TRANSACTION
  
  	BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
  	BOOLEAN_P BOTH BY
***************
*** 575,581 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  	ORDER ORDINALITY OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
  
  	PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION
! 	PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
  	PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROGRAM
  
  	QUOTE
--- 576,582 ----
  	ORDER ORDINALITY OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
  
  	PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION
! 	PRAGMA PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
  	PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROGRAM
  
  	QUOTE
***************
*** 8154,8159 **** TransactionStmt:
--- 8155,8167 ----
  					n->gid = $3;
  					$$ = (Node *)n;
  				}
+ 			| PRAGMA AUTONOMOUS_TRANSACTION
+ 				{
+                     TransactionStmt *n = makeNode(TransactionStmt);
+                     n->kind = TRANS_STMT_AUTONOMOUS;
+                     n->options = NIL;
+                     $$ = (Node *)n;
+                 }
  		;
  
  opt_transaction:	WORK							{}
***************
*** 12803,12808 **** unreserved_keyword:
--- 12811,12817 ----
  			| ASSIGNMENT
  			| AT
  			| ATTRIBUTE
+ 			| AUTONOMOUS_TRANSACTION
  			| BACKWARD
  			| BEFORE
  			| BEGIN_P
***************
*** 12946,12951 **** unreserved_keyword:
--- 12955,12961 ----
  			| PASSING
  			| PASSWORD
  			| PLANS
+ 			| PRAGMA
  			| PRECEDING
  			| PREPARE
  			| PREPARED
*** a/src/backend/storage/ipc/procarray.c
--- b/src/backend/storage/ipc/procarray.c
***************
*** 101,106 **** static ProcArrayStruct *procArray;
--- 101,109 ----
  static PGPROC *allProcs;
  static PGXACT *allPgXact;
  
+ static PGAutonomousXACT *allPgAutonomousXact;
+ 
+ 
  /*
   * Bookkeeping for tracking emulated transactions in recovery
   */
***************
*** 246,251 **** CreateSharedProcArray(void)
--- 249,255 ----
  
  	allProcs = ProcGlobal->allProcs;
  	allPgXact = ProcGlobal->allPgXact;
+ 	allPgAutonomousXact = ProcGlobal->allPgAutonomousXact;
  
  	/* Create or attach to the KnownAssignedXids arrays too, if needed */
  	if (EnableHotStandby)
***************
*** 443,448 **** ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
--- 447,501 ----
  	}
  }
  
+ void
+ ProcArrayEndAutonomousTransaction(PGPROC *proc, TransactionId latestXid)
+ {
+ 	PGAutonomousXACT *pgautonouxact = GetCurrentPGAutonomousXACT();
+ 	if (TransactionIdIsValid(latestXid))
+ 	{
+ 		/*
+ 		 * We must lock ProcArrayLock while clearing our advertised XID, so
+ 		 * that we do not exit the set of "running" transactions while someone
+ 		 * else is taking a snapshot.  See discussion in
+ 		 * src/backend/access/transam/README.
+ 		 */
+ 
+ 
+ 		LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ 
+ 		pgautonouxact->xid = InvalidTransactionId;
+ 		pgautonouxact->xmin = InvalidTransactionId;
+ 		/* must be cleared with xid/xmin: */
+ 		pgautonouxact->delayChkpt = false;		/* be sure this is cleared in abort */
+ 
+ 		/* Clear the subtransaction-XID cache too while holding the lock */
+ 		pgautonouxact->nxids = 0;
+ 		pgautonouxact->overflowed = false;
+ 
+ 		/* Also advance global latestCompletedXid while holding the lock */
+ 		if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
+ 								  latestXid))
+ 			ShmemVariableCache->latestCompletedXid = latestXid;
+ 
+ 		LWLockRelease(ProcArrayLock);
+ 	}
+ 	else
+ 	{
+ 		/*
+ 		 * If we have no XID, we don't need to lock, since we won't affect
+ 		 * anyone else's calculation of a snapshot.  We might change their
+ 		 * estimate of global xmin, but that's OK.
+ 		 */
+ 		Assert(!TransactionIdIsValid(allPgAutonomousXact[proc->pgprocno].xid));
+ 		pgautonouxact->xmin = InvalidTransactionId;
+ 		/* must be cleared with xid/xmin: */
+ 		pgautonouxact->delayChkpt = false;
+ 		/* be sure this is cleared in abort */
+ 
+ 		Assert(pgautonouxact->nxids == 0);
+ 		Assert(pgautonouxact->overflowed == false);
+ 	}
+ }
  
  /*
   * ProcArrayClearTransaction -- clear the transaction fields
***************
*** 854,860 **** TransactionIdIsInProgress(TransactionId xid)
  	ProcArrayStruct *arrayP = procArray;
  	TransactionId topxid;
  	int			i,
! 				j;
  
  	/*
  	 * Don't bother checking a transaction older than RecentXmin; it could not
--- 907,914 ----
  	ProcArrayStruct *arrayP = procArray;
  	TransactionId topxid;
  	int			i,
! 				j,
! 				k;
  
  	/*
  	 * Don't bother checking a transaction older than RecentXmin; it could not
***************
*** 926,937 **** TransactionIdIsInProgress(TransactionId xid)
  	for (i = 0; i < arrayP->numProcs; i++)
  	{
  		int			pgprocno = arrayP->pgprocnos[i];
  		volatile PGPROC *proc = &allProcs[pgprocno];
  		volatile PGXACT *pgxact = &allPgXact[pgprocno];
  		TransactionId pxid;
  
  		/* Ignore my own proc --- dealt with it above */
! 		if (proc == MyProc)
  			continue;
  
  		/* Fetch xid just once - see GetNewTransactionId */
--- 980,994 ----
  	for (i = 0; i < arrayP->numProcs; i++)
  	{
  		int			pgprocno = arrayP->pgprocnos[i];
+ 		int			pgautoxno = pgprocno * MAX_AUTOX_NESTING_LEVEL;
  		volatile PGPROC *proc = &allProcs[pgprocno];
  		volatile PGXACT *pgxact = &allPgXact[pgprocno];
+ 		volatile PGAutonomousXACT *pgautonomousxact = &allPgAutonomousXact[pgautoxno];
  		TransactionId pxid;
+ 		TransactionId pautoxid = InvalidTransactionId;
  
  		/* Ignore my own proc --- dealt with it above */
! 		if (proc == MyProc && !MyProc->inAutoTXLevel)
  			continue;
  
  		/* Fetch xid just once - see GetNewTransactionId */
***************
*** 982,987 **** TransactionIdIsInProgress(TransactionId xid)
--- 1039,1083 ----
  		 */
  		if (pgxact->overflowed)
  			xids[nxids++] = pxid;
+ 
+ 		/*
+ 		 * check autonomous transaction
+ 		 */
+ 		for (j = 0; j < proc->inAutoTXLevel; j++)
+ 		{
+ 			/*check top level autoTX*/
+ 			pautoxid = pgautonomousxact[j].xid;
+ 			if (!TransactionIdIsValid(pautoxid))
+ 				break;
+ 
+ 			if (TransactionIdEquals(pautoxid, xid))
+ 			{
+ 				LWLockRelease(ProcArrayLock);
+ 				xc_by_main_xid_inc();
+ 				return true;
+ 			}
+ 
+ 			/*if the xid logically < pautoxid, we don't need check lower TX*/
+ 			if (TransactionIdPrecedes(xid, pautoxid))
+ 				break;
+ 
+ 			/*check sub transactions of this autoTX*/
+ 			for (k = pgautonomousxact[j].nxids - 1; k >= 0; k--)
+ 			{
+ 				/* Fetch xid just once - see GetNewTransactionId */
+ 				TransactionId cxid = pgautonomousxact[j].subxids.xids[k];
+ 
+ 				if (TransactionIdEquals(cxid, xid))
+ 				{
+ 					LWLockRelease(ProcArrayLock);
+ 					xc_by_child_xid_inc();
+ 					return true;
+ 				}
+ 			}
+ 
+ 			if (pgautonomousxact[j].overflowed)
+ 				xids[nxids++] = pautoxid;
+ 		}
  	}
  
  	/*
***************
*** 1367,1372 **** GetSnapshotData(Snapshot snapshot)
--- 1463,1469 ----
  	bool		suboverflowed = false;
  	volatile TransactionId replication_slot_xmin = InvalidTransactionId;
  	volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
+ 	int         autoTxIndex = 0;
  
  	Assert(snapshot != NULL);
  
***************
*** 1435,1440 **** GetSnapshotData(Snapshot snapshot)
--- 1532,1542 ----
  			volatile PGXACT *pgxact = &allPgXact[pgprocno];
  			TransactionId xid;
  
+ 			int			pgautoxno = pgprocno * MAX_AUTOX_NESTING_LEVEL;
+ 			volatile PGPROC *pgproc = &allProcs[pgprocno];
+ 			volatile PGAutonomousXACT *pgAutonomousxact =
+ 												&allPgAutonomousXact[pgautoxno];
+ 
  			/*
  			 * Backend is doing logical decoding which manages xmin
  			 * separately, check below.
***************
*** 1471,1477 **** GetSnapshotData(Snapshot snapshot)
  			 */
  			if (NormalTransactionIdPrecedes(xid, xmin))
  				xmin = xid;
! 			if (pgxact == MyPgXact)
  				continue;
  
  			/* Add XID to snapshot. */
--- 1573,1585 ----
  			 */
  			if (NormalTransactionIdPrecedes(xid, xmin))
  				xmin = xid;
! 
! 			/*
! 			 * When pgAutonomousxact->inAutoTX is true, there is a autonomous
! 			 * transaction in this proc, it still need add the main transaction
! 			 * to the snapshot.
!   			 */
! 			if (pgxact == MyPgXact && !MyProc->inAutoTXLevel)
  				continue;
  
  			/* Add XID to snapshot. */
***************
*** 1511,1516 **** GetSnapshotData(Snapshot snapshot)
--- 1619,1664 ----
  					}
  				}
  			}
+ 
+ 			/* Add auto tx to snapshot */
+ 			for (autoTxIndex = 0; autoTxIndex < pgproc->inAutoTXLevel; autoTxIndex++)
+ 			{
+ 				xid = pgAutonomousxact[autoTxIndex].xid;
+ 
+ 				/* If auto tx is myself, skip it */
+ 				if (&pgAutonomousxact[autoTxIndex] == &MyPgAutonomousXact[MyProc->inAutoTXLevel - 1])
+ 					break;
+ 
+ 				/*
+ 				 * If the auto tx has no XID assigned, we can skip it; it
+ 				 * won't have sub-XIDs either.  If the XID is >= xmax, we can also
+ 				 * skip it; such tx will be treated as running anyway
+ 				 * (and any sub-XIDs will also be >= xmax).
+ 				 */
+ 				if (!TransactionIdIsNormal(xid)
+ 					|| !NormalTransactionIdPrecedes(xid, xmax))
+ 					break;
+ 
+ 				snapshot->xip[count++] = xid;
+ 
+ 				if (!suboverflowed)
+ 				{
+ 					if (pgAutonomousxact[autoTxIndex].overflowed)
+ 						suboverflowed = true;
+ 					else
+ 					{
+ 						int	nxids = pgAutonomousxact[autoTxIndex].nxids;
+ 
+ 						if (nxids > 0)
+ 						{
+ 							memcpy(snapshot->subxip + subcount,
+ 									(void *) pgAutonomousxact[autoTxIndex].subxids.xids,
+ 							   		nxids * sizeof(TransactionId));
+ 							subcount += nxids;
+ 						}
+ 					}
+ 				}
+ 			}
  		}
  	}
  	else
***************
*** 2042,2047 **** GetVirtualXIDsDelayingChkpt(int *nvxids)
--- 2190,2198 ----
  		int			pgprocno = arrayP->pgprocnos[index];
  		volatile PGPROC *proc = &allProcs[pgprocno];
  		volatile PGXACT *pgxact = &allPgXact[pgprocno];
+ 		int pgautotxno = pgprocno*MAX_AUTOX_NESTING_LEVEL;
+ 		volatile PGAutonomousXACT *pgautonomousxact = &allPgAutonomousXact[pgautotxno];
+ 
  
  		if (pgxact->delayChkpt)
  		{
***************
*** 2795,2800 **** XidCacheRemoveRunningXids(TransactionId xid,
--- 2946,3031 ----
  	LWLockRelease(ProcArrayLock);
  }
  
+ /*
+  * XidCacheRemoveAutoRunningXids
+  *
+  * Remove a bunch of TransactionIds from the list of known-running
+  * subtransactions of auto transaction for my backend.	Both the specified xid and those in
+  * the xids[] array (of length nxids) are removed from the subxids cache.
+  * latestXid must be the latest XID among the group.
+  */
+ void
+ XidCacheRemoveAutoRunningXids(TransactionId xid,
+ 						  int nxids, const TransactionId *xids,
+ 						  TransactionId latestXid, bool isTopAutoTX)
+ {
+ 	int			i,
+ 				j;
+ 	PGAutonomousXACT * currentautox = GetCurrentPGAutonomousXACT();
+ 	Assert(TransactionIdIsValid(xid));
+ 
+ 	/*
+ 	 * Under normal circumstances xid and xids[] will be in increasing order,
+ 	 * as will be the entries in subxids.  Scan backwards to avoid O(N^2)
+ 	 * behavior when removing a lot of xids.
+ 	 */
+ 	for (i = nxids - 1; i >= 0; i--)
+ 	{
+ 		TransactionId anxid = xids[i];
+ 
+ 		for (j = currentautox->nxids - 1; j >= 0; j--)
+ 		{
+ 			if (TransactionIdEquals(currentautox->subxids.xids[j], anxid))
+ 			{
+ 				currentautox->subxids.xids[j] = currentautox->subxids.xids[currentautox->nxids - 1];
+ 				currentautox->nxids--;
+ 				break;
+ 			}
+ 
+ 		}
+ 		/*
+ 		 * Ordinarily we should have found it, unless the cache has
+ 		 * overflowed. However it's also possible for this routine to be
+ 		 * invoked multiple times for the same subtransaction, in case of an
+ 		 * error during AbortSubTransaction.  So instead of Assert, emit a
+ 		 * debug warning.
+ 		 */
+ 		if (j < 0 && !currentautox->overflowed)
+ 			ereport(WARNING,
+ 					(errmsg("did not find subXID %u in MyPgAutonomousXact",
+ 						anxid)));
+ 
+ 	}
+ 
+ 	/* top level in auto TX, PopTransaction will MemSet MyPgAutonomousXact */
+ 	if(!isTopAutoTX)
+ 	{
+ 		for (j = currentautox->nxids - 1; j >= 0; j--)
+ 		{
+ 			if (TransactionIdEquals(currentautox->subxids.xids[j], xid))
+ 			{
+ 				currentautox->subxids.xids[j] = currentautox->subxids.xids[currentautox->nxids - 1];
+ 				currentautox->nxids--; ;
+ 				break;
+ 			}
+ 		}
+ 		/* Ordinarily we should have found it, unless the cache has overflowed */
+ 		if (j < 0 && !currentautox->overflowed)
+ 			ereport(WARNING,
+ 					(errmsg("did not find subXID %u in MyPgAutonomousXact",
+ 						xid)));
+ 	}
+ 
+ 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ 
+ 	/* Also advance global latestCompletedXid while holding the lock */
+ 	if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
+ 							  latestXid))
+ 		ShmemVariableCache->latestCompletedXid = latestXid;
+ 
+ 	LWLockRelease(ProcArrayLock);
+ }
+ 
  #ifdef XIDCACHE_DEBUG
  
  /*
*** a/src/backend/storage/lmgr/lmgr.c
--- b/src/backend/storage/lmgr/lmgr.c
***************
*** 23,29 ****
  #include "storage/lmgr.h"
  #include "storage/procarray.h"
  #include "utils/inval.h"
! 
  
  /*
   * Struct to hold context info for transaction lock waits.
--- 23,29 ----
  #include "storage/lmgr.h"
  #include "storage/procarray.h"
  #include "utils/inval.h"
! #include "storage/proc.h"
  
  /*
   * Struct to hold context info for transaction lock waits.
***************
*** 524,529 **** XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
--- 524,534 ----
  		error_context_stack = &callback;
  	}
  
+ #ifdef USE_ASSERT_CHECKING
+ 		if(!MyProc->inAutoTXLevel)
+ 			Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
+ #endif
+ 
  	for (;;)
  	{
  		Assert(TransactionIdIsValid(xid));
*** a/src/backend/storage/lmgr/lock.c
--- b/src/backend/storage/lmgr/lock.c
***************
*** 355,360 **** static void LockRefindAndRelease(LockMethod lockMethodTable, PGPROC *proc,
--- 355,363 ----
  					 LOCKTAG *locktag, LOCKMODE lockmode,
  					 bool decrement_strong_lock_count);
  
+ static void InternalDeadLockCheckforAutoX(LockMethod lockMethodTable,
+ 											LOCKMODE lockmode,
+ 											LOCK *lock, PROCLOCK *proclock);
  
  /*
   * InitLocks -- Initialize the lock manager's data structures.
***************
*** 783,788 **** LockAcquireExtended(const LOCKTAG *locktag,
--- 786,797 ----
  	 */
  	if (locallock->nLocks > 0)
  	{
+ 		if(MyProc->inAutoTXLevel && locallock->proclock != NULL)
+ 		{
+ 			InternalDeadLockCheckforAutoX(lockMethodTable, lockmode, locallock->lock, locallock->proclock);
+ 		}
+ 
+ 
  		GrantLockLocal(locallock, owner);
  		return LOCKACQUIRE_ALREADY_HELD;
  	}
***************
*** 818,825 **** LockAcquireExtended(const LOCKTAG *locktag,
  	 * lock type on a relation we have already locked using the fast-path, but
  	 * for now we don't worry about that case either.
  	 */
! 	if (EligibleForRelationFastPath(locktag, lockmode) &&
! 		FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND)
  	{
  		uint32		fasthashcode = FastPathStrongLockHashPartition(hashcode);
  		bool		acquired;
--- 827,835 ----
  	 * lock type on a relation we have already locked using the fast-path, but
  	 * for now we don't worry about that case either.
  	 */
! 	if (EligibleForRelationFastPath(locktag, lockmode)
! 		&& FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND
! 		&& !MyProc->inAutoTXLevel)
  	{
  		uint32		fasthashcode = FastPathStrongLockHashPartition(hashcode);
  		bool		acquired;
***************
*** 1142,1147 **** SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
--- 1152,1160 ----
  		uint32		partition = LockHashPartition(hashcode);
  
  		proclock->holdMask = 0;
+ 		MemSet(proclock->holdMaskByAutoTX, 0, MAX_AUTOX_NESTING_LEVEL * (sizeof(LOCKMASK)));
+ 
+ 		proclock->holdMaskByNormalTX = 0;
  		proclock->releaseMask = 0;
  		/* Add proclock to appropriate lists */
  		SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
***************
*** 1272,1277 **** LockCheckConflicts(LockMethod lockMethodTable,
--- 1285,1292 ----
  	LOCKMASK	myLocks;
  	LOCKMASK	otherLocks;
  	int			i;
+ 	LOCKMASK	myLocksByAutoTX;
+ 
  
  	/*
  	 * first check for global conflicts: If no locks conflict with my request,
***************
*** 1295,1300 **** LockCheckConflicts(LockMethod lockMethodTable,
--- 1310,1326 ----
  	 */
  	myLocks = proclock->holdMask;
  	otherLocks = 0;
+ 
+ 	/* In autonomous TX, check whether lock conflict with parent TX */
+ 	if(MyProc->inAutoTXLevel)
+ 	{
+ 		myLocksByAutoTX = proclock->holdMaskByAutoTX[MyProc->inAutoTXLevel - 1];
+ 		/* if conflict with parent TX, It's a dead lock */
+ 		InternalDeadLockCheckforAutoX(lockMethodTable, lockmode, lock, proclock);
+ 		/* Something conflicts.	But it could still be autonomous own lock. */
+ 		myLocks = myLocksByAutoTX;
+ 	}
+ 
  	for (i = 1; i <= numLockModes; i++)
  	{
  		int			myHolding = (myLocks & LOCKBIT_ON(i)) ? 1 : 0;
***************
*** 1333,1344 **** LockCheckConflicts(LockMethod lockMethodTable,
--- 1359,1393 ----
  void
  GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
  {
+ 	uint8 autoTXLevel;
+ 
  	lock->nGranted++;
  	lock->granted[lockmode]++;
  	lock->grantMask |= LOCKBIT_ON(lockmode);
  	if (lock->granted[lockmode] == lock->requested[lockmode])
  		lock->waitMask &= LOCKBIT_OFF(lockmode);
  	proclock->holdMask |= LOCKBIT_ON(lockmode);
+ 
+ 
+ 	if (MyProc == proclock->tag.myProc)
+ 	{
+ 		autoTXLevel = GetCurrentResourceOwnerAutoTXLevel();
+ 	}
+ 	else
+ 	{
+ 		autoTXLevel = proclock->tag.myProc->inAutoTXLevel;
+ 	}
+ 
+ 	proclock->holdMask |= LOCKBIT_ON(lockmode);
+ 	if (autoTXLevel)
+ 	{
+ 		proclock->holdMaskByAutoTX[autoTXLevel - 1] |= LOCKBIT_ON(lockmode);
+ 	}
+ 	else
+ 	{
+ 		proclock->holdMaskByNormalTX |= LOCKBIT_ON(lockmode);
+ 	}
+ 
  	LOCK_PRINT("GrantLock", lock, lockmode);
  	Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
  	Assert(lock->nGranted <= lock->nRequested);
***************
*** 1394,1399 **** UnGrantLock(LOCK *lock, LOCKMODE lockmode,
--- 1443,1457 ----
  	/*
  	 * Now fix the per-proclock state.
  	 */
+ 	if (MyProc->inAutoTXLevel)
+ 	{
+ 		proclock->holdMaskByAutoTX[MyProc->inAutoTXLevel - 1] &= LOCKBIT_OFF(lockmode);
+ 	}
+ 	else
+ 	{
+ 		proclock->holdMaskByNormalTX &= LOCKBIT_OFF(lockmode);
+ 
+ 	}
  	proclock->holdMask &= LOCKBIT_OFF(lockmode);
  	PROCLOCK_PRINT("UnGrantLock: updated", proclock);
  
***************
*** 4084,4086 **** VirtualXactLock(VirtualTransactionId vxid, bool wait)
--- 4142,4185 ----
  	LockRelease(&tag, ShareLock, false);
  	return true;
  }
+ 
+ static void
+ InternalDeadLockCheckforAutoX(LockMethod lockMethodTable, LOCKMODE lockmode,
+ 										  LOCK *lock, PROCLOCK *proclock)
+ {
+ 	int i = 0;
+ 	/*check deadlock with main xact*/
+ 	if (lockMethodTable->conflictTab[lockmode] & proclock->holdMaskByNormalTX)
+ 	{
+ 		lock->nRequested--;
+ 		Assert(lock->requested[lockmode] > 0);
+ 		lock->requested[lockmode]--;
+ 		PROCLOCK_PRINT("LockCheckConflicts: auto TX conflict with parent TX", proclock);
+ 		ereport(ERROR,
+ 			(errmsg("lock %s on object %u/%u/%u/%u required by auto TX is conflict with parent TX",
+ 				lockMethodTable->lockModeNames[lockmode],
+ 				lock->tag.locktag_field1,
+ 				lock->tag.locktag_field2,
+ 				lock->tag.locktag_field3,
+ 				lock->tag.locktag_field4)));
+ 	}
+ 	/*check deadlock with upper autox*/
+ 	for (i = 0; i < MyProc->inAutoTXLevel - 1; i++)
+ 	{
+ 		if (lockMethodTable->conflictTab[lockmode] & proclock->holdMaskByAutoTX[i])
+ 		{
+ 			lock->nRequested--;
+ 			Assert(lock->requested[lockmode] > 0);
+ 			lock->requested[lockmode]--;
+ 			PROCLOCK_PRINT("LockCheckConflicts: auto TX conflict with parent AutoX", proclock);
+ 			ereport(ERROR,
+ 				(errmsg("lock %s on object %u/%u/%u/%u required by auto TX is conflict with parent AutoX",
+ 					lockMethodTable->lockModeNames[lockmode],
+ 					lock->tag.locktag_field1,
+ 					lock->tag.locktag_field2,
+ 					lock->tag.locktag_field3,
+ 					lock->tag.locktag_field4)));
+ 		}
+ 	}
+ }
+ 
*** a/src/backend/storage/lmgr/predicate.c
--- b/src/backend/storage/lmgr/predicate.c
***************
*** 199,204 ****
--- 199,205 ----
  #include "utils/rel.h"
  #include "utils/snapmgr.h"
  #include "utils/tqual.h"
+ #include "storage/proc.h"
  
  /* Uncomment the next line to test the graceful degradation code. */
  /* #define TEST_OLDSERXID */
***************
*** 502,507 **** SerializationNeededForRead(Relation relation, Snapshot snapshot)
--- 503,518 ----
  		return false;
  
  	/*
+ 	 * BEGIN<x00221760>
+ 	 * Don't acquire locks or conflict if it is an autonomous transaction. Autonomous
+ 	 * transaction always does simple work like create partition or create undo segement,
+ 	 * it should not faild because of serializable isolation.
+ 	 */
+ 	if (MyProc->inAutoTXLevel)
+ 		return false;
+ 	/* END */
+ 
+ 	/*
  	 * Check if we have just become "RO-safe". If we have, immediately release
  	 * all locks as they're not needed anymore. This also resets
  	 * MySerializableXact, so that subsequent calls to this function can exit
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
***************
*** 62,67 **** bool		log_lock_waits = false;
--- 62,68 ----
  /* Pointer to this process's PGPROC and PGXACT structs, if any */
  PGPROC	   *MyProc = NULL;
  PGXACT	   *MyPgXact = NULL;
+ PGAutonomousXACT *MyPgAutonomousXact = NULL;
  
  /*
   * This spinlock protects the freelist of recycled PGPROC structures.
***************
*** 112,117 **** ProcGlobalShmemSize(void)
--- 113,122 ----
  	size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGXACT)));
  	size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGXACT)));
  
+ 	size = add_size(size, mul_size(MaxBackends * MAX_AUTOX_NESTING_LEVEL, sizeof(PGAutonomousXACT)));
+ 	size = add_size(size, mul_size(NUM_AUXILIARY_PROCS * MAX_AUTOX_NESTING_LEVEL, sizeof(PGAutonomousXACT)));
+ 	size = add_size(size, mul_size(max_prepared_xacts * MAX_AUTOX_NESTING_LEVEL, sizeof(PGAutonomousXACT)));
+ 
  	return size;
  }
  
***************
*** 162,167 **** InitProcGlobal(void)
--- 167,175 ----
  	bool		found;
  	uint32		TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
  
+ 	PGAutonomousXACT	   *pgautonomousxacts;
+ 
+ 
  	/* Create the ProcGlobal shared structure */
  	ProcGlobal = (PROC_HDR *)
  		ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
***************
*** 210,215 **** InitProcGlobal(void)
--- 218,229 ----
  	MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACT));
  	ProcGlobal->allPgXact = pgxacts;
  
+ 	pgautonomousxacts = (PGAutonomousXACT *) ShmemAlloc(TotalProcs * MAX_AUTOX_NESTING_LEVEL * sizeof(PGAutonomousXACT));
+ 	/*lint -e506 -e681  */
+ 	MemSet(pgautonomousxacts, 0, TotalProcs * MAX_AUTOX_NESTING_LEVEL * sizeof(PGAutonomousXACT));
+ 	/*lint +e506 +e681  */
+     ProcGlobal->allPgAutonomousXact = pgautonomousxacts;
+ 
  	for (i = 0; i < TotalProcs; i++)
  	{
  		/* Common initialization for all PGPROCs, regardless of type. */
***************
*** 279,284 **** InitProcess(void)
--- 293,299 ----
  {
  	/* use volatile pointer to prevent code rearrangement */
  	volatile PROC_HDR *procglobal = ProcGlobal;
+ 	int pgautotxno = 0;
  
  	/*
  	 * ProcGlobal should be set up already (if we are a backend, we inherit
***************
*** 317,322 **** InitProcess(void)
--- 332,340 ----
  
  	if (MyProc != NULL)
  	{
+ 		MyProc->inAutoTXLevel = 0;
+ 
+ 
  		if (IsAnyAutoVacuumProcess())
  			procglobal->autovacFreeProcs = (PGPROC *) MyProc->links.next;
  		else if (IsBackgroundWorker)
***************
*** 340,345 **** InitProcess(void)
--- 358,368 ----
  	}
  	MyPgXact = &ProcGlobal->allPgXact[MyProc->pgprocno];
  
+ 	pgautotxno = MyProc->pgprocno*MAX_AUTOX_NESTING_LEVEL;
+ 	MyPgAutonomousXact = &ProcGlobal->allPgAutonomousXact[pgautotxno];
+ 	MemSet(MyPgAutonomousXact, 0, MAX_AUTOX_NESTING_LEVEL*sizeof(PGAutonomousXACT));
+ 
+ 
  	/*
  	 * Now that we have a PGPROC, mark ourselves as an active postmaster
  	 * child; this is so that the postmaster can detect it if we exit without
***************
*** 390,395 **** InitProcess(void)
--- 413,419 ----
  	/* Initialize fields for sync rep */
  	MyProc->waitLSN = 0;
  	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
+ 
  	SHMQueueElemInit(&(MyProc->syncRepLinks));
  
  	/*
***************
*** 464,469 **** InitAuxiliaryProcess(void)
--- 488,494 ----
  {
  	PGPROC	   *auxproc;
  	int			proctype;
+ 	int			pgautoxno;
  
  	/*
  	 * ProcGlobal should be set up already (if we are a backend, we inherit
***************
*** 515,520 **** InitAuxiliaryProcess(void)
--- 540,549 ----
  	MyProc = auxproc;
  	MyPgXact = &ProcGlobal->allPgXact[auxproc->pgprocno];
  
+ 	pgautoxno = auxproc->pgprocno * MAX_AUTOX_NESTING_LEVEL;
+ 	MyPgAutonomousXact = &ProcGlobal->allPgAutonomousXact[pgautoxno];
+ 
+ 
  	SpinLockRelease(ProcStructLock);
  
  	/*
***************
*** 1669,1671 **** ProcSendSignal(int pid)
--- 1698,1708 ----
  	if (proc != NULL)
  		PGSemaphoreUnlock(&proc->sem);
  }
+ 
+ PGAutonomousXACT *GetCurrentPGAutonomousXACT(void)
+ {
+ 	Assert(MyProc->inAutoTXLevel);
+ 
+ 	return &MyPgAutonomousXact[MyProc->inAutoTXLevel - 1];
+ }
+ 
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 414,419 **** standard_ProcessUtility(Node *parsetree,
--- 414,424 ----
  						UserAbortTransactionBlock();
  						break;
  
+ 					case TRANS_STMT_AUTONOMOUS:
+ 						RequireTransactionChain(isTopLevel, "AUTONOMOUS TRANSACTION");
+ 						DefineAutonomousTransaction();
+ 						break;
+ 
  					case TRANS_STMT_SAVEPOINT:
  						{
  							ListCell   *cell;
***************
*** 1751,1756 **** CreateCommandTag(Node *parsetree)
--- 1756,1765 ----
  						tag = "ROLLBACK PREPARED";
  						break;
  
+ 					case TRANS_STMT_AUTONOMOUS:
+ 						tag = "START AUTONOMOUS TRANSACTION";
+ 						break;
+ 
  					default:
  						tag = "???";
  						break;
*** a/src/backend/utils/cache/catcache.c
--- b/src/backend/utils/cache/catcache.c
***************
*** 1326,1331 **** ReleaseCatCache(HeapTuple tuple)
--- 1326,1399 ----
  		CatCacheRemoveCTup(ct->my_cache, ct);
  }
  
+ /*if it is a autonomous transaction, it will not use syscache*/
+ HeapTuple
+ SearchSystableForAutoX(CatCache *cache,
+ 			   Datum v1,
+ 			   Datum v2,
+ 			   Datum v3,
+ 			   Datum v4)
+ {
+ 	ScanKeyData cur_skey[CATCACHE_MAXKEYS];
+ 	Relation	relation;
+ 	SysScanDesc scandesc;
+ 	HeapTuple	ntp = NULL;
+ 	HeapTuple	dtp = NULL;
+ 
+ 	/*
+ 	 * one-time startup overhead for each cache
+ 	 */
+ 	if (cache->cc_tupdesc == NULL)
+ 		CatalogCacheInitializeCache(cache);
+ 
+ #ifdef CATCACHE_STATS
+ 	cache->cc_searches++;
+ #endif
+ 
+ 	/*
+ 	 * initialize the search key information
+ 	 */
+ 	memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey));
+ 	cur_skey[0].sk_argument = v1;
+ 	cur_skey[1].sk_argument = v2;
+ 	cur_skey[2].sk_argument = v3;
+ 	cur_skey[3].sk_argument = v4;
+ 
+ 	relation = heap_open(cache->cc_reloid, AccessShareLock);
+ 	scandesc = systable_beginscan(relation,
+ 								  cache->cc_indexoid,
+ 								  IndexScanOK(cache, cur_skey),
+ 								  NULL,
+ 								  cache->cc_nkeys,
+ 								  cur_skey);
+ 
+ 	ntp = systable_getnext(scandesc);
+ 	if (NULL != ntp)
+ 	{
+ 		dtp = (HeapTupleData *) palloc(sizeof(HeapTupleData));
+ 
+ 		heap_copytuple_with_tuple(ntp, dtp);
+ 	}
+ 
+ 	systable_endscan(scandesc);
+ 
+ 	heap_close(relation, AccessShareLock);
+ 
+ 	return dtp;
+ }
+ 
+ void
+ ReleaseHeapTupleforAutoX(HeapTuple tuple)
+ {
+ 	if(NULL != tuple)
+ 	{
+ 		if(NULL != tuple->t_data)
+ 		{
+ 			pfree(tuple->t_data);
+ 		}
+ 		pfree(tuple);
+ 	}
+ }
  
  /*
   *	GetCatCacheHashValue
*** a/src/backend/utils/cache/inval.c
--- b/src/backend/utils/cache/inval.c
***************
*** 778,789 **** MakeSharedInvalidMessagesArray(const SharedInvalidationMessage *msgs, int n)
   */
  int
  xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
! 									 bool *RelcacheInitFileInval)
  {
  	MemoryContext oldcontext;
  
  	/* Must be at top of stack */
! 	Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
  
  	/*
  	 * Relcache init file invalidation requires processing both before and
--- 778,791 ----
   */
  int
  xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
! 									 bool *RelcacheInitFileInval,
! 									 bool isAutoXact)
  {
  	MemoryContext oldcontext;
  
  	/* Must be at top of stack */
! 	if (!isAutoXact)
! 		Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
  
  	/*
  	 * Relcache init file invalidation requires processing both before and
***************
*** 982,987 **** AtEOSubXact_Inval(bool isCommit)
--- 984,1067 ----
  }
  
  /*
+  * AtEOAutoXact_Inval
+  *		Process queued-up invalidation messages at end of autonomous transaction.
+  *
+  * If isCommit, we must send out the messages in our PriorCmdInvalidMsgs list
+  * to the shared invalidation message queue.  Note that these will be read
+  * not only by other backends, but also by our own backend at the next
+  * transaction start (via AcceptInvalidationMessages).	This means that
+  * we can skip immediate local processing of anything that's still in
+  * CurrentCmdInvalidMsgs, and just send that list out too.
+  *
+  * If not isCommit, we are aborting, and must locally process the messages
+  * in PriorCmdInvalidMsgs.	No messages need be sent to other backends,
+  * since they'll not have seen our changed tuples anyway.  We can forget
+  * about CurrentCmdInvalidMsgs too, since those changes haven't touched
+  * the caches yet.
+  *
+  * In any case, pop the transaction stack.	We need not physically free memory
+  * here, since CurTransactionContext is about to be emptied anyway
+  * (if aborting).  Beware of the possibility of aborting the same nesting
+  * level twice, though.
+  */
+ void
+ AtEOAutoXact_Inval(bool isCommit)
+ {
+ 	int			my_level = GetCurrentTransactionNestLevel();
+ 	TransInvalidationInfo *myInfo = transInvalInfo;
+ 
+ 	if (isCommit)
+ 	{
+ 		/* Must be at non-top of stack */
+ 		Assert(myInfo != NULL && myInfo->parent != NULL);
+ 		Assert(myInfo->my_level == my_level);
+ 
+ 		/*
+ 		 * Relcache init file invalidation requires processing both before and
+ 		 * after we send the SI messages.  However, we need not do anything
+ 		 * unless we committed.
+ 		 */
+ 		if (myInfo->RelcacheInitFileInval)
+ 			RelationCacheInitFilePreInvalidate();
+ 
+ 		AppendInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
+ 								   &myInfo->CurrentCmdInvalidMsgs);
+ 
+ 		ProcessInvalidationMessagesMulti(&myInfo->PriorCmdInvalidMsgs,
+ 										 SendSharedInvalidMessages);
+ 
+ 
+ 		if (myInfo->RelcacheInitFileInval)
+ 			RelationCacheInitFilePostInvalidate();
+ 
+ 		/* Pop the transaction state stack */
+ 		transInvalInfo = myInfo->parent;
+ 
+ 		/* Need not free anything else explicitly */
+ 		pfree(myInfo);
+ 	}
+ 	else if (myInfo != NULL && myInfo->my_level == my_level)
+ 	{
+ 		/* Must be at non-top of stack */
+ 		Assert(myInfo->parent != NULL);
+ 
+ 		ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
+ 									LocalExecuteInvalidationMessage);
+ 
+ 		/* Pop the transaction state stack */
+ 		transInvalInfo = myInfo->parent;
+ 
+ 		/* Need not free anything else explicitly */
+ 		pfree(myInfo);
+ 	}
+ 
+ 	/* when auto transaction end, unset SharedInvalidMessagesArray  and numSharedInvalidMessagesArray */
+ 	SharedInvalidMessagesArray = NULL;
+ 	numSharedInvalidMessagesArray = 0;
+ }
+ 
+ /*
   * CommandEndInvalidationMessages
   *		Process queued-up invalidation messages at end of one command
   *		in a transaction.
*** a/src/backend/utils/cache/syscache.c
--- b/src/backend/utils/cache/syscache.c
***************
*** 66,71 ****
--- 66,72 ----
  #include "utils/rel.h"
  #include "utils/catcache.h"
  #include "utils/syscache.h"
+ #include "storage/proc.h"
  
  
  /*---------------------------------------------------------------------------
***************
*** 906,911 **** SearchSysCache(int cacheId,
--- 907,917 ----
  		!PointerIsValid(SysCache[cacheId]))
  		elog(ERROR, "invalid cache ID: %d", cacheId);
  
+ 	if (MyProc->inAutoTXLevel)
+ 	{
+ 		return SearchSystableForAutoX(SysCache[cacheId], key1, key2, key3, key4);
+ 	}
+ 
  	return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
  }
  
***************
*** 916,921 **** SearchSysCache(int cacheId,
--- 922,934 ----
  void
  ReleaseSysCache(HeapTuple tuple)
  {
+ 
+ 	if (MyProc->inAutoTXLevel)
+ 	{
+ 		ReleaseHeapTupleforAutoX(tuple);
+ 		return;
+ 	}
+ 
  	ReleaseCatCache(tuple);
  }
  
*** a/src/backend/utils/mmgr/portalmem.c
--- b/src/backend/utils/mmgr/portalmem.c
***************
*** 25,30 ****
--- 25,31 ----
  #include "utils/builtins.h"
  #include "utils/memutils.h"
  #include "utils/timestamp.h"
+ #include "storage/proc.h"
  
  /*
   * Estimate of the maximum number of open portals a user would have,
***************
*** 724,729 **** PreCommit_Portals(bool isPrepare)
--- 725,839 ----
  }
  
  /*
+  * Pre-commit processing for portals in Autonomous Transaction.
+  *
+  * Holdable cursors created in this transaction need to be converted to
+  * materialized form, since we are going to close down the executor and
+  * release locks.  Non-holdable portals created in this transaction are
+  * simply removed.	Portals remaining from prior transactions should be
+  * left untouched.
+  *
+  * Returns TRUE if any portals changed state (possibly causing user-defined
+  * code to be run), FALSE if not.
+  */
+ bool
+ AutoPreCommit_Portals(uint32 createSubid)
+ {
+ 	bool		result = false;
+ 	HASH_SEQ_STATUS status;
+ 	PortalHashEnt *hentry;
+ 
+ 	hash_seq_init(&status, PortalHashTable);
+ 
+ 	while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+ 	{
+ 		Portal		portal = hentry->portal;
+ 
+ 		/* portal created in auto TX? */
+ 		if (createSubid > portal->createSubid)
+ 			continue;
+ 
+ 		/*
+ 		 * There should be no pinned portals anymore. Complain if someone
+ 		 * leaked one.
+ 		 */
+ 		if (portal->portalPinned)
+ 			ereport(ERROR,(errmsg("cannot commit while a portal is pinned")));
+ 
+ 		/*
+ 		 * Do not touch active portals --- this can only happen in the case of
+ 		 * a multi-transaction utility command, such as VACUUM.
+ 		 *
+ 		 * Note however that any resource owner attached to such a portal is
+ 		 * still going to go away, so don't leave a dangling pointer.
+ 		 */
+ 		if (portal->status == PORTAL_ACTIVE )
+ 		{
+ 			portal->resowner = NULL;
+ 			continue;
+ 		}
+ 
+ 		/* Is it a holdable portal created in the auto xact? */
+ 		if ((portal->cursorOptions & CURSOR_OPT_HOLD) &&
+ 			portal->createSubid != InvalidSubTransactionId &&
+ 			portal->status == PORTAL_READY)
+ 		{
+ 			/*
+ 			 * Note that PersistHoldablePortal() must release all resources
+ 			 * used by the portal that are local to the creating transaction.
+ 			 */
+ 			PortalCreateHoldStore(portal);
+ 			PersistHoldablePortal(portal);
+ 
+ 			/* drop cached plan reference, if any */
+ 			PortalReleaseCachedPlan(portal);
+ 
+ 			/*
+ 			 * Any resources belonging to the portal will be released in the
+ 			 * upcoming transaction-wide cleanup; the portal will no longer
+ 			 * have its own resources.
+ 			 */
+ 			portal->resowner = NULL;
+ 
+ 			/*
+ 			 * Having successfully exported the holdable cursor, mark it as
+ 			 * not belonging to this transaction.
+ 			 */
+ 			portal->createSubid = InvalidSubTransactionId;
+ 
+ 			/* Report we changed state */
+ 			result = true;
+ 		}
+ 		else if (portal->createSubid == InvalidSubTransactionId)
+ 		{
+ 			/*
+ 			 * Do nothing to cursors held over from a previous transaction
+ 			 * (including ones we just froze in a previous cycle of this loop)
+ 			 */
+ 			continue;
+ 		}
+ 		else
+ 		{
+ 			/* Zap all non-holdable portals */
+ 			PortalDrop(portal, true);
+ 
+ 			/* Report we changed state */
+ 			result = true;
+ 		}
+ 
+ 		/*
+ 		 * After either freezing or dropping a portal, we have to restart the
+ 		 * iteration, because we could have invoked user-defined code that
+ 		 * caused a drop of the next portal in the hash chain.
+ 		 */
+ 		hash_seq_term(&status);
+ 		hash_seq_init(&status, PortalHashTable);
+ 	}
+ 
+ 	return result;
+ }
+ 
+ /*
   * Abort processing for portals.
   *
   * At this point we reset "active" status and run the cleanup hook if
*** a/src/backend/utils/resowner/resowner.c
--- b/src/backend/utils/resowner/resowner.c
***************
*** 103,108 **** typedef struct ResourceOwnerData
--- 103,110 ----
  	int			ndsms;			/* number of owned shmem segments */
  	dsm_segment **dsms;			/* dynamically allocated array */
  	int			maxdsms;		/* currently allocated array size */
+ 
+ 	uint8		inAutoTXLevel;
  }	ResourceOwnerData;
  
  
***************
*** 1339,1341 **** PrintDSMLeakWarning(dsm_segment *seg)
--- 1341,1351 ----
  		 "dynamic shared memory leak: segment %u still referenced",
  		 dsm_segment_handle(seg));
  }
+ 
+ uint8
+ GetCurrentResourceOwnerAutoTXLevel()
+ {
+ 	Assert(CurrentResourceOwner != NULL);
+ 
+ 	return CurrentResourceOwner->inAutoTXLevel;
+ }
*** a/src/include/access/transam.h
--- b/src/include/access/transam.h
***************
*** 163,169 **** extern TransactionId TransactionIdLatest(TransactionId mainxid,
  extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid);
  
  /* in transam/varsup.c */
! extern TransactionId GetNewTransactionId(bool isSubXact);
  extern TransactionId ReadNewTransactionId(void);
  extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
  					  Oid oldest_datoid);
--- 163,170 ----
  extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid);
  
  /* in transam/varsup.c */
! TransactionId GetNewTransactionId(bool isSubXact, int stateNestinglevel,
! 															int autotxlevel);
  extern TransactionId ReadNewTransactionId(void);
  extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
  					  Oid oldest_datoid);
*** a/src/include/access/xact.h
--- b/src/include/access/xact.h
***************
*** 27,32 ****
--- 27,38 ----
  #define XACT_REPEATABLE_READ	2
  #define XACT_SERIALIZABLE		3
  
+ #define IS_TOP_AUTO_TX_STATE(s) \
+ 	( \
+ 		((s)->blockState >= TBLOCK_AUTOBEGIN) \
+ 		&& ((s)->blockState <=  TBLOCK_AUTOABORT_PENDING) \
+ 	)
+ 
  extern int	DefaultXactIsoLevel;
  extern PGDLLIMPORT int XactIsoLevel;
  
***************
*** 258,261 **** extern int	xactGetCommittedChildren(TransactionId **ptr);
--- 264,277 ----
  extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
  extern void xact_desc(StringInfo buf, uint8 xl_info, char *rec);
  
+ extern void DefineAutonomousTransaction(void);
+ extern void BeginInternalAutonomousTransaction(void);
+ extern void CommitInternalAutonomousTransaction(void);
+ extern void AbortInternalAutonomousTransaction(void);
+ extern void BeginAutonomousTransaction(void);
+ extern void CommitAutonomousTransaction(void);
+ extern void AbortAutonomousTransaction(void);
+ extern bool IsCurrentAutoTx(void);
+ 
+ 
  #endif   /* XACT_H */
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
***************
*** 141,146 **** extern Oid	FindDefaultConversionProc(int32 for_encoding, int32 to_encoding);
--- 141,148 ----
  /* initialization & transaction cleanup code */
  extern void InitializeSearchPath(void);
  extern void AtEOXact_Namespace(bool isCommit);
+ extern void AtEOAutoXact_Namespace(bool isCommit, SubTransactionId mySubid,
+ 					  SubTransactionId parentSubid);
  extern void AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
  					  SubTransactionId parentSubid);
  
*** a/src/include/commands/trigger.h
--- b/src/include/commands/trigger.h
***************
*** 185,190 **** extern void AfterTriggerBeginXact(void);
--- 185,191 ----
  extern void AfterTriggerBeginQuery(void);
  extern void AfterTriggerEndQuery(EState *estate);
  extern void AfterTriggerFireDeferred(void);
+ extern void AfterTriggerFireDeferredForAutoX(void);
  extern void AfterTriggerEndXact(bool isCommit);
  extern void AfterTriggerBeginSubXact(void);
  extern void AfterTriggerEndSubXact(bool isCommit);
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 2356,2362 **** typedef enum TransactionStmtKind
  	TRANS_STMT_ROLLBACK_TO,
  	TRANS_STMT_PREPARE,
  	TRANS_STMT_COMMIT_PREPARED,
! 	TRANS_STMT_ROLLBACK_PREPARED
  } TransactionStmtKind;
  
  typedef struct TransactionStmt
--- 2356,2363 ----
  	TRANS_STMT_ROLLBACK_TO,
  	TRANS_STMT_PREPARE,
  	TRANS_STMT_COMMIT_PREPARED,
! 	TRANS_STMT_ROLLBACK_PREPARED,
! 	TRANS_STMT_AUTONOMOUS
  } TransactionStmtKind;
  
  typedef struct TransactionStmt
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 51,56 **** PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
--- 51,57 ----
  PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
  PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD)
  PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
+ PG_KEYWORD("autonomous_transaction", AUTONOMOUS_TRANSACTION, UNRESERVED_KEYWORD)
  PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
  PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
  PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
***************
*** 285,290 **** PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
--- 286,292 ----
  PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
  PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
  PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD)
+ PG_KEYWORD("pragma", PRAGMA, UNRESERVED_KEYWORD)
  PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD)
  PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD)
  PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD)
*** a/src/include/storage/lock.h
--- b/src/include/storage/lock.h
***************
*** 77,82 **** typedef struct
--- 77,83 ----
  	((vxid).backendId = (proc).backendId, \
  	 (vxid).localTransactionId = (proc).lxid)
  
+ #define     MAX_AUTOX_NESTING_LEVEL   3
  
  /*
   * LOCKMODE is an integer (1..N) indicating a lock type.  LOCKMASK is a bit
***************
*** 363,368 **** typedef struct PROCLOCK
--- 364,371 ----
  
  	/* data */
  	LOCKMASK	holdMask;		/* bitmask for lock types currently held */
+ 	LOCKMASK	holdMaskByAutoTX[MAX_AUTOX_NESTING_LEVEL];	/* bitmask for lock types currently held by autonomous TX */
+ 	LOCKMASK    holdMaskByNormalTX;
  	LOCKMASK	releaseMask;	/* bitmask for lock types to be released */
  	SHM_QUEUE	lockLink;		/* list link in LOCK's list of proclocks */
  	SHM_QUEUE	procLink;		/* list link in PGPROC's list of proclocks */
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
***************
*** 141,146 **** struct PGPROC
--- 141,148 ----
  	bool		fpVXIDLock;		/* are we holding a fast-path VXID lock? */
  	LocalTransactionId fpLocalTransactionId;	/* lxid for fast-path VXID
  												 * lock */
+ 
+ 	uint8 inAutoTXLevel;
  };
  
  /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */
***************
*** 148,153 **** struct PGPROC
--- 150,156 ----
  
  extern PGDLLIMPORT PGPROC *MyProc;
  extern PGDLLIMPORT struct PGXACT *MyPgXact;
+ extern PGDLLIMPORT struct PGAutonomousXACT *MyPgAutonomousXact;
  
  /*
   * Prior to PostgreSQL 9.2, the fields below were stored as part of the
***************
*** 176,181 **** typedef struct PGXACT
--- 179,196 ----
  	uint8		nxids;
  } PGXACT;
  
+ typedef struct PGAutonomousXACT
+ {
+ 	TransactionId   xid;
+ 	TransactionId   xmin;
+ 
+ 	int			nestingLevel;	/* transaction nesting depth */
+ 	struct XidCache subxids;    /* cache for subtransaction XIDs */
+ 	bool		overflowed;
+ 	bool		delayChkpt;		/* true if this proc delays checkpoint start*/
+ 	uint8		 nxids;         /* number of subtransactions */
+ } PGAutonomousXACT;
+ 
  /*
   * There is one ProcGlobal struct for the whole database cluster.
   */
***************
*** 185,190 **** typedef struct PROC_HDR
--- 200,209 ----
  	PGPROC	   *allProcs;
  	/* Array of PGXACT structures (not including dummies for prepared txns) */
  	PGXACT	   *allPgXact;
+ 
+ 	/* Array of PGAutonomous transaction structure*/
+ 	PGAutonomousXACT *allPgAutonomousXact;
+ 
  	/* Length of allProcs array */
  	uint32		allProcCount;
  	/* Head of list of free PGPROC structures */
***************
*** 256,259 **** extern void LockErrorCleanup(void);
--- 275,280 ----
  extern void ProcWaitForSignal(void);
  extern void ProcSendSignal(int pid);
  
+ extern PGAutonomousXACT *GetCurrentPGAutonomousXACT(void);
+ 
  #endif   /* PROC_H */
*** a/src/include/storage/procarray.h
--- b/src/include/storage/procarray.h
***************
*** 25,30 **** extern void ProcArrayAdd(PGPROC *proc);
--- 25,31 ----
  extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid);
  
  extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid);
+ extern void ProcArrayEndAutonomousTransaction(PGPROC *proc, TransactionId latestXid);
  extern void ProcArrayClearTransaction(PGPROC *proc);
  
  extern void ProcArrayInitRecovery(TransactionId initializedUptoXID);
***************
*** 79,88 **** extern void XidCacheRemoveRunningXids(TransactionId xid,
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid);
  
  extern void ProcArraySetReplicationSlotXmin(TransactionId xmin,
  							TransactionId catalog_xmin, bool already_locked);
  
  extern void ProcArrayGetReplicationSlotXmin(TransactionId *xmin,
  											TransactionId *catalog_xmin);
- 
  #endif   /* PROCARRAY_H */
--- 80,92 ----
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid);
  
+ extern void XidCacheRemoveAutoRunningXids(TransactionId xid,
+ 						  int nxids, const TransactionId *xids,
+ 						  TransactionId latestXid, bool isTopAutoTX);
+ 
  extern void ProcArraySetReplicationSlotXmin(TransactionId xmin,
  							TransactionId catalog_xmin, bool already_locked);
  
  extern void ProcArrayGetReplicationSlotXmin(TransactionId *xmin,
  											TransactionId *catalog_xmin);
  #endif   /* PROCARRAY_H */
*** a/src/include/storage/sinval.h
--- b/src/include/storage/sinval.h
***************
*** 142,148 **** extern void EnableCatchupInterrupt(void);
  extern bool DisableCatchupInterrupt(void);
  
  extern int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
! 									 bool *RelcacheInitFileInval);
  extern void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
  									 int nmsgs, bool RelcacheInitFileInval,
  									 Oid dbid, Oid tsid);
--- 142,148 ----
  extern bool DisableCatchupInterrupt(void);
  
  extern int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
! 									 bool *RelcacheInitFileInval, bool isAutoXact);
  extern void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
  									 int nmsgs, bool RelcacheInitFileInval,
  									 Oid dbid, Oid tsid);
*** a/src/include/utils/catcache.h
--- b/src/include/utils/catcache.h
***************
*** 174,179 **** extern HeapTuple SearchCatCache(CatCache *cache,
--- 174,183 ----
  			   Datum v3, Datum v4);
  extern void ReleaseCatCache(HeapTuple tuple);
  
+ extern HeapTuple SearchSystableForAutoX(CatCache *cache, Datum v1, Datum v2,
+ 											Datum v3, Datum v4);
+ extern void ReleaseHeapTupleforAutoX(HeapTuple tuple);
+ 
  extern uint32 GetCatCacheHashValue(CatCache *cache,
  					 Datum v1, Datum v2,
  					 Datum v3, Datum v4);
*** a/src/include/utils/inval.h
--- b/src/include/utils/inval.h
***************
*** 33,38 **** extern void AtEOXact_Inval(bool isCommit);
--- 33,40 ----
  
  extern void AtEOSubXact_Inval(bool isCommit);
  
+ extern void AtEOAutoXact_Inval(bool isCommit);
+ 
  extern void AtPrepare_Inval(void);
  
  extern void PostPrepare_Inval(void);
*** a/src/include/utils/portal.h
--- b/src/include/utils/portal.h
***************
*** 194,199 **** typedef struct PortalData
--- 194,200 ----
  /* Prototypes for functions in utils/mmgr/portalmem.c */
  extern void EnablePortalManager(void);
  extern bool PreCommit_Portals(bool isPrepare);
+ extern bool AutoPreCommit_Portals(uint32 createSubid);
  extern void AtAbort_Portals(void);
  extern void AtCleanup_Portals(void);
  extern void AtSubCommit_Portals(SubTransactionId mySubid,
*** a/src/include/utils/resowner.h
--- b/src/include/utils/resowner.h
***************
*** 78,82 **** extern void RegisterResourceReleaseCallback(ResourceReleaseCallback callback,
--- 78,83 ----
  								void *arg);
  extern void UnregisterResourceReleaseCallback(ResourceReleaseCallback callback,
  								  void *arg);
+ extern uint8 GetCurrentResourceOwnerAutoTXLevel(void);
  
  #endif   /* RESOWNER_H */
