Autonomous Transaction (WIP)

Started by Rajeev rastogialmost 12 years ago47 messages
#1Rajeev rastogi
rajeev.rastogi@huawei.com
1 attachment(s)

I would like to propose "Autonomous Transaction" feature for 9.5. Details for the same are mentioned below:

What is Autonomous Transaction?
An autonomous transaction has its own COMMIT and ROLLBACK scope to ensure that its outcome does not affect the caller's uncommitted changes. Additionally, the COMMITs and ROLLBACK in the calling transaction should not affect the changes that were finalized on the completion of autonomous transaction itself. Below are properties of autonomous transaction:

1. The autonomous transaction does not see uncommitted changes made by the main transaction and does not share locks or resources with main transaction.

2. Changes in autonomous transactions are visible to other transactions upon commit of the autonomous transactions. Thus, users can access the updated information without having to wait for the main transaction to commit.

3. Autonomous transactions can start other autonomous transaction. There are no limit, other than resource limits, on how many levels of autonomous transaction can be started.

Use-case:
There are many use-case for this feature. One of the use-case is illustrated below
Say a procedure is defined, which does some operation on the database and incase of any failure in operation on main table, it maintains the failure information in a separate relation. But because of current transaction behavior, once main table operation fails, it will rollback whole transaction and hence error logged in error relation will be also lost, which might have been required for future analysis.
In order to solve this issue, we can use autonomous transaction as shown below:
CREATE OR REPLACE function operation(err_msg IN VARCHAR) returns void AS $$
BEGIN
INSERT INTO at_test(id, description) VALUES (998, 'Description for 998');
INSERT INTO at_test(id, description) VALUES (999, NULL);
EXCEPTION
WHEN OTHER THEN
PRAGMA AUTONOMOUS TRANSACTION;
INSERT INTO error_logs(id, timestamp, err_msg) VALUES(nextval('errno'), timenow(), err_msg);
COMMIT;
RAISE not_null_violation;
END;
$$ LANGUAGE plpgsql;
So once we execute above procedure, second INSERT will fails and then within exception handling it will start autonomous transaction and log the error information in a separate table and then gets committed. So though operation to table at_test will fail and rollback, error information will persist in the error_logs table. After execution of procedure, record in two tables will be as below:
Postgres=# select * from error_logs;
id | log_time | err_msg
----+---------------------+---------
5 | 2014-01-17 19:57:11 | error
postgres=# select * from at_test;
id | decsription
----+-------------
(0 rows)

Syntax:
Syntax to create autonomous transaction can be as:
PRAGMA AUTONOMOUS TRANSACTION;
This can be used with independent SQL commands, from procedure, triggers.

Implementation:
Implementation of autonomous transaction is based on the existing sub-transaction and main transaction. Most of the implementations are re-used for autonomous transaction also. Below are the brief details about the same:

Autonomous Transaction Storage:
As for main transaction, structure PGXACT is used to store main transactions, which are created in shared memory of size:
(Number of process)*sizeof(struct PGXACT)
Similarly a new structure will be defined to store autonomous transaction:
Struct PGAutonomousXACT
{
TransactionId xid;
TransactionId xmin;
/* Store the level below main transaction as stored for sub-transaction*/
int nestingLevel;
struct XidCache subxids;
bool overflowed;
bool delaychkpt;
uint nxids;
} PGAutonomousXACT;
All structure members of PGAutonomousXACT are same as used in PGXACT except nestingLevel as marked in bold color to store the level of transaction.
Similar to main transaction, the memory allocated to store autonomous transaction will be:
(Number of process) * sizeof (struct PGAutonomousXACT)*MAX_AUTO_TX_LEVEL
Where MAX_AUTO_TX_LEVEL is maximum number of nested autonomous transaction level.
Unlike main transaction, autonomous transaction cannot be accessed directly. It can be accessed using offset as:
(Process number)*MAX_AUTO_TX_LEVEL + (current auto tx level)
Where 'current auto tx level' is autonomous transaction level in current process (which will be maintained in MyProc structure).

Definition of Autonomous Transaction:
Autonomous transaction will be defined in similar way as sub-transaction except few additional info (like level of autonomous transaction in MyProc) about autonomous transaction will be initialized.

Starting of Autonomous Transaction:
Starting of autonomous transaction will be exactly same as starting sub-transaction.

Committing of Autonomous Transaction:
Commit uses mix approach of main and sub-transaction to perform commit:

1. Commit of record and logging the corresponding WAL happens in the same way as main transaction (except the way autonomous transaction and their sub-transaction accessed).

2. Freeing of all resource and popping of previous transaction happens in the same way as sub-transaction.

Data Visibility for Autonomous Transaction:
Autonomous transaction will be treated as independent and similar to main transaction while taking the snapshot. For each process, all running autonomous transaction (except the current one) and their sub-transaction (if any) will be added to transaction list of snapshot.
Suppose below processes are running with given transactions:
Proc-1

Proc-2

Proc-3

100

101

105

102 (Auto Tx1)

106 (Auto Tx1)

103 (Auto Tx1)

107 (Auto Tx2)

104 (Auto Tx2 sub-tx)

Suppose latest completed transaction is 108.
Then Snapshot data for autonomous transaction 107 will be as below:
Xmin: 100
Xmax: 109
Snapshot->xip[]: 100, 101, 102, 103, 105, 106
Snapshot->subxip[]: 104

System Cache:
As per current design, subsequent search for a same tuple from same session results in getting tuple from system cache itself. Since autonomous transaction is not supposed to see the changes done by main transaction, so it should not search in the system cache which was updated by main transaction otherwise it will end-up in seeing changes done by main transaction. So in order to avoid this, we can take one of the approaches:

1. It should always search from the system table and should not add tuple to system cache. This will keep the design simple but performance will be impacted if same tuple is searched multiple times.

2. We can maintain one system cache for each transaction for each system tables i.e. for each system table per process, number of cache will be:
MAX_AUTO_TX_LEVEL + 1 (For Main transaction)
So then autonomous transaction will have to search and insert the tuple in the corresponding cache of the transaction. This will use more resources to manage more number of caches but performance will not be impacted.
First approach is used in current patch.

Deadlock Detection:
It is possible that the main or upper autonomous transaction has taken a lock on some resource, which might be required by lower autonomous transaction. If it happens so then deadlock will occur. So in order to solve this issue, each main and autonomous transaction will hold list of all locks acquired in PROLOCK based on which deadlock will be resolved.

Plan to push it into 9.5:

1. Initially we can plan to support only along with standalone SQL-commands. This will create infrastructure for future work.

2. Then in further CommitFest/Release, we can plan to support this inside the Procedure (this will require to create infrastructure to do autonomous transaction operation inside procedure) and triggers also.

Any Comments/Suggestions/Feedbacks are welcome.

Thanks and Regards,
Kumar Rajeev Rastogi

Attachments:

autonomous_tx_v0.patchapplication/octet-stream; name=autonomous_tx_v0.patchDownload
*** 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
***************
*** 3787,3792 **** AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
--- 3787,3841 ----
  	}
  }
  
+ 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;
***************
*** 10750,10755 **** PreCommit_on_commit_actions(void)
--- 10754,10761 ----
  				/* 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
***************
*** 10763,10768 **** PreCommit_on_commit_actions(void)
--- 10769,10777 ----
  				{
  					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;
+ 		}
  	}
  
  	/*
***************
*** 2042,2047 **** GetVirtualXIDsDelayingChkpt(int *nvxids)
--- 2138,2146 ----
  		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,
--- 2894,2979 ----
  	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);
  
***************
*** 4082,4084 **** VirtualXactLock(VirtualTransactionId vxid, bool wait)
--- 4140,4183 ----
  	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
***************
*** 140,145 **** extern Oid	FindDefaultConversionProc(int32 for_encoding, int32 to_encoding);
--- 140,147 ----
  /* 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 */
#2Pavel Stehule
pavel.stehule@gmail.com
In reply to: Rajeev rastogi (#1)
Re: Autonomous Transaction (WIP)

Hello

+1 for feature
-1 for Oracle syntax - it is hardly inconsistent with Postgres

Autonomous transactions should be used everywhere - not only in plpgsql

Regards

Pavel

2014-04-07 6:06 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

Show quoted text

I would like to propose “Autonomous Transaction” feature for 9.5.
Details for the same are mentioned below:

*What is Autonomous Transaction?*

An autonomous transaction has its own COMMIT and ROLLBACK scope to ensure
that its outcome does not affect the caller’s uncommitted changes.
Additionally, the COMMITs and ROLLBACK in the calling transaction should
not affect the changes that were finalized on the completion of autonomous
transaction itself. Below are properties of autonomous transaction:

1. The autonomous transaction does not see uncommitted changes made
by the main transaction and does not share locks or resources with main
transaction.

2. Changes in autonomous transactions are visible to other
transactions upon commit of the autonomous transactions. Thus, users can
access the updated information without having to wait for the main
transaction to commit.

3. Autonomous transactions can start other autonomous transaction.
There are no limit, other than resource limits, on how many levels of
autonomous transaction can be started.

*Use-case:*

There are many use-case for this feature. One of the use-case is
illustrated below

Say a procedure is defined, which does some operation on the
database and incase of any failure in operation on main table, it maintains
the failure information in a separate relation. But because of current
transaction behavior, once main table operation fails, it will rollback
whole transaction and hence error logged in error relation will be also
lost, which might have been required for future analysis.

In order to solve this issue, we can use autonomous transaction as
shown below:

*CREATE OR REPLACE function operation(err_msg IN VARCHAR) returns void AS
$$*

*BEGIN*

* INSERT INTO at_test(id, description) VALUES (998,
‘Description for 998’);*

* INSERT INTO at_test(id, description) VALUES (999, NULL);*

*EXCEPTION*

* WHEN OTHER THEN*

* PRAGMA AUTONOMOUS TRANSACTION;*

* INSERT INTO error_logs(id, timestamp,
err_msg) VALUES(nextval(‘errno’), timenow(), err_msg);*

* COMMIT;*

* RAISE not_null_violation;*

*END;*

*$$ LANGUAGE plpgsql;*

So once we execute above procedure, second INSERT will fails and then
within exception handling it will start autonomous transaction and log the
error information in a separate table and then gets committed. So though
operation to table at_test will fail and rollback, error information will
persist in the error_logs table. After execution of procedure, record in
two tables will be as below:

*Postgres=# select * from error_logs;*

*id | log_time | err_msg*

*----+---------------------+---------*

* 5 | 2014-01-17 19:57:11 | error*

*postgres=# select * from at_test;*

*id | decsription*

*----+-------------*

*(0 rows)*

*Syntax:*

Syntax to create autonomous transaction can be as:

*PRAGMA AUTONOMOUS TRANSACTION;*

This can be used with independent SQL commands, from procedure, triggers.

*Implementation:*

Implementation of autonomous transaction is based on the existing
sub-transaction and main transaction. Most of the implementations are
re-used for autonomous transaction also. Below are the brief details about
the same:

*Autonomous Transaction Storage:*

As for main transaction, structure PGXACT is used to store main
transactions, which are created in shared memory of size:

(Number of process)*sizeof(struct PGXACT)

Similarly a new structure will be defined to store autonomous transaction:

*Struct PGAutonomousXACT*

*{*

* TransactionId xid;*

* TransactionId xmin;*

* /* Store the level below main transaction as stored for
sub-transaction*/*

* int nestingLevel;*

* struct XidCache subxids;*

* bool overflowed;*

* bool delaychkpt;*

* uint nxids;*

*} PGAutonomousXACT;*

All structure members of PGAutonomousXACT are same as used in PGXACT
except nestingLevel as marked in bold color to store the level of
transaction.

Similar to main transaction, the memory allocated to store autonomous
transaction will be:

*(Number of process) * sizeof (struct PGAutonomousXACT)*MAX_AUTO_TX_LEVEL*

Where MAX_AUTO_TX_LEVEL is maximum number of nested autonomous transaction
level.

Unlike main transaction, autonomous transaction cannot be accessed
directly. It can be accessed using offset as:

*(Process number)*MAX_AUTO_TX_LEVEL + (current auto tx level)*

Where ‘current auto tx level’ is autonomous transaction level in current
process (which will be maintained in MyProc structure).

*Definition of Autonomous Transaction:*

Autonomous transaction will be defined in similar way as sub-transaction
except few additional info (like level of autonomous transaction in MyProc)
about autonomous transaction will be initialized.

*Starting of Autonomous Transaction:*

Starting of autonomous transaction will be exactly same as starting
sub-transaction.

*Committing of Autonomous Transaction:*

Commit uses mix approach of main and sub-transaction to perform commit:

1. Commit of record and logging the corresponding WAL happens in the
same way as main transaction (except the way autonomous transaction and
their sub-transaction accessed).

2. Freeing of all resource and popping of previous transaction
happens in the same way as sub-transaction.

*Data Visibility for Autonomous Transaction:*

Autonomous transaction will be treated as independent and similar to main
transaction while taking the snapshot. For each process, all running
autonomous transaction (except the current one) and their sub-transaction
(if any) will be added to transaction list of snapshot.

Suppose below processes are running with given transactions:

Proc-1

Proc-2

Proc-3

100

101

105

102 (Auto Tx1)

106 (Auto Tx1)

103 (Auto Tx1)

107 (Auto Tx2)

104 (Auto Tx2 sub-tx)

Suppose latest completed transaction is 108.

Then Snapshot data for autonomous transaction 107 will be as below:

*Xmin: 100*

*Xmax: 109*

*Snapshot->xip[]: 100, 101, 102, 103, 105,
106 *

*Snapshot->subxip[]: 104*

*System Cache:*

As per current design, subsequent search for a same tuple from same
session results in getting tuple from system cache itself. Since autonomous
transaction is not supposed to see the changes done by main transaction, so
it should not search in the system cache which was updated by main
transaction otherwise it will end-up in seeing changes done by main
transaction. So in order to avoid this, we can take one of the approaches:

1. It should always search from the system table and should not add
tuple to system cache. This will keep the design simple but performance
will be impacted if same tuple is searched multiple times.

2. We can maintain one system cache for each transaction for each
system tables i.e. for each system table per process, number of cache will
be:

MAX_AUTO_TX_LEVEL + 1 (For Main
transaction)

So then autonomous transaction will have to search and insert the tuple in
the corresponding cache of the transaction. This will use more resources to
manage more number of caches but performance will not be impacted.

First approach is used in current patch.

*Deadlock Detection:*

It is possible that the main or upper autonomous transaction has taken a
lock on some resource, which might be required by lower autonomous
transaction. If it happens so then deadlock will occur. So in order to
solve this issue, each main and autonomous transaction will hold list of
all locks acquired in PROLOCK based on which deadlock will be resolved.

*Plan to push it into 9.5:*

1. Initially we can plan to support only along with standalone
SQL-commands. This will create infrastructure for future work.

2. Then in further CommitFest/Release, we can plan to support this
inside the Procedure (this will require to create infrastructure to do
autonomous transaction operation inside procedure) and triggers also.

Any Comments/Suggestions/Feedbacks are welcome.

*Thanks and Regards,*

*Kumar Rajeev Rastogi *

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Craig Ringer
craig@2ndquadrant.com
In reply to: Rajeev rastogi (#1)
Re: Autonomous Transaction (WIP)

On 04/07/2014 12:06 PM, Rajeev rastogi wrote:

Syntax to create autonomous transaction can be as:

*/PRAGMA AUTONOMOUS TRANSACTION;/*

Wouldn't you want to use SET TRANSACTION for this?

Or a suffix on BEGIN, like BEGIN AUTONOMOUS TRANSACTION ?

What's the logic behind introducing "PRAGMA" ?

If you wanted to use that syntax for Oracle compatibility you'd need to use:

PRAGMA AUTONOMOUS_TRANSACTION;

(note underscore). But really, this would no be a pragma at all,
PostgreSQL doesn't really have the concept. Calling it that would just
be misleading.

*_Starting of Autonomous Transaction:_*

Starting of autonomous transaction will be exactly same as starting
sub-transaction.

If you don't want it to dirty read data from the parent tx, or inherit
parent locks, then it cannot be the same at all.

2. Freeing of all resource and popping of previous transaction
happens in the same way as sub-transaction.

I'm not sure what you mean here.

Overall, this looks like a HUGE job to make work well. I know some
others have been doing work along the same lines, so hopefully you'll be
able to collaborate and share ideas.

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Ian Barwick
ian@2ndquadrant.com
In reply to: Craig Ringer (#3)
Re: Autonomous Transaction (WIP)

On 07/04/14 15:50, Craig Ringer wrote:

On 04/07/2014 12:06 PM, Rajeev rastogi wrote:

Syntax to create autonomous transaction can be as:

*/PRAGMA AUTONOMOUS TRANSACTION;/*

Wouldn't you want to use SET TRANSACTION for this?

Or a suffix on BEGIN, like BEGIN AUTONOMOUS TRANSACTION ?

What's the logic behind introducing "PRAGMA" ?

If you wanted to use that syntax for Oracle compatibility you'd need to use:

PRAGMA AUTONOMOUS_TRANSACTION;

(note underscore).

FWIW the implementation in the patch uses "PRAGMA
AUTONOMOUS_TRANSACTION", the space is presumably a typo.

Regards

Ian Barwick

--
Ian Barwick http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Craig Ringer (#3)
Re: Autonomous Transaction (WIP)

On 07 April 2014 12:20, Craig Ringer

Syntax to create autonomous transaction can be as:

*/PRAGMA AUTONOMOUS TRANSACTION;/*

Wouldn't you want to use SET TRANSACTION for this?

Or a suffix on BEGIN, like BEGIN AUTONOMOUS TRANSACTION ?

What's the logic behind introducing "PRAGMA" ?

If you wanted to use that syntax for Oracle compatibility you'd need to
use:

PRAGMA AUTONOMOUS_TRANSACTION;

(note underscore). But really, this would no be a pragma at all,
PostgreSQL doesn't really have the concept. Calling it that would just
be misleading.

Actually it is same as oracle (i.e. PRAGMA AUTONOMOUS_TRANSACTION), it was just typo mistake in previous mail.
But if this is also not accepted then we can discuss and come out with a syntax based on everyone agreement.

*_Starting of Autonomous Transaction:_*

Starting of autonomous transaction will be exactly same as starting
sub-transaction.

If you don't want it to dirty read data from the parent tx, or inherit
parent locks, then it cannot be the same at all.

While starting sub-transaction, it is just initializing the resources required and
links the same to the parent transaction, which we require for autonomous transaction also.
I am not able to notice any issue as you mentioned above with this.
Please let me know if I am missing something or misunderstood your concern.

2. Freeing of all resource and popping of previous transaction
happens in the same way as sub-transaction.

I'm not sure what you mean here.

It means, during commit of autonomous transaction, freeing of all resource are done in the same way as done for sub-transaction.
Also current autonomous transaction gets popped out and points to the parent transaction in the similar way as done for sub-transaction.

Overall, this looks like a HUGE job to make work well. I know some
others have been doing work along the same lines, so hopefully you'll
be able to collaborate and share ideas.

Yes it is huge works, so I have proposed in the beginning of 9.5 so that we can have multiple round of discussion and hence address
all concerns.
Also I have proposed to finish this feature in multiple rounds i.e. first patch, we can try to support autonomous transaction from
standalone SQL-command only, which will set-up infrastructure for future work in this area.

Using the WIP patch sent, I have done basic testing and it works fine.

Any comments?

Thanks and Regards,
Kumar Rajeev Rastogi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Rajeev rastogi (#5)
Re: Autonomous Transaction (WIP)

On 07 April 2014 12:12, Pavel Stehule wrote:

+1 for feature

Thanks

-1 for Oracle syntax - it is hardly inconsistent with Postgres

We can discuss and come out with the syntax based on everyone agreement.

Autonomous transactions should be used everywhere - not only in plpgsql

Yes you are right. I am not planning to support only using plpgsql. Initially we can support this
Using the standalone SQL-commands and then later we can enhance based on this infrastructure
to be used using plpgsql, triggers.

Thanks and Regards,
Kumar Rajeev Rastogi

#7Pavel Stehule
pavel.stehule@gmail.com
In reply to: Rajeev rastogi (#6)
Re: Autonomous Transaction (WIP)

2014-04-07 11:59 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

On 07 April 2014 12:12, Pavel Stehule wrote:

+1 for feature

Thanks

-1 for Oracle syntax - it is hardly inconsistent with Postgres

We can discuss and come out with the syntax based on everyone agreement.

Autonomous transactions should be used everywhere - not only in plpgsql

Yes you are right. I am not planning to support only using plpgsql.
Initially we can support this

Using the standalone SQL-commands and then later we can enhance based on
this infrastructure

to be used using plpgsql, triggers.

ok

long time I though about this feature.

I am thinking so this should be fully isolated transaction - it should not
be subtransaction, because then you can break database consistency - RI

I am happy so someone does this job

Regards

Pavel

Show quoted text

*Thanks and Regards,*

*Kumar Rajeev Rastogi *

#8Atri Sharma
atri.jiit@gmail.com
In reply to: Pavel Stehule (#7)
Re: Autonomous Transaction (WIP)

On Mon, Apr 7, 2014 at 3:41 PM, Pavel Stehule <pavel.stehule@gmail.com>wrote:

2014-04-07 11:59 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

On 07 April 2014 12:12, Pavel Stehule wrote:

+1 for feature

Thanks

-1 for Oracle syntax - it is hardly inconsistent with Postgres

We can discuss and come out with the syntax based on everyone agreement.

Autonomous transactions should be used everywhere - not only in plpgsql

Yes you are right. I am not planning to support only using plpgsql.
Initially we can support this

Using the standalone SQL-commands and then later we can enhance based on
this infrastructure

to be used using plpgsql, triggers.

ok

long time I though about this feature.

I am thinking so this should be fully isolated transaction - it should not
be subtransaction, because then you can break database consistency - RI

I am missing something here, but how does making it a subtransaction break
consistency? Isnt that what should actually be happening so that the
autonomous transaction's changes are actually visible till the parent
transaction commits?

What am I missing here?

Regards,

Atri

#9Andres Freund
andres@2ndquadrant.com
In reply to: Atri Sharma (#8)
Re: Autonomous Transaction (WIP)

On 2014-04-07 15:46:42 +0530, Atri Sharma wrote:

On Mon, Apr 7, 2014 at 3:41 PM, Pavel Stehule <pavel.stehule@gmail.com>wrote:
I am missing something here, but how does making it a subtransaction break
consistency? Isnt that what should actually be happening so that the
autonomous transaction's changes are actually visible till the parent
transaction commits?

What am I missing here?

START TRANSACTION;
INSERT INTO referenced_to_table ... id = 1;
START AUTONOMOUS SUBTRANSACTION;
INSERT INTO referencing_table id = 1 ...;
COMMIT AUTONOMOUS SUBTRANSACTION;
ROLLBACK;

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Pavel Stehule
pavel.stehule@gmail.com
In reply to: Atri Sharma (#8)
Re: Autonomous Transaction (WIP)

2014-04-07 12:16 GMT+02:00 Atri Sharma <atri.jiit@gmail.com>:

On Mon, Apr 7, 2014 at 3:41 PM, Pavel Stehule <pavel.stehule@gmail.com>wrote:

2014-04-07 11:59 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

On 07 April 2014 12:12, Pavel Stehule wrote:

+1 for feature

Thanks

-1 for Oracle syntax - it is hardly inconsistent with Postgres

We can discuss and come out with the syntax based on everyone agreement.

Autonomous transactions should be used everywhere - not only in plpgsql

Yes you are right. I am not planning to support only using plpgsql.
Initially we can support this

Using the standalone SQL-commands and then later we can enhance based on
this infrastructure

to be used using plpgsql, triggers.

ok

long time I though about this feature.

I am thinking so this should be fully isolated transaction - it should
not be subtransaction, because then you can break database consistency - RI

I am missing something here, but how does making it a subtransaction break
consistency? Isnt that what should actually be happening so that the
autonomous transaction's changes are actually visible till the parent
transaction commits?

commit of autonomous transaction doesn't depends on outer transaction. So
anything what you can do, should be independent on outer transaction.

Pavel

Show quoted text

What am I missing here?

Regards,

Atri

#11Greg Stark
stark@mit.edu
In reply to: Rajeev rastogi (#1)
Re: Autonomous Transaction (WIP)

On Mon, Apr 7, 2014 at 12:06 AM, Rajeev rastogi
<rajeev.rastogi@huawei.com> wrote:

Deadlock Detection:

It is possible that the main or upper autonomous transaction has taken a lock on some resource, which might be required by lower autonomous transaction. If it happens so then deadlock will occur. So in order to solve this issue, each main and autonomous transaction will hold list of all locks acquired in PROLOCK based on which deadlock will be resolved.

I'm not sure how this would work out internally -- it would depend on
how you plan to allocate the new transaction in the internal data
structures -- but the natural way to prevent/detect deadlocks would be
to have the parent transaction immediately take a lock on the
autonomous transaction as soon as it's started. That would cause any
lock in the autonomous transaction which caused it to wait on the
parent transaction to be detected as a deadlock. It would also cause
any monitoring tool to correctly show the parent transaction as
waiting on the autonomous transaction to finish.

If the autonomous transaction is actually a separate procarray entry
(which I suspect it would have to be, much like prepared transactions
and the dblink connections which are commonly used to kludge
autonomous transactions) then this should be fairly painless. If you
implement some kind of saving and restoring procarray data then it
probably wouldn't work out.

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Greg Stark (#11)
Re: Autonomous Transaction (WIP)

Greg Stark wrote:

If the autonomous transaction is actually a separate procarray entry
(which I suspect it would have to be, much like prepared transactions
and the dblink connections which are commonly used to kludge
autonomous transactions) then this should be fairly painless. If you
implement some kind of saving and restoring procarray data then it
probably wouldn't work out.

I don't have time to digest this proposal ATM, but in previous occasion
when we have discussed autonomous transactions (ATs), we have always
considered natural that they have their own procarray entries; there are
too many strange issues otherwise.

Since the number of procarray entries is fixed at startup time, one
natural consequence of this is that the number of ATs in flight at any
moment is also fixed. Normally we consider allocating a single AT per
session to be sufficient. So you can't have one AT start another AT,
for instance -- that seems a reasonable restriction.

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#12)
Re: Autonomous Transaction (WIP)

On Tue, Apr 8, 2014 at 2:43 PM, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Greg Stark wrote:

If the autonomous transaction is actually a separate procarray entry
(which I suspect it would have to be, much like prepared transactions
and the dblink connections which are commonly used to kludge
autonomous transactions) then this should be fairly painless. If you
implement some kind of saving and restoring procarray data then it
probably wouldn't work out.

I don't have time to digest this proposal ATM, but in previous occasion
when we have discussed autonomous transactions (ATs), we have always
considered natural that they have their own procarray entries; there are
too many strange issues otherwise.

Since the number of procarray entries is fixed at startup time, one
natural consequence of this is that the number of ATs in flight at any
moment is also fixed. Normally we consider allocating a single AT per
session to be sufficient. So you can't have one AT start another AT,
for instance -- that seems a reasonable restriction.

It depends. A lot of Oracle users are used to having autonomous
transactions be very cheap, so you can just mark random procedures as
running in an autonomous transaction and forget about it. If the call
stack is several levels deep, then you could easily have one such
procedure call another such procedure. Of course, you may feel that's
bad practice or that we shouldn't emulate what $COMPETITOR does, and I
agree we don't have to necessarily do it that way just because they do
it that way, but I'm not sure it's accurate to say that nobody will
care.

I'm also pretty unconvinced that multiple PGPROCs is the right way to
go. First, PGPROCs have a bunch of state in them that is assumed to
exist once per backend. We might find pretty substantial code churn
there if we try to go change that. Second, why do other backends
really need to know about our ATs? As far as I can see, if other
backends see the AT as a subtransaction of our top-level transaction
up until it actually commits, that ought to be just fine. Maybe the
backend needs to internally frob visibility rules, but that's not a
matter for shared memory.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Andres Freund
andres@2ndquadrant.com
In reply to: Robert Haas (#13)
Re: Autonomous Transaction (WIP)

On 2014-04-08 15:39:18 -0400, Robert Haas wrote:

I'm also pretty unconvinced that multiple PGPROCs is the right way to
go. First, PGPROCs have a bunch of state in them that is assumed to
exist once per backend. We might find pretty substantial code churn
there if we try to go change that. Second, why do other backends
really need to know about our ATs? As far as I can see, if other
backends see the AT as a subtransaction of our top-level transaction
up until it actually commits, that ought to be just fine. Maybe the
backend needs to internally frob visibility rules, but that's not a
matter for shared memory.

Agreed. That's also how I imagined things to work.

I think except the visibility semantics, there's really not that much to
do if we were to reuse the subtransaction framework. There's some
complications with Hot Standby, but I think those can be solved.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#13)
Re: Autonomous Transaction (WIP)

Robert Haas <robertmhaas@gmail.com> writes:

I'm also pretty unconvinced that multiple PGPROCs is the right way to
go. First, PGPROCs have a bunch of state in them that is assumed to
exist once per backend. We might find pretty substantial code churn
there if we try to go change that. Second, why do other backends
really need to know about our ATs? As far as I can see, if other
backends see the AT as a subtransaction of our top-level transaction
up until it actually commits, that ought to be just fine.

If we can make it work like that, sure. I'm a bit worried about how you'd
decouple a subtransaction and commit it atomically ... or if that's not
atomic, will it create any problems? The point being that you need to
change both pg_subtrans and pg_clog to make that state transition.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Andres Freund
andres@2ndquadrant.com
In reply to: Tom Lane (#15)
Re: Autonomous Transaction (WIP)

On 2014-04-08 16:13:21 -0400, Tom Lane wrote:

Robert Haas <robertmhaas@gmail.com> writes:

I'm also pretty unconvinced that multiple PGPROCs is the right way to
go. First, PGPROCs have a bunch of state in them that is assumed to
exist once per backend. We might find pretty substantial code churn
there if we try to go change that. Second, why do other backends
really need to know about our ATs? As far as I can see, if other
backends see the AT as a subtransaction of our top-level transaction
up until it actually commits, that ought to be just fine.

If we can make it work like that, sure. I'm a bit worried about how you'd
decouple a subtransaction and commit it atomically ... or if that's not
atomic, will it create any problems? The point being that you need to
change both pg_subtrans and pg_clog to make that state transition.

I think it can be made work sensibly - while those states are changed it
will still appear to be running via the procarray. There's some fun
around suboverflowed entries, but I think that can be handled by
reserving an entry for autonomous transactions.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Greg Stark (#11)
1 attachment(s)
Re: Autonomous Transaction (WIP)

On 08 April 2014 23:29, Greg Stark Wrote:

If the autonomous transaction is actually a separate procarray entry
(which I suspect it would have to be, much like prepared transactions
and the dblink connections which are commonly used to kludge autonomous
transactions) then this should be fairly painless. If you implement
some kind of saving and restoring procarray data then it probably
wouldn't work out.

No, I am not creating a separate procarray entry to maintain autonomous transaction.

Similar to MyPgXact (of type PGXACT), which hold main transaction for a particular session,
I have created another member MyPgAutonomousXact (of type structure PGAutonomousXACT),
which holds autonomous transactions for a particular session.

Unlike MyPgXact, MyPgAutonomousXact will be an array to hold multiple autonomous transactions.
There are no limit, other than resource limits, on how many levels of autonomous transaction
can be started. As of now we have used maximum as 3, which can be changed easily if required or
it can be made configurable also.

MyProc for a particular session just have an entry to track the level of autonomous transaction,
which will be used to reference current autonomous transaction from MyPgAutonomousXact.
e.g. if one autonomous transaction is created and it is currently working under this transaction,
then level inside MyProc will be as 1. Once this transaction is over and popped out, level will
be reduced to zero.

Again like main transaction MyPgXact, MyPgAutonomousXact can also track list of all sub-transaction
and overflowed transaction started within this autonomous transaction.

Deadlock Detection:

I'm not sure how this would work out internally

In order to resolve deadlock, two member variable will be created in the structure PROLOCK:
Bitmask for lock types currently held by autonomous transaction.
LOCKMASK holdMaskByAutoTx[MAX_AUTO_TX_LEVEL]
Bitmask for lock types currently held by main transaction.
LOCKMASK holdMaskByNormalTx

Now when we grant the lock to particular transaction, depending on type of transaction, bit
Mask will be set for either holdMaskByAutoTx or holdMaskByNormalTx.
Similar when lock is ungranted, corresponding bitmask will be reset.

Using the above two information, deadlock will be detected.

Any comment/feedback/doubt are welcome.

Thanks and Regards,
Kumar Rajeev Rastogi

Attachments:

autonomous_tx_v1.patchapplication/octet-stream; name=autonomous_tx_v1.patchDownload
*** 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 */
#18Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Robert Haas (#13)
Re: Autonomous Transaction (WIP)

On 09 April 2014 01:09, Rover Haas Wrote:

I'm also pretty unconvinced that multiple PGPROCs is the right way to
go. First, PGPROCs have a bunch of state in them that is assumed to
exist once per backend. We might find pretty substantial code churn
there if we try to go change that.

Yes you right. That is why I am not creating a separate procarray entry to
maintain autonomous transaction. Please find details in previous reply sent
today sometime back.

Second, why do other backends
really need to know about our ATs? As far as I can see, if other
backends see the AT as a subtransaction of our top-level transaction up
until it actually commits, that ought to be just fine. Maybe the
backend needs to internally frob visibility rules, but that's not a
matter for shared memory.

In order to get snapshot from other session, it will be required by other
session to access autonomous transaction and their sub-transactions.

During snapshot creation, autonomous transaction is considered as main
transaction and list of all running autonomous transaction and their sub-transaction
gets stored in snapshot data.

e.g. Suppose below processes are running with given transactions:

Proc-1: 100
Proc-2: 101, 102 (Auto Tx1), 103 (Auto Tx2), 104 (Sub-tx of Auto Tx2)
Proc-3: 105, 106 (Auto Tx2), 107 (Auto Tx2)

Suppose latest completed transaction is 108.

Then Snapshot data for autonomous transaction 107 will be as below:
Xmin: 100
Xmax: 109
Snapshot->xip[]: 100, 101, 102, 103, 105, 106
Snapshot->subxip[]: 104

Thanks and Regards,
Kumar Rajeev Rastogi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Tom Lane (#15)
Re: Autonomous Transaction (WIP)

On 09 April 2014 01:43, Tom Lane Wrote:

I'm also pretty unconvinced that multiple PGPROCs is the right way to
go. First, PGPROCs have a bunch of state in them that is assumed to
exist once per backend. We might find pretty substantial code churn
there if we try to go change that. Second, why do other backends
really need to know about our ATs? As far as I can see, if other
backends see the AT as a subtransaction of our top-level transaction
up until it actually commits, that ought to be just fine.

If we can make it work like that, sure. I'm a bit worried about how
you'd decouple a subtransaction and commit it atomically ... or if
that's not atomic, will it create any problems?

Though autonomous transaction uses mixed approach of sub-transaction as well as main
transaction, transaction state of autonomous transaction is handled independently.
So depending on the transaction state of autonomous transaction (for commit TBLOCK_AUTOCOMMIT),
this transaction will be committed. While committing:
1. Commit of record and logging the corresponding WAL happens in the same way as main transaction (except the way autonomous transaction and their sub-transaction accessed).
This will take care automatically of updating pg_clog also for autonomous transaction.
2. Also it marks the autonomous transaction finish by setting appropriate fields of MyPgAutonomousXact in similar manner as done for main transaction.
3. Freeing of all resource and popping out of parent transaction happens in the same way as sub-transaction.

The point being that
you need to change both pg_subtrans and pg_clog to make that state
transition.

Yes I am changing both. But no specific changes were required. During commit and assignment of autonomous transaction, it is automatically taken care.

Any comment/feedback/doubt are welcome?

Thanks and Regards,
Kumar Rajeev Rastogi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Rajeev rastogi (#19)
Re: Autonomous Transaction (WIP)

On Wed, Apr 9, 2014 at 11:03 AM, Rajeev rastogi
<rajeev.rastogi@huawei.com>wrote:

Though autonomous transaction uses mixed approach of sub-transaction as
well as main
transaction, transaction state of autonomous transaction is handled
independently.

Whenever I was asked to have a look at implementing this feature, I always
wondered about the great amount of global state that a backend maintains
which is normally tied to a single top transaction. Since AT will have same
characteristics as a top level transaction, I wonder how do you plan to
separate those global state variables ? Sure, we can group them in a
structure and put them on a stack when an AT starts and pop them off when
the original top transaction becomes active again, finding all such global
state variables is going to be tricky.

Thanks,
Pavan

--
Pavan Deolasee
http://www.linkedin.com/in/pavandeolasee

#21Hannu Krosing
hannu@krosing.net
In reply to: Pavan Deolasee (#20)
Re: Autonomous Transaction (WIP)

On 04/09/2014 08:44 AM, Pavan Deolasee wrote:

On Wed, Apr 9, 2014 at 11:03 AM, Rajeev rastogi
<rajeev.rastogi@huawei.com <mailto:rajeev.rastogi@huawei.com>> wrote:

Though autonomous transaction uses mixed approach of
sub-transaction as well as main
transaction, transaction state of autonomous transaction is
handled independently.

Whenever I was asked to have a look at implementing this feature, I
always wondered about the great amount of global state that a backend
maintains which is normally tied to a single top transaction. Since AT
will have same characteristics as a top level transaction, I wonder
how do you plan to separate those global state variables ? Sure, we
can group them in a structure and put them on a stack when an AT
starts and pop them off when the original top transaction becomes
active again, finding all such global state variables is going to be
tricky.

I would hope most of this to be solved by having one (read only) virtual
transaction and
then juggling the ATs in a way similar to current subtransaction machinery.

The main differences would be that:

A) the top level transaction stays virtual

and

B) ATs are committed independantly

This would be greatly simplified if we can accept the restriction that
there is only single
snapshot per backend (not per transaction). To me this seems a
completely sensible restriction.

Re syntax, I think we need a way to name the transactions so we can have
a way
to switch between multiple parallel active autonomous transactions.

-----
BEGIN TRANSACTION myfirsttransaction;

do something in myfirsttransaction;

BEGIN TRANSACTION anothertransaction;

do something in anothertransaction;

SET TRANSACTION myfirsttransaction;

more work in myfirsttransaction;

ROLLBACK anothertransaction;

COMMIT; -- or COMMIT myfirsttransaction;
----

Cheers
Hannu

Show quoted text

Thanks,
Pavan

--
Pavan Deolasee
http://www.linkedin.com/in/pavandeolasee

#22Craig Ringer
craig@2ndquadrant.com
In reply to: Pavan Deolasee (#20)
Re: Autonomous Transaction (WIP)

On 04/09/2014 02:44 PM, Pavan Deolasee wrote:

On Wed, Apr 9, 2014 at 11:03 AM, Rajeev rastogi
<rajeev.rastogi@huawei.com <mailto:rajeev.rastogi@huawei.com>> wrote:

Though autonomous transaction uses mixed approach of sub-transaction
as well as main
transaction, transaction state of autonomous transaction is handled
independently.

Whenever I was asked to have a look at implementing this feature, I
always wondered about the great amount of global state that a backend
maintains which is normally tied to a single top transaction. Since AT
will have same characteristics as a top level transaction, I wonder how
do you plan to separate those global state variables ? Sure, we can
group them in a structure and put them on a stack when an AT starts and
pop them off when the original top transaction becomes active again,
finding all such global state variables is going to be tricky.

... not to mention the fact that extensions may rely on having their own
global state.

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Hannu Krosing (#21)
Re: Autonomous Transaction (WIP)

On 04/09/2014 09:55 AM, Hannu Krosing wrote:

This would be greatly simplified if we can accept the restriction that
there is only single
snapshot per backend (not per transaction). To me this seems a
completely sensible restriction.

Huh? In Read committed mode, every query within a transaction gets a
different snapshot.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Robert Haas
robertmhaas@gmail.com
In reply to: Rajeev rastogi (#17)
Re: Autonomous Transaction (WIP)

On Wed, Apr 9, 2014 at 12:24 AM, Rajeev rastogi
<rajeev.rastogi@huawei.com> wrote:

Deadlock Detection:

I'm not sure how this would work out internally

In order to resolve deadlock, two member variable will be created in the structure PROLOCK:
Bitmask for lock types currently held by autonomous transaction.
LOCKMASK holdMaskByAutoTx[MAX_AUTO_TX_LEVEL]
Bitmask for lock types currently held by main transaction.
LOCKMASK holdMaskByNormalTx

Now when we grant the lock to particular transaction, depending on type of transaction, bit
Mask will be set for either holdMaskByAutoTx or holdMaskByNormalTx.
Similar when lock is ungranted, corresponding bitmask will be reset.

That sounds pretty ugly, not to mention the fact that it will cause a
substantial increase in the amount of memory required to store
PROCLOCKs. It will probably slow things down, too.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#24)
Re: Autonomous Transaction (WIP)

Robert Haas <robertmhaas@gmail.com> writes:

On Wed, Apr 9, 2014 at 12:24 AM, Rajeev rastogi
<rajeev.rastogi@huawei.com> wrote:

Now when we grant the lock to particular transaction, depending on type of transaction, bit
Mask will be set for either holdMaskByAutoTx or holdMaskByNormalTx.
Similar when lock is ungranted, corresponding bitmask will be reset.

That sounds pretty ugly, not to mention the fact that it will cause a
substantial increase in the amount of memory required to store
PROCLOCKs. It will probably slow things down, too.

More to the point, why isn't it a flat-out bad idea? I can see no
justification for distinguishing normal and autonomous transactions
at this level.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#26Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Tom Lane (#25)
Re: Autonomous Transaction (WIP)

On 09 April 2014 12:14, Pavan Deolasee Wrote:

Whenever I was asked to have a look at implementing this feature, I always wondered about the great amount of global state that a backend maintains which is normally tied to a single top transaction. Since AT will have same characteristics as a top level transaction, I
wonder how do you plan to separate those global state variables ? Sure, we can group them in a structure and put them on a stack when an AT starts and pop them off when the original top transaction becomes active again, finding all such global state variables is
going to be tricky.

I could think of few global variables like transaction properties related(i.e. read-only mode, isolation level etc). As I plan to keep transaction properties of autonomous transaction same as main transaction, so there is no need to have these global variables separately.
Apart from this there are global variables like with-in transaction counters, GUC, xactStartTimeStamp. I think there is no need to maintain these variables also separately. They can continue from previous value for autonomous transaction also similar to as sub-transaction does.

In-case of autonomous transaction, only specific global variables initialized are related to resources (similar to sub-transaction), which anyway gets stored in current transaction state.

Please let me know if I am missing something or if you have some specific global variables related issue.

Thanks and Regards,
Kumar Rajeev Rastogi

#27Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Rajeev rastogi (#26)
Re: Autonomous Transaction (WIP)

On Thu, Apr 10, 2014 at 10:44 AM, Rajeev rastogi
<rajeev.rastogi@huawei.com>wrote:

On 09 April 2014 12:14, Pavan Deolasee Wrote:

Whenever I was asked to have a look at implementing this feature, I

always wondered about the great amount of global state that a backend
maintains which is normally tied to a single top transaction. Since AT will
have same characteristics as a top level transaction, I

wonder how do you plan to separate those global state variables ? Sure,

we can group them in a structure and put them on a stack when an AT starts
and pop them off when the original top transaction becomes active again,
finding all such global state variables is

going to be tricky.

I could think of few global variables like transaction properties
related(i.e. read-only mode, isolation level etc). As I plan to keep
transaction properties of autonomous transaction same as main transaction,
so there is no need to have these global variables separately.

Apart from this there are global variables like with-in transaction
counters, GUC, xactStartTimeStamp. I think there is no need to maintain
these variables also separately. They can continue from previous value for
autonomous transaction also similar to as sub-transaction does.

Hmm. Is that in line with what other databases do ? I would have preferred
AT to run like a standalone transaction without any influence of the
starting transaction, managing its own resources/locks/visibility/triggers
etc.

In-case of autonomous transaction, only specific global variables
initialized are related to resources (similar to sub-transaction), which
anyway gets stored in current transaction state.

Please let me know if I am missing something or if you have some specific
global variables related issue.

No, I don't have any specific issues in mind. Mostly all such global state
is managed through various AtStart/AtEOX and related routines. So a careful
examination of all those routines will give a good idea what needs to be
handled. You probably will require to write AtATStart/AtATEOX and similar
routines to manage the state at AT start/commit/rollback. Sorry, I haven't
looked at your WIP patch yet.

Thanks,
Pavan

--
Pavan Deolasee
http://www.linkedin.com/in/pavandeolasee

#28Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Pavan Deolasee (#27)
Re: Autonomous Transaction (WIP)

On 10 April 2014 11:18, Pavan Deolasee Wrote:

I could think of few global variables like transaction properties related(i.e. read-only mode, isolation level etc). As I plan to keep transaction properties of autonomous transaction same as main transaction, so there is no need to have these global variables separately.
Apart from this there are global variables like with-in transaction counters, GUC, xactStartTimeStamp. I think there is no need to maintain these variables also separately. They can continue from previous value for autonomous transaction also similar to as sub->>transaction does.

Hmm. Is that in line with what other databases do ? I would have preferred AT to run like a standalone transaction without any influence of the starting transaction, managing its own resources/locks/visibility/triggers etc.

To me it seems it is not very useful to keep the transaction properties separate except the read-only properties (though oracle does not share any transaction properties).

So we can have restriction that isolation and deferrable properties of main transaction will be inherited by autonomous transaction but read-only properties can be defined independently by autonomous transaction. Which looks to be fair restriction according to me.

In order to keep read-only properties separate, there is already infrastructure in PG. Inside the structure TransactionStateData, there is variable prevXactReadOnly (entry-time xact r/o state), which can keep the parent transaction read only properties and XactReadOnly can be changed to current transaction properties.
Moreover we can take this (transaction properties) as a feature enhancement also once a basic infrastructure is established, if acceptable to everyone.

Autonomous transaction will not share resource/lock/visibility etc with main transaction. This has been already taken care in WIP patch.

In-case of autonomous transaction, only specific global variables initialized are related to resources (similar to sub-transaction), which anyway gets stored in current transaction state.
Please let me know if I am missing something or if you have some specific global variables related issue.

No, I don't have any specific issues in mind. Mostly all such global state is managed through various AtStart/AtEOX and related routines. So a careful examination of all those routines will give a good idea what needs to be handled. You probably will require to write
AtATStart/AtATEOX and similar routines to manage the state at AT start/commit/rollback. Sorry, I haven't looked at your WIP patch yet.

For some of the resources, I have already written AtATStart/AtATEOX kind of routines in WIP patch.

Comments/feedbacks/doubts are welcome.

Thanks and Regards,
Kumar Rajeev Rastogi

#29Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Robert Haas (#24)
Re: Autonomous Transaction (WIP)

On 09 April 2014 21:25, Robert Haas Wrote:

Deadlock Detection:

I'm not sure how this would work out internally

In order to resolve deadlock, two member variable will be created in

the structure PROLOCK:

Bitmask for lock types currently held by autonomous

transaction.

LOCKMASK holdMaskByAutoTx[MAX_AUTO_TX_LEVEL]
Bitmask for lock types currently held by main transaction.
LOCKMASK holdMaskByNormalTx

Now when we grant the lock to particular transaction, depending on
type of transaction, bit Mask will be set for either holdMaskByAutoTx

or holdMaskByNormalTx.

Similar when lock is ungranted, corresponding bitmask will be reset.

That sounds pretty ugly, not to mention the fact that it will cause a
substantial increase in the amount of memory required to store
PROCLOCKs. It will probably slow things down, too.

Actually I followed above design to keep it align with the existing design. As I understand, currently also
all lock conflict is checked based on the corresponding lock bit mask.

This is good catch that shared memory required will increase but isn't it justified from user perspective
since we are allowing more transactions per session and hence memory required to store various kind of resources
will increase.

Since we are just additionally setting the bitmask for each lock (in-case there is autonomous transaction, then there will
be one more additional bit mask setting and deadlock check), I don't think it should slow down the overall operation.

Also We can keep number of autonomous transaction configurable(default-0), to keep it less impacting incase it is not configured.

An autonomous transaction can also conflict with main transaction, so in order to check conflict between them,
I am distinguishing at this level.

Please correct me If I am wrong anywhere and also please provide your thought on this and on overall design.

Thanks and Regards,
Kumar Rajeev Rastogi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Simon Riggs
simon@2ndQuadrant.com
In reply to: Rajeev rastogi (#1)
Re: Autonomous Transaction (WIP)

On 7 April 2014 05:06, Rajeev rastogi <rajeev.rastogi@huawei.com> wrote:

*Autonomous Transaction Storage:*

As for main transaction, structure PGXACT is used to store main
transactions, which are created in shared memory of size:

(Number of process)*sizeof(struct PGXACT)

Similarly a new structure will be defined to store autonomous transaction:

*Struct PGAutonomousXACT*

I already proposed exactly this design two years ago and it was rejected at
the PgCon hackers meeting.

I have a better design worked out now and will likely be working on it for
9.5

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#31Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Simon Riggs (#30)
Re: Autonomous Transaction (WIP)

On 14 April 2014 20:10, Simon Riggs wrote:

Autonomous Transaction Storage:
As for main transaction, structure PGXACT is used to store main transactions, which are created in shared memory of size:
(Number of process)*sizeof(struct PGXACT)
Similarly a new structure will be defined to store autonomous transaction:
Struct PGAutonomousXACT

Oh...I had already added this patch for 2014-June CommitFest, thinking that everyone is busy with work to wrap up 9.4.

I already proposed exactly this design two years ago and it was rejected at the PgCon hackers meeting.
I have a better design worked out now and will likely be working on it for 9.5

Can we work together to take this feature to final goal.
May be you can go through my complete patch and see whatever part of the patch and related design can be re-used along with your new design.
Also if possible you can share your design (even rough is OK), I will see if I can contribute to that in some-way.

Thanks and Regards,
Kumar Rajeev Rastogi

#32Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Rajeev rastogi (#31)
Re: Autonomous Transaction (WIP)

What's the status of this patch?

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#33Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Alvaro Herrera (#32)
1 attachment(s)
Re: Autonomous Transaction (WIP)

On 17 June 2014 02:01, Alvaro Herrera Wrote:

What's the status of this patch?

I have completed work on this and some more changes are done on top of earlier patch shared:
1. Fixed all of the issues observed.
2. Addressed some of the feedback from community like
a. Change the syntax to
START AUTONOMOUS TRANSACTION [READ ONLY | READ WRITE]
b. As Pavan had pointed, I have made transaction behavior (only read-only properties) of main and autonomous transaction independent.
3. Added documentation for this feature.
4. Rebased to latest git code.

Please find the attached latest patch and provide opinion.

Thanks and Regards,
Kumar Rajeev Rastogi

Attachments:

autonomous_tx_v2.patchapplication/octet-stream; name=autonomous_tx_v2.patchDownload
*** /dev/null
--- b/doc/src/sgml/ref/start_autonomous_transaction.sgml
***************
*** 0 ****
--- 1,51 ----
+ <!--
+ doc/src/sgml/ref/start_autonomous_transaction.sgml
+ PostgreSQL documentation
+ -->
+ 
+ <refentry id="SQL-START-AUTONOMOUS-TRANSACTION">
+  <indexterm zone="sql-start-autonomous-transaction">
+   <primary>START AUTONOMOUS TRANSACTION</primary>
+  </indexterm>
+ 
+  <refmeta>
+   <refentrytitle>START AUTONOMOUS TRANSACTION</refentrytitle>
+   <manvolnum>7</manvolnum>
+   <refmiscinfo>SQL - Language Statements</refmiscinfo>
+  </refmeta>
+ 
+  <refnamediv>
+   <refname>START AUTONOMOUS TRANSACTION</refname>
+   <refpurpose>start an autonomous transaction block</refpurpose>
+  </refnamediv>
+ 
+  <refsynopsisdiv>
+ <synopsis>
+ START AUTONOMOUS TRANSACTION [ <replaceable class="parameter">transaction_mode</replaceable>]
+ 
+ <phrase>where <replaceable class="parameter">transaction_mode</replaceable> is one of:</phrase>
+ 
+     READ WRITE | READ ONLY
+ 
+ </synopsis>
+  </refsynopsisdiv>
+ 
+  <refsect1>
+   <title>Description</title>
+ 
+   <para>
+    This command begins a new autonomous transaction block. This can be started
+    only with in already running transaction block.
+   </para>
+ 
+    <para>
+    An autonomous transaction has its own <xref linkend="sql-commit"> and
+    <xref linkend="sql-rollback"> scope to ensure
+    that its outcome does not effect the caller's uncommitted changes.
+    Additionally, the <xref linkend="sql-commit"> and <xref linkend="sql-rollback">
+    in the calling  transaction should not effect the changes that were finalized
+    on the completion of autonomous transaction itself. If read/write mode is
+    specified, the new transaction has those characteristics.
+   </para>
+  </refsect1>
+ </refentry>
*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
***************
*** 973,979 **** 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));
--- 973,979 ----
  	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, bool readOnly);
! static TransactionId GetTopAutonomousTransactionID(void);
  static void PopTransaction(void);
  
  static void AtSubAbort_Memory(void);
***************
*** 294,299 **** static void ShowTransactionStateRec(TransactionState state);
--- 305,314 ----
  static const char *BlockStateAsString(TBlockState blockState);
  static const char *TransStateAsString(TransState state);
  
+ extern void GetPreContextAndResource(MemoryContext *preContext,
+ 													ResourceOwner *preOwner);
+ extern void SetPreContextAndResource(MemoryContext preContext,
+ 													ResourceOwner preOwner);
  
  /* ----------------------------------------------------------------
   *	transaction state accessors
***************
*** 332,338 **** IsAbortedTransactionBlockState(void)
  	TransactionState s = CurrentTransactionState;
  
  	if (s->blockState == TBLOCK_ABORT ||
! 		s->blockState == TBLOCK_SUBABORT)
  		return true;
  
  	return false;
--- 347,354 ----
  	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;
  }
--- 364,374 ----
  TransactionId
  GetTopTransactionId(void)
  {
! 	if (MyProc->inAutoTXLevel)
! 	{
! 		return GetTopAutonomousTransactionID();
! 	}
! 	else if (!TransactionIdIsValid(TopTransactionStateData.transactionId))
  		AssignTransactionId(&TopTransactionStateData);
  	return TopTransactionStateData.transactionId;
  }
***************
*** 363,368 **** GetTopTransactionId(void)
--- 383,406 ----
  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;
  }
  
***************
*** 450,461 **** AssignTransactionId(TransactionState s)
  {
  	bool		isSubXact = (s->parent != NULL);
  	ResourceOwner currentOwner;
! 	bool		log_unknown_top = false;
  
  	/* Assert that caller didn't screw up */
  	Assert(!TransactionIdIsValid(s->transactionId));
  	Assert(s->state == TRANS_INPROGRESS);
  
  	/*
  	 * 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
--- 488,519 ----
  {
  	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);
  
  	/*
--- 565,573 ----
  	 * 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 */
--- 807,830 ----
  	{
  		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)
--- 844,856 ----
  			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);
--- 1070,1076 ----
   * 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);
  
  	/*
--- 1083,1098 ----
  	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
--- 1120,1126 ----
  		 * 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();
  
--- 1149,1163 ----
  		 * 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.
--- 1318,1339 ----
  	 */
  	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 */
--- 1345,1352 ----
  		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 */
--- 1642,1683 ----
  	 * 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);
  
--- 2076,2082 ----
  	/*
  	 * Here is where we really truly commit.
  	 */
! 	latestXid = RecordTransactionCommit(false);
  
  	TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->lxid);
  
***************
*** 2539,2544 **** StartTransactionCommand(void)
--- 2670,2676 ----
  			 */
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			break;
  
  			/*
***************
*** 2551,2556 **** StartTransactionCommand(void)
--- 2683,2689 ----
  			 */
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
+ 		case TBLOCK_AUTOABORT:
  			break;
  
  			/* These cases are invalid. */
***************
*** 2567,2572 **** StartTransactionCommand(void)
--- 2700,2709 ----
  		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;
***************
*** 2702,2708 **** CommitTransactionCommand(void)
  			} while (s->blockState == TBLOCK_SUBRELEASE);
  
  			Assert(s->blockState == TBLOCK_INPROGRESS ||
! 				   s->blockState == TBLOCK_SUBINPROGRESS);
  			break;
  
  			/*
--- 2839,2846 ----
  			} while (s->blockState == TBLOCK_SUBRELEASE);
  
  			Assert(s->blockState == TBLOCK_INPROGRESS ||
! 				   s->blockState == TBLOCK_SUBINPROGRESS ||
! 				   s->blockState == TBLOCK_AUTOINPROGRESS);
  			break;
  
  			/*
***************
*** 2733,2738 **** CommitTransactionCommand(void)
--- 2871,2881 ----
  				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));
***************
*** 2814,2819 **** CommitTransactionCommand(void)
--- 2957,2986 ----
  				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;
  	}
  }
  
***************
*** 2900,2905 **** AbortCurrentTransaction(void)
--- 3067,3073 ----
  			 */
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
+ 		case TBLOCK_AUTOABORT:
  			break;
  
  			/*
***************
*** 2966,2971 **** AbortCurrentTransaction(void)
--- 3134,3155 ----
  			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;
  	}
  }
  
***************
*** 3269,3274 **** BeginTransactionBlock(void)
--- 3453,3460 ----
  		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")));
***************
*** 3288,3293 **** BeginTransactionBlock(void)
--- 3474,3483 ----
  		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;
***************
*** 3312,3317 **** PrepareTransactionBlock(char *gid)
--- 3502,3512 ----
  	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();
  
***************
*** 3387,3393 **** 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;
--- 3582,3588 ----
  			 * 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;
***************
*** 3398,3403 **** EndTransactionBlock(void)
--- 3593,3601 ----
  			}
  			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));
***************
*** 3410,3416 **** EndTransactionBlock(void)
  			 * transaction.
  			 */
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL)
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
--- 3608,3614 ----
  			 * transaction.
  			 */
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL && !IS_TOP_AUTO_TX_STATE(s))
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
***************
*** 3425,3430 **** EndTransactionBlock(void)
--- 3623,3633 ----
  				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));
***************
*** 3443,3448 **** EndTransactionBlock(void)
--- 3646,3660 ----
  			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:
***************
*** 3457,3462 **** EndTransactionBlock(void)
--- 3669,3678 ----
  		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;
***************
*** 3503,3509 **** UserAbortTransactionBlock(void)
  			 */
  		case TBLOCK_SUBINPROGRESS:
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL)
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
--- 3719,3725 ----
  			 */
  		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;
***************
*** 3518,3523 **** UserAbortTransactionBlock(void)
--- 3734,3744 ----
  				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));
***************
*** 3535,3540 **** UserAbortTransactionBlock(void)
--- 3756,3768 ----
  					 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:
***************
*** 3550,3555 **** UserAbortTransactionBlock(void)
--- 3778,3787 ----
  		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;
***************
*** 3569,3577 **** 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
--- 3801,3811 ----
  	{
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction(false, XactReadOnly);
! 
!  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
  			 * Savepoint names, like the TransactionState block itself, live
***************
*** 3598,3603 **** DefineSavepoint(char *name)
--- 3832,3842 ----
  		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;
***************
*** 3626,3631 **** ReleaseSavepoint(List *options)
--- 3865,3872 ----
  			 * defined.
  			 */
  		case TBLOCK_INPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 
  			ereport(ERROR,
  					(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  					 errmsg("no such savepoint")));
***************
*** 3655,3660 **** ReleaseSavepoint(List *options)
--- 3896,3907 ----
  		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;
***************
*** 3670,3682 **** 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")));
--- 3917,3929 ----
  
  	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")));
***************
*** 3727,3732 **** RollbackToSavepoint(List *options)
--- 3974,3982 ----
  			 */
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_ABORT:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 		case TBLOCK_AUTOABORT:
+ 
  			ereport(ERROR,
  					(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  					 errmsg("no such savepoint")));
***************
*** 3754,3759 **** RollbackToSavepoint(List *options)
--- 4004,4013 ----
  		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;
***************
*** 3769,3781 **** 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")));
--- 4023,4035 ----
  
  	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")));
***************
*** 3838,3845 **** BeginInternalSubTransaction(char *name)
  		case TBLOCK_END:
  		case TBLOCK_PREPARE:
  		case TBLOCK_SUBINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction();
  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
--- 4092,4100 ----
  		case TBLOCK_END:
  		case TBLOCK_PREPARE:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction(false, XactReadOnly);
  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
***************
*** 3864,3869 **** BeginInternalSubTransaction(char *name)
--- 4119,4129 ----
  		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;
***************
*** 3931,3936 **** RollbackAndReleaseCurrentSubTransaction(void)
--- 4191,4202 ----
  		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;
***************
*** 4029,4034 **** AbortOutOfAnyTransaction(void)
--- 4295,4315 ----
  				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);
  
***************
*** 4089,4094 **** TransactionBlockStatusCode(void)
--- 4370,4378 ----
  		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:
***************
*** 4098,4103 **** TransactionBlockStatusCode(void)
--- 4382,4390 ----
  		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 */
  	}
  
***************
*** 4412,4418 **** CleanupSubTransaction(void)
  
  	ShowTransactionState("CleanupSubTransaction");
  
! 	if (s->state != TRANS_ABORT)
  		elog(WARNING, "CleanupSubTransaction while in %s state",
  			 TransStateAsString(s->state));
  
--- 4699,4705 ----
  
  	ShowTransactionState("CleanupSubTransaction");
  
! 	if (s->state != TRANS_ABORT && !IS_TOP_AUTO_TX_STATE(s))
  		elog(WARNING, "CleanupSubTransaction while in %s state",
  			 TransStateAsString(s->state));
  
***************
*** 4439,4448 **** 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.
--- 4726,4736 ----
   *	if it has a local pointer to it after calling this function.
   */
  static void
! PushTransaction(bool isAutoTX, bool readOnly)
  {
  	TransactionState p = CurrentTransactionState;
  	TransactionState s;
+ 	PGAutonomousXACT *currentautotx = NULL;
  
  	/*
  	 * We keep subtransaction state nodes in TopTransactionContext.
***************
*** 4475,4484 **** 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;
  
  	/*
--- 4763,4785 ----
  	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;
+ 		XactReadOnly = readOnly;
+ 	}
+ 	else
+ 	{
+ 		s->blockState = TBLOCK_SUBBEGIN;
+ 	}
+ 
+ 
  	CurrentTransactionState = s;
  
  	/*
***************
*** 4500,4505 **** static void
--- 4801,4807 ----
  PopTransaction(void)
  {
  	TransactionState s = CurrentTransactionState;
+ 	PGAutonomousXACT *currentautox = NULL;
  
  	if (s->state != TRANS_DEFAULT)
  		elog(WARNING, "PopTransaction while in %s state",
***************
*** 4518,4523 **** PopTransaction(void)
--- 4820,4832 ----
  	CurTransactionResourceOwner = s->parent->curTransactionOwner;
  	CurrentResourceOwner = s->parent->curTransactionOwner;
  
+ 	if(IS_TOP_AUTO_TX_STATE(s))
+ 	{
+ 		currentautox = GetCurrentPGAutonomousXACT();
+ 		MemSet(currentautox, 0, sizeof(PGAutonomousXACT));
+ 		MyProc->inAutoTXLevel--;
+ 	}
+ 
  	/* Free the old child structure */
  	if (s->name)
  		pfree(s->name);
***************
*** 4622,4627 **** BlockStateAsString(TBlockState blockState)
--- 4931,4948 ----
  			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";
  }
***************
*** 4994,4996 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
--- 5315,5885 ----
  	else
  		elog(PANIC, "xact_redo: unknown op code %u", info);
  }
+ 
+ /*
+  * DefineAutonomousTransaction:
+  * This fuction creates an autonomous transaction.
+  * readOnly: This argumet indicates, whether it is read-only or read-write
+  * transaction.
+  * Note: In future, if we are supporting more independent properties to auto tx,
+  * the we can pass a structure containig all properties instead of bool.
+  */
+ void
+ DefineAutonomousTransaction(bool readOnly)
+ {
+ 	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, readOnly);
+ 			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: SetPreContextAndResource
+  * save the previous memory context and resource owner
+  * Param: preContext
+  * Param: preOwner
+  */
+ void
+ SetPreContextAndResource(MemoryContext preContext,ResourceOwner preOwner)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 
+ 	if (s)
+ 	{
+ 		s->preMemoryContext = preContext;
+ 		s->preResourceOwner = preOwner;
+ 	}
+ }
+ 
+ /*
+  * Brief: GetPreContextAndResource
+  * get  the previous memory context and resource owner
+  * Param: preContext
+  * Param: preOwner
+  */
+ void
+ 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, XactReadOnly);
+ 			break;
+ 
+ 			/* These cases are invalid. */
+ 
+ 		default:
+ 			ereport(FATAL,
+ 					(errmsg("DefineAutonomousTransaction: unexpected state %s",
+ 				 BlockStateAsString(s->blockState))));
+ 			break;
+ 	}
+ 	CommitTransactionCommand();
+ 	StartTransactionCommand();
+ 	SetPreContextAndResource(oldContext, oldOwner);
+ 	MyProc->isIntAutoTx = true;
+ 	(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;
+ 	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;
+ 
+ 	MyProc->isIntAutoTx = false;
+ }
+ 
+ void
+ AbortInternalAutonomousTransaction(void)
+ {
+ 
+ 	TransactionState s = CurrentTransactionState;
+ 	MemoryContext	preContext  = NULL;
+ 	ResourceOwner	preOwner    = NULL;
+ 	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;
+ 	MyProc->isIntAutoTx = false;
+ }
+ 
+ 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
***************
*** 953,959 **** open_share_lock(SeqTable seq)
  		currentOwner = CurrentResourceOwner;
  		PG_TRY();
  		{
! 			CurrentResourceOwner = TopTransactionResourceOwner;
  			LockRelationOid(seq->relid, AccessShareLock);
  		}
  		PG_CATCH();
--- 953,963 ----
  		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
***************
*** 87,92 ****
--- 87,93 ----
  #include "utils/syscache.h"
  #include "utils/tqual.h"
  #include "utils/typcache.h"
+ #include "storage/proc.h"
  
  
  /*
***************
*** 106,111 **** typedef struct OnCommitItem
--- 107,115 ----
  	 */
  	SubTransactionId creating_subid;
  	SubTransactionId deleting_subid;
+ 
+ 	TransactionId	toptxid;	/* top tx id */
+ 
  } OnCommitItem;
  
  static List *on_commits = NIL;
***************
*** 10793,10798 **** PreCommit_on_commit_actions(void)
--- 10797,10804 ----
  				/* 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
***************
*** 10806,10811 **** PreCommit_on_commit_actions(void)
--- 10812,10820 ----
  				{
  					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;
***************
*** 3679,3695 **** 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)))
  		{
--- 3679,3701 ----
  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)))
  		{
***************
*** 3752,3758 **** static bool
  afterTriggerInvokeEvents(AfterTriggerEventList *events,
  						 CommandId firing_id,
  						 EState *estate,
! 						 bool delete_ok)
  {
  	bool		all_fired = true;
  	AfterTriggerEventChunk *chunk;
--- 3758,3765 ----
  afterTriggerInvokeEvents(AfterTriggerEventList *events,
  						 CommandId firing_id,
  						 EState *estate,
! 						 bool delete_ok,
! 						 bool inAutoX)
  {
  	bool		all_fired = true;
  	AfterTriggerEventChunk *chunk;
***************
*** 3764,3769 **** afterTriggerInvokeEvents(AfterTriggerEventList *events,
--- 3771,3777 ----
  	Instrumentation *instr = NULL;
  	TupleTableSlot *slot1 = NULL,
  			   *slot2 = NULL;
+ 	int			my_level = GetCurrentTransactionNestLevel();
  
  	/* Make a local EState if need be */
  	if (estate == NULL)
***************
*** 3789,3794 **** afterTriggerInvokeEvents(AfterTriggerEventList *events,
--- 3797,3806 ----
  		{
  			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?
  			 */
***************
*** 4033,4044 **** 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
--- 4045,4056 ----
  	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
***************
*** 4097,4107 **** 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 */
  	}
  
--- 4109,4201 ----
  	 * 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 */
  	}
  
***************
*** 4112,4117 **** AfterTriggerFireDeferred(void)
--- 4206,4212 ----
  
  	if (snap_pushed)
  		PopActiveSnapshot();
+ 	pfree(events);
  }
  
  
***************
*** 4659,4665 **** AfterTriggerSetState(ConstraintsSetStmt *stmt)
  		AfterTriggerEventList *events = &afterTriggers->events;
  		bool		snapshot_set = false;
  
! 		while (afterTriggerMarkEvents(events, NULL, true))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
--- 4754,4760 ----
  		AfterTriggerEventList *events = &afterTriggers->events;
  		bool		snapshot_set = false;
  
! 		while (afterTriggerMarkEvents(events, NULL, true, false))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
***************
*** 4684,4690 **** AfterTriggerSetState(ConstraintsSetStmt *stmt)
  			 * subtransaction could later get rolled back.
  			 */
  			if (afterTriggerInvokeEvents(events, firing_id, NULL,
! 										 !IsSubTransaction()))
  				break;			/* all fired */
  		}
  
--- 4779,4785 ----
  			 * 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
***************
*** 2069,2074 **** _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
--- 2069,2091 ----
  		 * 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
***************
*** 349,355 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  				execute_param_clause using_clause returning_clause
  				opt_enum_val_list enum_val_list table_func_column_list
  				create_generic_options alter_generic_options
! 				relation_expr_list dostmt_opt_list
  
  %type <list>	opt_fdw_options fdw_options
  %type <defelt>	fdw_option
--- 349,355 ----
  				execute_param_clause using_clause returning_clause
  				opt_enum_val_list enum_val_list table_func_column_list
  				create_generic_options alter_generic_options
! 				relation_expr_list dostmt_opt_list opt_auto_transaction_mode
  
  %type <list>	opt_fdw_options fdw_options
  %type <defelt>	fdw_option
***************
*** 527,532 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
--- 527,533 ----
  %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
  
  	BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
  	BOOLEAN_P BOTH BY
***************
*** 8166,8171 **** TransactionStmt:
--- 8167,8179 ----
  					n->gid = $3;
  					$$ = (Node *)n;
  				}
+ 			| START AUTONOMOUS TRANSACTION opt_auto_transaction_mode
+ 				{
+                     TransactionStmt *n = makeNode(TransactionStmt);
+                     n->kind = TRANS_STMT_AUTONOMOUS;
+                     n->options = $4;
+                     $$ = (Node *)n;
+                 }
  		;
  
  opt_transaction:	WORK							{}
***************
*** 8173,8178 **** opt_transaction:	WORK							{}
--- 8181,8197 ----
  			| /*EMPTY*/								{}
  		;
  
+ opt_auto_transaction_mode:
+ 			 READ ONLY
+ 					{ $$ = list_make1(makeDefElem("transaction_read_only",
+ 									  	 (Node *)makeInteger(TRUE))); }
+ 			| READ WRITE
+ 					{ $$ = list_make1(makeDefElem("transaction_read_only",
+ 										   (Node *)makeInteger(FALSE))); }
+ 			| /* EMPTY */
+ 					{ $$ = NIL; }
+ 		;
+ 
  transaction_mode_item:
  			ISOLATION LEVEL iso_level
  					{ $$ = makeDefElem("transaction_isolation",
***************
*** 12812,12817 **** unreserved_keyword:
--- 12831,12837 ----
  			| ASSIGNMENT
  			| AT
  			| ATTRIBUTE
+ 			| AUTONOMOUS
  			| BACKWARD
  			| BEFORE
  			| BEGIN_P
*** 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
***************
*** 2795,2800 **** XidCacheRemoveRunningXids(TransactionId xid,
--- 2943,3028 ----
  	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
***************
*** 51,57 ****
  int			max_locks_per_xact; /* set by guc.c */
  
  #define NLOCKENTS() \
! 	mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
  
  
  /*
--- 51,58 ----
  int			max_locks_per_xact; /* set by guc.c */
  
  #define NLOCKENTS() \
! 	mul_size(max_locks_per_xact, add_size((MAX_AUTOX_NESTING_LEVEL*MaxConnections), \
! 						add_size(MaxBackends, max_prepared_xacts)))
  
  
  /*
***************
*** 355,360 **** static void LockRefindAndRelease(LockMethod lockMethodTable, PGPROC *proc,
--- 356,364 ----
  					 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,
--- 787,798 ----
  	 */
  	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;
--- 828,836 ----
  	 * 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,
--- 1153,1161 ----
  		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,
--- 1286,1293 ----
  	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,
--- 1311,1327 ----
  	 */
  	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,
--- 1360,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;
+ 	}
+ 
+ 	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,227 ----
  	MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACT));
  	ProcGlobal->allPgXact = pgxacts;
  
+ 	pgautonomousxacts = (PGAutonomousXACT *) ShmemAlloc(TotalProcs * MAX_AUTOX_NESTING_LEVEL * sizeof(PGAutonomousXACT));
+ 	MemSet(pgautonomousxacts, 0, TotalProcs * MAX_AUTOX_NESTING_LEVEL * sizeof(PGAutonomousXACT));
+     ProcGlobal->allPgAutonomousXact = pgautonomousxacts;
+ 
  	for (i = 0; i < TotalProcs; i++)
  	{
  		/* Common initialization for all PGPROCs, regardless of type. */
***************
*** 279,284 **** InitProcess(void)
--- 291,297 ----
  {
  	/* 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)
--- 330,338 ----
  
  	if (MyProc != NULL)
  	{
+ 		MyProc->inAutoTXLevel = 0;
+ 
+ 
  		if (IsAnyAutoVacuumProcess())
  			procglobal->autovacFreeProcs = (PGPROC *) MyProc->links.next;
  		else if (IsBackgroundWorker)
***************
*** 340,345 **** InitProcess(void)
--- 356,366 ----
  	}
  	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)
--- 411,417 ----
  	/* Initialize fields for sync rep */
  	MyProc->waitLSN = 0;
  	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
+ 
  	SHMQueueElemInit(&(MyProc->syncRepLinks));
  
  	/*
***************
*** 464,469 **** InitAuxiliaryProcess(void)
--- 486,492 ----
  {
  	PGPROC	   *auxproc;
  	int			proctype;
+ 	int			pgautoxno;
  
  	/*
  	 * ProcGlobal should be set up already (if we are a backend, we inherit
***************
*** 515,520 **** InitAuxiliaryProcess(void)
--- 538,547 ----
  	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)
--- 1696,1706 ----
  	if (proc != NULL)
  		PGSemaphoreUnlock(&proc->sem);
  }
+ 
+ PGAutonomousXACT *GetCurrentPGAutonomousXACT(void)
+ {
+ 	Assert(MyProc->inAutoTXLevel);
+ 
+ 	return &MyPgAutonomousXact[MyProc->inAutoTXLevel - 1];
+ }
+ 
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
***************
*** 3857,3862 **** PostgresMain(int argc, char *argv[],
--- 3857,3867 ----
  		debug_query_string = NULL;
  
  		/*
+ 		 * Abort internal autonomous transaction, if started.
+ 		 */
+ 		if (MyProc->isIntAutoTx)
+ 			AbortInternalAutonomousTransaction();
+ 		/*
  		 * Abort the current transaction in order to recover.
  		 */
  		AbortCurrentTransaction();
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 414,419 **** standard_ProcessUtility(Node *parsetree,
--- 414,440 ----
  						UserAbortTransactionBlock();
  						break;
  
+ 					case TRANS_STMT_AUTONOMOUS:
+ 						{
+ 							ListCell   *cell;
+ 							bool readOnly = false;	/* by default read-write*/
+ 
+ 							RequireTransactionChain(isTopLevel, "AUTONOMOUS TRANSACTION");
+ 							/*
+ 							 * As of now only one element in list is expected.
+ 							 * If more elements added to it, handing might need to
+ 							 * be relooked.
+ 							 */
+ 							foreach(cell, stmt->options)
+ 							{
+ 								DefElem    *elem = lfirst(cell);
+ 								if (strcmp(elem->defname, "transaction_read_only") == 0)
+ 									readOnly = (bool)intVal(elem->arg);
+ 							}
+ 							DefineAutonomousTransaction(readOnly);
+ 						}
+ 						break;
+ 
  					case TRANS_STMT_SAVEPOINT:
  						{
  							ListCell   *cell;
***************
*** 1751,1756 **** CreateCommandTag(Node *parsetree)
--- 1772,1781 ----
  						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
***************
*** 1327,1332 **** ReleaseCatCache(HeapTuple tuple)
--- 1327,1400 ----
  		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
***************
*** 799,810 **** 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
--- 799,812 ----
   */
  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
***************
*** 1003,1008 **** AtEOSubXact_Inval(bool isCommit)
--- 1005,1088 ----
  }
  
  /*
+  * 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"
  
  
  /*---------------------------------------------------------------------------
***************
*** 907,912 **** SearchSysCache(int cacheId,
--- 908,918 ----
  		!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);
  }
  
***************
*** 917,922 **** SearchSysCache(int cacheId,
--- 923,935 ----
  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,276 ----
  extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
  extern void xact_desc(StringInfo buf, XLogRecord *record);
  
+ extern void DefineAutonomousTransaction(bool readOnly);
+ 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
***************
*** 2354,2360 **** typedef enum TransactionStmtKind
  	TRANS_STMT_ROLLBACK_TO,
  	TRANS_STMT_PREPARE,
  	TRANS_STMT_COMMIT_PREPARED,
! 	TRANS_STMT_ROLLBACK_PREPARED
  } TransactionStmtKind;
  
  typedef struct TransactionStmt
--- 2354,2361 ----
  	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", AUTONOMOUS, UNRESERVED_KEYWORD)
  PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
  PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
  PG_KEYWORD("begin", BEGIN_P, 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
***************
*** 142,147 **** struct PGPROC
--- 142,150 ----
  	bool		fpVXIDLock;		/* are we holding a fast-path VXID lock? */
  	LocalTransactionId fpLocalTransactionId;	/* lxid for fast-path VXID
  												 * lock */
+ 
+ 	uint8 inAutoTXLevel;		/* At what leve of autonomous tx*/
+ 	bool  isIntAutoTx;			/* Is any internal autonomous tx started by proc*/
  };
  
  /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */
***************
*** 149,154 **** struct PGPROC
--- 152,158 ----
  
  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
***************
*** 177,182 **** typedef struct PGXACT
--- 181,198 ----
  	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.
   */
***************
*** 186,191 **** typedef struct PROC_HDR
--- 202,211 ----
  	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 */
***************
*** 257,260 **** extern void LockErrorCleanup(void);
--- 277,282 ----
  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 */
#34Pavel Stehule
pavel.stehule@gmail.com
In reply to: Rajeev rastogi (#33)
1 attachment(s)
Re: Autonomous Transaction (WIP)

Hello

regress tests fails:

plancache ... ok
limit ... ok
plpgsql ... ok
copy2 ... ok
temp ... FAILED
domain ... ok
rangefuncs ... ok
prepare ... ok
without_oid ... ok
conversion ... ok
truncate ... ok
alter_table ... ok
sequence ... ok

I did some small tests and it works well. When I looked to code, I was
surprised by hardcoded max nesting level of autonomous transactions

#define MAX_AUTOX_NESTING_LEVEL 3

why? Is not it too restrictive?

I am missing a regress tests.

Regards

Pavel

2014-06-18 11:19 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

Show quoted text

On 17 June 2014 02:01, Alvaro Herrera Wrote:

What's the status of this patch?

I have completed work on this and some more changes are done on top of
earlier patch shared:
1. Fixed all of the issues observed.
2. Addressed some of the feedback from community like
a. Change the syntax to
START AUTONOMOUS TRANSACTION [READ ONLY | READ
WRITE]
b. As Pavan had pointed, I have made transaction behavior (only
read-only properties) of main and autonomous transaction independent.
3. Added documentation for this feature.
4. Rebased to latest git code.

Please find the attached latest patch and provide opinion.

Thanks and Regards,
Kumar Rajeev Rastogi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Attachments:

regression.diffsapplication/octet-stream; name=regression.diffsDownload
*** /home/pavel/src/postgresql/src/test/regress/expected/temp.out	2013-12-01 07:50:55.748792948 +0100
--- /home/pavel/src/postgresql/src/test/regress/results/temp.out	2014-06-24 18:10:45.636027420 +0200
***************
*** 95,116 ****
  
  COMMIT;
  SELECT * FROM temptest;
! ERROR:  relation "temptest" does not exist
! LINE 1: SELECT * FROM temptest;
!                       ^
  BEGIN;
  CREATE TEMP TABLE temptest(col) ON COMMIT DROP AS SELECT 1;
  SELECT * FROM temptest;
   col 
  -----
     1
! (1 row)
  
- COMMIT;
- SELECT * FROM temptest;
- ERROR:  relation "temptest" does not exist
- LINE 1: SELECT * FROM temptest;
-                       ^
  -- ON COMMIT is only allowed for TEMP
  CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS;
  ERROR:  ON COMMIT can only be used on temporary tables
--- 95,119 ----
  
  COMMIT;
  SELECT * FROM temptest;
!  col 
! -----
!    1
!    2
! (2 rows)
! 
  BEGIN;
  CREATE TEMP TABLE temptest(col) ON COMMIT DROP AS SELECT 1;
+ ERROR:  relation "temptest" already exists
+ SELECT * FROM temptest;
+ ERROR:  current transaction is aborted, commands ignored until end of transaction block
+ COMMIT;
  SELECT * FROM temptest;
   col 
  -----
     1
!    2
! (2 rows)
  
  -- ON COMMIT is only allowed for TEMP
  CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS;
  ERROR:  ON COMMIT can only be used on temporary tables

======================================================================

#35Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#34)
1 attachment(s)
Re: Autonomous Transaction (WIP)

postgres=# select version();

version
-----------------------------------------------------------------------------------------------------------------
PostgreSQL 9.5devel on x86_64-unknown-linux-gnu, compiled by gcc (GCC)
4.8.2 20131212 (Red Hat 4.8.2-7), 64-bit
(1 row)

2014-06-24 18:39 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Show quoted text

Hello

regress tests fails:

plancache ... ok
limit ... ok
plpgsql ... ok
copy2 ... ok
temp ... FAILED
domain ... ok
rangefuncs ... ok
prepare ... ok
without_oid ... ok
conversion ... ok
truncate ... ok
alter_table ... ok
sequence ... ok

I did some small tests and it works well. When I looked to code, I was
surprised by hardcoded max nesting level of autonomous transactions

#define MAX_AUTOX_NESTING_LEVEL 3

why? Is not it too restrictive?

I am missing a regress tests.

Regards

Pavel

2014-06-18 11:19 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

On 17 June 2014 02:01, Alvaro Herrera Wrote:

What's the status of this patch?

I have completed work on this and some more changes are done on top of
earlier patch shared:
1. Fixed all of the issues observed.
2. Addressed some of the feedback from community like
a. Change the syntax to
START AUTONOMOUS TRANSACTION [READ ONLY | READ
WRITE]
b. As Pavan had pointed, I have made transaction behavior (only
read-only properties) of main and autonomous transaction independent.
3. Added documentation for this feature.
4. Rebased to latest git code.

Please find the attached latest patch and provide opinion.

Thanks and Regards,
Kumar Rajeev Rastogi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Attachments:

temp.outapplication/octet-stream; name=temp.outDownload
#36Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#35)
Re: Autonomous Transaction (WIP)

Hello

There are lot of unnecessary block over one statement in code

+               if ((inAutoX) && (chunk == events->head) && ((char *)event
< afterTriggers->events_stack[my_level].tailfree))
+               {
+                       continue;
+               }
+

and there a few too long lines

Regards

Pavel

2014-06-24 18:40 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Show quoted text

postgres=# select version();

version

-----------------------------------------------------------------------------------------------------------------
PostgreSQL 9.5devel on x86_64-unknown-linux-gnu, compiled by gcc (GCC)
4.8.2 20131212 (Red Hat 4.8.2-7), 64-bit
(1 row)

2014-06-24 18:39 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Hello

regress tests fails:

plancache ... ok
limit ... ok
plpgsql ... ok
copy2 ... ok
temp ... FAILED
domain ... ok
rangefuncs ... ok
prepare ... ok
without_oid ... ok
conversion ... ok
truncate ... ok
alter_table ... ok
sequence ... ok

I did some small tests and it works well. When I looked to code, I was
surprised by hardcoded max nesting level of autonomous transactions

#define MAX_AUTOX_NESTING_LEVEL 3

why? Is not it too restrictive?

I am missing a regress tests.

Regards

Pavel

2014-06-18 11:19 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

On 17 June 2014 02:01, Alvaro Herrera Wrote:

What's the status of this patch?

I have completed work on this and some more changes are done on top of
earlier patch shared:
1. Fixed all of the issues observed.
2. Addressed some of the feedback from community like
a. Change the syntax to
START AUTONOMOUS TRANSACTION [READ ONLY | READ
WRITE]
b. As Pavan had pointed, I have made transaction behavior (only
read-only properties) of main and autonomous transaction independent.
3. Added documentation for this feature.
4. Rebased to latest git code.

Please find the attached latest patch and provide opinion.

Thanks and Regards,
Kumar Rajeev Rastogi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#37Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Pavel Stehule (#36)
1 attachment(s)
Re: Autonomous Transaction (WIP)

On 24 June 2014 22:18, Pavel Stehule Wrote:

Thanks for looking into this patch.

There are lot of unnecessary block over one statement in code

+               if ((inAutoX) && (chunk == events->head) && ((char *)event < afterTriggers->events_stack[my_level].tailfree))
+               {
+                       continue;
+               }
+
and there a few too long lines

I have removed unnecessary blocks and long lines are broken in shorted lines.

plancache ... ok
limit ... ok
plpgsql ... ok
copy2 ... ok
temp ... FAILED
domain ... ok
rangefuncs ... ok
prepare ... ok
without_oid ... ok
conversion ... ok
truncate ... ok
alter_table ... ok
sequence ... ok

Fixed the regression test failure.

I did some small tests and it works well. When I looked to code, I was surprised by hardcoded max nesting level of autonomous transactions

#define MAX_AUTOX_NESTING_LEVEL 3
why? Is not it too restrictive?

Yes you are right. I had plan to make it configurable parameters but wanted to take feedback of community. Please let me know if configurable
parameter with minimum value as zero (which is also default value to disable this feature) and maximum as 100 will be OK.? In current patch this
Change is not available.
Apart from the issue reported by you, in the latest patch I have also added support for local transaction ID for autonomous transaction also, as it has dependency on
CONCURRENT INDEX and CHECKPOINT.

Updated patch is attached.

Thanks and Regards,
Kumar Rajeev Rastogi

Attachments:

autonomous_tx_v3.patchapplication/octet-stream; name=autonomous_tx_v3.patchDownload
*** /dev/null
--- b/doc/src/sgml/ref/start_autonomous_transaction.sgml
***************
*** 0 ****
--- 1,51 ----
+ <!--
+ doc/src/sgml/ref/start_autonomous_transaction.sgml
+ PostgreSQL documentation
+ -->
+ 
+ <refentry id="SQL-START-AUTONOMOUS-TRANSACTION">
+  <indexterm zone="sql-start-autonomous-transaction">
+   <primary>START AUTONOMOUS TRANSACTION</primary>
+  </indexterm>
+ 
+  <refmeta>
+   <refentrytitle>START AUTONOMOUS TRANSACTION</refentrytitle>
+   <manvolnum>7</manvolnum>
+   <refmiscinfo>SQL - Language Statements</refmiscinfo>
+  </refmeta>
+ 
+  <refnamediv>
+   <refname>START AUTONOMOUS TRANSACTION</refname>
+   <refpurpose>start an autonomous transaction block</refpurpose>
+  </refnamediv>
+ 
+  <refsynopsisdiv>
+ <synopsis>
+ START AUTONOMOUS TRANSACTION [ <replaceable class="parameter">transaction_mode</replaceable>]
+ 
+ <phrase>where <replaceable class="parameter">transaction_mode</replaceable> is one of:</phrase>
+ 
+     READ WRITE | READ ONLY
+ 
+ </synopsis>
+  </refsynopsisdiv>
+ 
+  <refsect1>
+   <title>Description</title>
+ 
+   <para>
+    This command begins a new autonomous transaction block. This can be started
+    only with in already running transaction block.
+   </para>
+ 
+    <para>
+    An autonomous transaction has its own <xref linkend="sql-commit"> and
+    <xref linkend="sql-rollback"> scope to ensure
+    that its outcome does not effect the caller's uncommitted changes.
+    Additionally, the <xref linkend="sql-commit"> and <xref linkend="sql-rollback">
+    in the calling  transaction should not effect the changes that were finalized
+    on the completion of autonomous transaction itself. If read/write mode is
+    specified, the new transaction has those characteristics.
+   </para>
+  </refsect1>
+ </refentry>
*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
***************
*** 973,979 **** 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));
--- 973,979 ----
  	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
***************
*** 79,85 **** int			synchronous_commit = SYNCHRONOUS_COMMIT_ON;
   */
  bool		MyXactAccessedTempRel = false;
  
- 
  /*
   *	transaction states - transaction state from server perspective
   */
--- 79,84 ----
***************
*** 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;
  
  /*
--- 122,136 ----
  	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
--- 156,163 ----
  	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);
--- 288,295 ----
  static void CommitSubTransaction(void);
  static void AbortSubTransaction(void);
  static void CleanupSubTransaction(void);
! static void PushTransaction(bool isAutoTX, bool readOnly);
! static TransactionId GetTopAutonomousTransactionID(void);
  static void PopTransaction(void);
  
  static void AtSubAbort_Memory(void);
***************
*** 294,299 **** static void ShowTransactionStateRec(TransactionState state);
--- 304,313 ----
  static const char *BlockStateAsString(TBlockState blockState);
  static const char *TransStateAsString(TransState state);
  
+ extern void GetPreContextAndResource(MemoryContext *preContext,
+ 													ResourceOwner *preOwner);
+ extern void SetPreContextAndResource(MemoryContext preContext,
+ 													ResourceOwner preOwner);
  
  /* ----------------------------------------------------------------
   *	transaction state accessors
***************
*** 332,338 **** IsAbortedTransactionBlockState(void)
  	TransactionState s = CurrentTransactionState;
  
  	if (s->blockState == TBLOCK_ABORT ||
! 		s->blockState == TBLOCK_SUBABORT)
  		return true;
  
  	return false;
--- 346,353 ----
  	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;
  }
--- 363,371 ----
  TransactionId
  GetTopTransactionId(void)
  {
! 	if (MyProc->inAutoTXLevel)
! 		return GetTopAutonomousTransactionID();
! 	else if (!TransactionIdIsValid(TopTransactionStateData.transactionId))
  		AssignTransactionId(&TopTransactionStateData);
  	return TopTransactionStateData.transactionId;
  }
***************
*** 363,368 **** GetTopTransactionId(void)
--- 380,403 ----
  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;
  }
  
***************
*** 450,461 **** AssignTransactionId(TransactionState s)
  {
  	bool		isSubXact = (s->parent != NULL);
  	ResourceOwner currentOwner;
! 	bool		log_unknown_top = false;
  
  	/* Assert that caller didn't screw up */
  	Assert(!TransactionIdIsValid(s->transactionId));
  	Assert(s->state == TRANS_INPROGRESS);
  
  	/*
  	 * 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
--- 485,516 ----
  {
  	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);
  
  	/*
--- 562,570 ----
  	 * 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 */
--- 804,827 ----
  	{
  		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)
--- 841,853 ----
  			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);
--- 1067,1073 ----
   * 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);
  
  	/*
--- 1080,1095 ----
  	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
--- 1117,1123 ----
  		 * 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();
  
--- 1146,1158 ----
  		 * 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.
--- 1313,1333 ----
  	 */
  	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 */
--- 1339,1346 ----
  		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 */
--- 1636,1670 ----
  	 * 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;
! 
! 				/* the top of auto TX */
! 				if(stateNestingLevel == autoNestingLevel)
! 					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 */
***************
*** 1799,1805 **** StartTransaction(void)
  	/*
  	 * Lock the virtual transaction id before we announce it in the proc array
  	 */
! 	VirtualXactLockTableInsert(vxid);
  
  	/*
  	 * Advertise it in the proc array.  We assume assignment of
--- 1917,1923 ----
  	/*
  	 * Lock the virtual transaction id before we announce it in the proc array
  	 */
! 	VirtualXactLockTableInsert(vxid, false);
  
  	/*
  	 * Advertise it in the proc array.  We assume assignment of
***************
*** 1945,1951 **** CommitTransaction(void)
  	/*
  	 * Here is where we really truly commit.
  	 */
! 	latestXid = RecordTransactionCommit();
  
  	TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->lxid);
  
--- 2063,2069 ----
  	/*
  	 * Here is where we really truly commit.
  	 */
! 	latestXid = RecordTransactionCommit(false);
  
  	TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->lxid);
  
***************
*** 2539,2544 **** StartTransactionCommand(void)
--- 2657,2663 ----
  			 */
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			break;
  
  			/*
***************
*** 2551,2556 **** StartTransactionCommand(void)
--- 2670,2676 ----
  			 */
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
+ 		case TBLOCK_AUTOABORT:
  			break;
  
  			/* These cases are invalid. */
***************
*** 2567,2572 **** StartTransactionCommand(void)
--- 2687,2696 ----
  		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;
***************
*** 2702,2708 **** CommitTransactionCommand(void)
  			} while (s->blockState == TBLOCK_SUBRELEASE);
  
  			Assert(s->blockState == TBLOCK_INPROGRESS ||
! 				   s->blockState == TBLOCK_SUBINPROGRESS);
  			break;
  
  			/*
--- 2826,2833 ----
  			} while (s->blockState == TBLOCK_SUBRELEASE);
  
  			Assert(s->blockState == TBLOCK_INPROGRESS ||
! 				   s->blockState == TBLOCK_SUBINPROGRESS ||
! 				   s->blockState == TBLOCK_AUTOINPROGRESS);
  			break;
  
  			/*
***************
*** 2733,2738 **** CommitTransactionCommand(void)
--- 2858,2868 ----
  				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));
***************
*** 2814,2819 **** CommitTransactionCommand(void)
--- 2944,2973 ----
  				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;
  	}
  }
  
***************
*** 2900,2905 **** AbortCurrentTransaction(void)
--- 3054,3060 ----
  			 */
  		case TBLOCK_ABORT:
  		case TBLOCK_SUBABORT:
+ 		case TBLOCK_AUTOABORT:
  			break;
  
  			/*
***************
*** 2966,2971 **** AbortCurrentTransaction(void)
--- 3121,3142 ----
  			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;
  	}
  }
  
***************
*** 3269,3274 **** BeginTransactionBlock(void)
--- 3440,3447 ----
  		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")));
***************
*** 3288,3293 **** BeginTransactionBlock(void)
--- 3461,3470 ----
  		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;
***************
*** 3312,3317 **** PrepareTransactionBlock(char *gid)
--- 3489,3498 ----
  	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();
  
***************
*** 3387,3393 **** 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;
--- 3568,3574 ----
  			 * 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;
***************
*** 3398,3403 **** EndTransactionBlock(void)
--- 3579,3587 ----
  			}
  			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));
***************
*** 3410,3416 **** EndTransactionBlock(void)
  			 * transaction.
  			 */
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL)
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
--- 3594,3600 ----
  			 * transaction.
  			 */
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL && !IS_TOP_AUTO_TX_STATE(s))
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
***************
*** 3425,3430 **** EndTransactionBlock(void)
--- 3609,3619 ----
  				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));
***************
*** 3443,3448 **** EndTransactionBlock(void)
--- 3632,3646 ----
  			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:
***************
*** 3457,3462 **** EndTransactionBlock(void)
--- 3655,3664 ----
  		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;
***************
*** 3503,3509 **** UserAbortTransactionBlock(void)
  			 */
  		case TBLOCK_SUBINPROGRESS:
  		case TBLOCK_SUBABORT:
! 			while (s->parent != NULL)
  			{
  				if (s->blockState == TBLOCK_SUBINPROGRESS)
  					s->blockState = TBLOCK_SUBABORT_PENDING;
--- 3705,3711 ----
  			 */
  		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;
***************
*** 3518,3523 **** UserAbortTransactionBlock(void)
--- 3720,3730 ----
  				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));
***************
*** 3535,3540 **** UserAbortTransactionBlock(void)
--- 3742,3754 ----
  					 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:
***************
*** 3550,3555 **** UserAbortTransactionBlock(void)
--- 3764,3773 ----
  		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;
***************
*** 3569,3577 **** 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
--- 3787,3797 ----
  	{
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction(false, XactReadOnly);
! 
!  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
  			 * Savepoint names, like the TransactionState block itself, live
***************
*** 3598,3603 **** DefineSavepoint(char *name)
--- 3818,3828 ----
  		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;
***************
*** 3626,3631 **** ReleaseSavepoint(List *options)
--- 3851,3858 ----
  			 * defined.
  			 */
  		case TBLOCK_INPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 
  			ereport(ERROR,
  					(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  					 errmsg("no such savepoint")));
***************
*** 3655,3660 **** ReleaseSavepoint(List *options)
--- 3882,3893 ----
  		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;
***************
*** 3670,3682 **** 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")));
--- 3903,3917 ----
  
  	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")));
***************
*** 3727,3732 **** RollbackToSavepoint(List *options)
--- 3962,3970 ----
  			 */
  		case TBLOCK_INPROGRESS:
  		case TBLOCK_ABORT:
+ 		case TBLOCK_AUTOINPROGRESS:
+ 		case TBLOCK_AUTOABORT:
+ 
  			ereport(ERROR,
  					(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
  					 errmsg("no such savepoint")));
***************
*** 3754,3759 **** RollbackToSavepoint(List *options)
--- 3992,4001 ----
  		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;
***************
*** 3769,3781 **** 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")));
--- 4011,4025 ----
  
  	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")));
***************
*** 3838,3845 **** BeginInternalSubTransaction(char *name)
  		case TBLOCK_END:
  		case TBLOCK_PREPARE:
  		case TBLOCK_SUBINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction();
  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
--- 4082,4090 ----
  		case TBLOCK_END:
  		case TBLOCK_PREPARE:
  		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_AUTOINPROGRESS:
  			/* Normal subtransaction start */
! 			PushTransaction(false, XactReadOnly);
  			s = CurrentTransactionState;		/* changed by push */
  
  			/*
***************
*** 3864,3869 **** BeginInternalSubTransaction(char *name)
--- 4109,4119 ----
  		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;
***************
*** 3931,3936 **** RollbackAndReleaseCurrentSubTransaction(void)
--- 4181,4192 ----
  		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;
***************
*** 4029,4034 **** AbortOutOfAnyTransaction(void)
--- 4285,4305 ----
  				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);
  
***************
*** 4089,4094 **** TransactionBlockStatusCode(void)
--- 4360,4368 ----
  		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:
***************
*** 4098,4103 **** TransactionBlockStatusCode(void)
--- 4372,4380 ----
  		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 */
  	}
  
***************
*** 4412,4418 **** CleanupSubTransaction(void)
  
  	ShowTransactionState("CleanupSubTransaction");
  
! 	if (s->state != TRANS_ABORT)
  		elog(WARNING, "CleanupSubTransaction while in %s state",
  			 TransStateAsString(s->state));
  
--- 4689,4695 ----
  
  	ShowTransactionState("CleanupSubTransaction");
  
! 	if (s->state != TRANS_ABORT && !IS_TOP_AUTO_TX_STATE(s))
  		elog(WARNING, "CleanupSubTransaction while in %s state",
  			 TransStateAsString(s->state));
  
***************
*** 4439,4448 **** 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.
--- 4716,4726 ----
   *	if it has a local pointer to it after calling this function.
   */
  static void
! PushTransaction(bool isAutoTX, bool readOnly)
  {
  	TransactionState p = CurrentTransactionState;
  	TransactionState s;
+ 	PGAutonomousXACT *currentautotx = NULL;
  
  	/*
  	 * We keep subtransaction state nodes in TopTransactionContext.
***************
*** 4475,4484 **** 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;
  
  	/*
--- 4753,4776 ----
  	s->gucNestLevel = NewGUCNestLevel();
  	s->savepointLevel = p->savepointLevel;
  	s->state = TRANS_DEFAULT;
  	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
  	s->prevXactReadOnly = XactReadOnly;
  
+ 	if (isAutoTX)
+ 	{
+ 		VirtualTransactionId vxid;
+ 		MyProc->inAutoTXLevel++;
+ 		currentautotx = GetCurrentPGAutonomousXACT();
+ 		currentautotx->nestingLevel = s->nestingLevel;
+ 		vxid.localTransactionId = currentautotx->lxid = GetNextLocalTransactionId();
+ 		vxid.backendId = MyProc->backendId;
+ 		VirtualXactLockTableInsert(vxid, true);
+  		s->blockState = TBLOCK_AUTOBEGIN;
+ 		XactReadOnly = readOnly;
+ 	}
+ 	else
+ 		s->blockState = TBLOCK_SUBBEGIN;
+ 
  	CurrentTransactionState = s;
  
  	/*
***************
*** 4500,4505 **** static void
--- 4792,4798 ----
  PopTransaction(void)
  {
  	TransactionState s = CurrentTransactionState;
+ 	PGAutonomousXACT *currentautox = NULL;
  
  	if (s->state != TRANS_DEFAULT)
  		elog(WARNING, "PopTransaction while in %s state",
***************
*** 4518,4523 **** PopTransaction(void)
--- 4811,4823 ----
  	CurTransactionResourceOwner = s->parent->curTransactionOwner;
  	CurrentResourceOwner = s->parent->curTransactionOwner;
  
+ 	if(IS_TOP_AUTO_TX_STATE(s))
+ 	{
+ 		currentautox = GetCurrentPGAutonomousXACT();
+ 		MemSet(currentautox, 0, sizeof(PGAutonomousXACT));
+ 		MyProc->inAutoTXLevel--;
+ 	}
+ 
  	/* Free the old child structure */
  	if (s->name)
  		pfree(s->name);
***************
*** 4622,4627 **** BlockStateAsString(TBlockState blockState)
--- 4922,4939 ----
  			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";
  }
***************
*** 4994,4996 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
--- 5306,5880 ----
  	else
  		elog(PANIC, "xact_redo: unknown op code %u", info);
  }
+ 
+ /*
+  * DefineAutonomousTransaction:
+  * This fuction creates an autonomous transaction.
+  * readOnly: This argumet indicates, whether it is read-only or read-write
+  * transaction.
+  * Note: In future, if we are supporting more independent properties to auto tx,
+  * the we can pass a structure containig all properties instead of bool.
+  */
+ void
+ DefineAutonomousTransaction(bool readOnly)
+ {
+ 	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, readOnly);
+ 			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);
+ 
+ 	/* Release auto tx VXID*/
+ 	VirtualAutoXactLockTableCleanup();
+ 	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);
+ 
+ 		/* Release auto tx VXID*/
+ 		VirtualAutoXactLockTableCleanup();
+ 
+ 		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: SetPreContextAndResource
+  * save the previous memory context and resource owner
+  * Param: preContext
+  * Param: preOwner
+  */
+ void
+ SetPreContextAndResource(MemoryContext preContext,ResourceOwner preOwner)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 
+ 	if (s)
+ 	{
+ 		s->preMemoryContext = preContext;
+ 		s->preResourceOwner = preOwner;
+ 	}
+ }
+ 
+ /*
+  * Brief: GetPreContextAndResource
+  * get  the previous memory context and resource owner
+  * Param: preContext
+  * Param: preOwner
+  */
+ void
+ 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, XactReadOnly);
+ 			break;
+ 
+ 			/* These cases are invalid. */
+ 
+ 		default:
+ 			ereport(FATAL,
+ 					(errmsg("DefineAutonomousTransaction: unexpected state %s",
+ 				 BlockStateAsString(s->blockState))));
+ 			break;
+ 	}
+ 	CommitTransactionCommand();
+ 	StartTransactionCommand();
+ 	SetPreContextAndResource(oldContext, oldOwner);
+ 	MyProc->isIntAutoTx = true;
+ 	(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;
+ 	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;
+ 
+ 	MyProc->isIntAutoTx = false;
+ }
+ 
+ void
+ AbortInternalAutonomousTransaction(void)
+ {
+ 
+ 	TransactionState s = CurrentTransactionState;
+ 	MemoryContext	preContext  = NULL;
+ 	ResourceOwner	preOwner    = NULL;
+ 	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;
+ 	MyProc->isIntAutoTx = false;
+ }
+ 
+ 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
***************
*** 943,949 **** setval3_oid(PG_FUNCTION_ARGS)
  static Relation
  open_share_lock(SeqTable seq)
  {
! 	LocalTransactionId thislxid = MyProc->lxid;
  
  	/* Get the lock if not already held in this xact */
  	if (seq->lxid != thislxid)
--- 943,957 ----
  static Relation
  open_share_lock(SeqTable seq)
  {
! 	LocalTransactionId thislxid;
! 
! 	if (MyProc->inAutoTXLevel)
! 	{
! 		PGAutonomousXACT *currentautotx = GetCurrentPGAutonomousXACT();
! 		thislxid = currentautotx->lxid;
! 	}
! 	else
! 		thislxid = MyProc->lxid;
  
  	/* Get the lock if not already held in this xact */
  	if (seq->lxid != thislxid)
***************
*** 953,959 **** open_share_lock(SeqTable seq)
  		currentOwner = CurrentResourceOwner;
  		PG_TRY();
  		{
! 			CurrentResourceOwner = TopTransactionResourceOwner;
  			LockRelationOid(seq->relid, AccessShareLock);
  		}
  		PG_CATCH();
--- 961,969 ----
  		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
***************
*** 87,92 ****
--- 87,93 ----
  #include "utils/syscache.h"
  #include "utils/tqual.h"
  #include "utils/typcache.h"
+ #include "storage/proc.h"
  
  
  /*
***************
*** 106,111 **** typedef struct OnCommitItem
--- 107,115 ----
  	 */
  	SubTransactionId creating_subid;
  	SubTransactionId deleting_subid;
+ 
+ 	TransactionId	toptxid;	/* top tx id */
+ 
  } OnCommitItem;
  
  static List *on_commits = NIL;
***************
*** 10735,10740 **** register_on_commit_action(Oid relid, OnCommitAction action)
--- 10739,10745 ----
  	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
  	oc->relid = relid;
  	oc->oncommit = action;
+ 	oc->toptxid = GetTopTransactionId();
  	oc->creating_subid = GetCurrentSubTransactionId();
  	oc->deleting_subid = InvalidSubTransactionId;
  
***************
*** 10792,10797 **** PreCommit_on_commit_actions(void)
--- 10797,10804 ----
  				/* 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
***************
*** 10805,10810 **** PreCommit_on_commit_actions(void)
--- 10812,10820 ----
  				{
  					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;
***************
*** 3679,3695 **** 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)))
  		{
--- 3679,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)))
  		{
***************
*** 3752,3758 **** 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;
***************
*** 3764,3769 **** 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)
***************
*** 3789,3794 **** afterTriggerInvokeEvents(AfterTriggerEventList *events,
--- 3796,3806 ----
  		{
  			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?
  			 */
***************
*** 4033,4044 **** 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
--- 4045,4056 ----
  	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
***************
*** 4097,4107 **** 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 */
  	}
  
--- 4109,4197 ----
  	 * 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 */
  	}
  
***************
*** 4112,4117 **** AfterTriggerFireDeferred(void)
--- 4202,4208 ----
  
  	if (snap_pushed)
  		PopActiveSnapshot();
+ 	pfree(events);
  }
  
  
***************
*** 4659,4665 **** AfterTriggerSetState(ConstraintsSetStmt *stmt)
  		AfterTriggerEventList *events = &afterTriggers->events;
  		bool		snapshot_set = false;
  
! 		while (afterTriggerMarkEvents(events, NULL, true))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
--- 4750,4756 ----
  		AfterTriggerEventList *events = &afterTriggers->events;
  		bool		snapshot_set = false;
  
! 		while (afterTriggerMarkEvents(events, NULL, true, false))
  		{
  			CommandId	firing_id = afterTriggers->firing_counter++;
  
***************
*** 4684,4690 **** AfterTriggerSetState(ConstraintsSetStmt *stmt)
  			 * subtransaction could later get rolled back.
  			 */
  			if (afterTriggerInvokeEvents(events, firing_id, NULL,
! 										 !IsSubTransaction()))
  				break;			/* all fired */
  		}
  
--- 4775,4781 ----
  			 * 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
***************
*** 2069,2074 **** _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
--- 2069,2092 ----
  		 * 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
***************
*** 349,355 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  				execute_param_clause using_clause returning_clause
  				opt_enum_val_list enum_val_list table_func_column_list
  				create_generic_options alter_generic_options
! 				relation_expr_list dostmt_opt_list
  
  %type <list>	opt_fdw_options fdw_options
  %type <defelt>	fdw_option
--- 349,355 ----
  				execute_param_clause using_clause returning_clause
  				opt_enum_val_list enum_val_list table_func_column_list
  				create_generic_options alter_generic_options
! 				relation_expr_list dostmt_opt_list opt_auto_transaction_mode
  
  %type <list>	opt_fdw_options fdw_options
  %type <defelt>	fdw_option
***************
*** 527,532 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
--- 527,533 ----
  %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
  
  	BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
  	BOOLEAN_P BOTH BY
***************
*** 8166,8171 **** TransactionStmt:
--- 8167,8179 ----
  					n->gid = $3;
  					$$ = (Node *)n;
  				}
+ 			| START AUTONOMOUS TRANSACTION opt_auto_transaction_mode
+ 				{
+                     TransactionStmt *n = makeNode(TransactionStmt);
+                     n->kind = TRANS_STMT_AUTONOMOUS;
+                     n->options = $4;
+                     $$ = (Node *)n;
+                 }
  		;
  
  opt_transaction:	WORK							{}
***************
*** 8173,8178 **** opt_transaction:	WORK							{}
--- 8181,8197 ----
  			| /*EMPTY*/								{}
  		;
  
+ opt_auto_transaction_mode:
+ 			 READ ONLY
+ 					{ $$ = list_make1(makeDefElem("transaction_read_only",
+ 									  	 (Node *)makeInteger(TRUE))); }
+ 			| READ WRITE
+ 					{ $$ = list_make1(makeDefElem("transaction_read_only",
+ 										   (Node *)makeInteger(FALSE))); }
+ 			| /* EMPTY */
+ 					{ $$ = NIL; }
+ 		;
+ 
  transaction_mode_item:
  			ISOLATION LEVEL iso_level
  					{ $$ = makeDefElem("transaction_isolation",
***************
*** 12858,12863 **** unreserved_keyword:
--- 12877,12883 ----
  			| ASSIGNMENT
  			| AT
  			| ATTRIBUTE
+ 			| AUTONOMOUS
  			| BACKWARD
  			| BEFORE
  			| BEGIN_P
*** 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;
  
+ 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,504 ----
  	}
  }
  
+ 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;
+ 		pgautonouxact->lxid = InvalidLocalTransactionId;
+ 
+ 		/* 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 */
+ 
+ 		pgautonouxact->lxid = InvalidLocalTransactionId;
+ 
+ 		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
--- 910,917 ----
  	ProcArrayStruct *arrayP = procArray;
  	TransactionId topxid;
  	int			i,
! 				j,
! 				k;
  
  	/*
  	 * Don't bother checking a transaction older than RecentXmin; it could not
***************
*** 900,906 **** TransactionIdIsInProgress(TransactionId xid)
  		 * known-assigned list. If we later finish recovery, we no longer need
  		 * the bigger array, but we don't bother to shrink it.
  		 */
! 		int			maxxids = RecoveryInProgress() ? TOTAL_MAX_CACHED_SUBXIDS : arrayP->maxProcs;
  
  		xids = (TransactionId *) malloc(maxxids * sizeof(TransactionId));
  		if (xids == NULL)
--- 957,964 ----
  		 * known-assigned list. If we later finish recovery, we no longer need
  		 * the bigger array, but we don't bother to shrink it.
  		 */
! 		int			maxxids = (RecoveryInProgress() ? TOTAL_MAX_CACHED_SUBXIDS
! 															: arrayP->maxProcs);
  
  		xids = (TransactionId *) malloc(maxxids * sizeof(TransactionId));
  		if (xids == NULL)
***************
*** 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 */
--- 984,998 ----
  	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)
--- 1043,1087 ----
  		 */
  		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)
--- 1467,1473 ----
  	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)
--- 1536,1546 ----
  			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. */
--- 1577,1589 ----
  			 */
  			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)
--- 1623,1669 ----
  					}
  				}
  			}
+ 
+ 			/* 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
***************
*** 2039,2052 **** GetVirtualXIDsDelayingChkpt(int *nvxids)
  
  	for (index = 0; index < arrayP->numProcs; index++)
  	{
  		int			pgprocno = arrayP->pgprocnos[index];
  		volatile PGPROC *proc = &allProcs[pgprocno];
  		volatile PGXACT *pgxact = &allPgXact[pgprocno];
  
! 		if (pgxact->delayChkpt)
! 		{
! 			VirtualTransactionId vxid;
  
  			GET_VXID_FROM_PGPROC(vxid, *proc);
  			if (VirtualTransactionIdIsValid(vxid))
  				vxids[count++] = vxid;
--- 2192,2223 ----
  
  	for (index = 0; index < arrayP->numProcs; index++)
  	{
+ 		VirtualTransactionId vxid;
+ 
  		int			pgprocno = arrayP->pgprocnos[index];
  		volatile PGPROC *proc = &allProcs[pgprocno];
  		volatile PGXACT *pgxact = &allPgXact[pgprocno];
  
! 		int			pgautoxno = pgprocno * MAX_AUTOX_NESTING_LEVEL;
! 		volatile PGAutonomousXACT *pgautonomousxact;
  
+ 		/*
+ 		 * If autonomous transaction is there, then only lowest autonomous
+ 		 * transaction can be in "in commit" stage. So in that case skip
+ 		 * checking for this stage for upper transaction.
+ 		 */
+ 		if (proc->inAutoTXLevel)
+ 		{
+ 			pgautonomousxact = &allPgAutonomousXact[pgautoxno + proc->inAutoTXLevel - 1];
+ 			if (pgautonomousxact->delayChkpt)
+ 			{
+ 				GET_VXID_FROM_PGAUTOXACT(vxid, *proc, *pgautonomousxact);
+ 				if (VirtualTransactionIdIsValid(vxid))
+ 					vxids[count++] = vxid;
+ 			}
+ 		}
+ 		else if (pgxact->delayChkpt)
+ 		{
  			GET_VXID_FROM_PGPROC(vxid, *proc);
  			if (VirtualTransactionIdIsValid(vxid))
  				vxids[count++] = vxid;
***************
*** 2084,2092 **** HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids)
  		volatile PGXACT *pgxact = &allPgXact[pgprocno];
  		VirtualTransactionId vxid;
  
! 		GET_VXID_FROM_PGPROC(vxid, *proc);
  
! 		if (pgxact->delayChkpt && VirtualTransactionIdIsValid(vxid))
  		{
  			int			i;
  
--- 2255,2278 ----
  		volatile PGXACT *pgxact = &allPgXact[pgprocno];
  		VirtualTransactionId vxid;
  
! 		int			pgautoxno = pgprocno * MAX_AUTOX_NESTING_LEVEL;
! 		volatile PGAutonomousXACT *pgautonomousxact;
! 		bool delayChkpt = false;
! 
  
! 		if (proc->inAutoTXLevel)
! 		{
! 			pgautonomousxact = &allPgAutonomousXact[pgautoxno + proc->inAutoTXLevel - 1];
! 			delayChkpt = pgautonomousxact->delayChkpt;
! 			GET_VXID_FROM_PGAUTOXACT(vxid, *proc, *pgautonomousxact);
! 		}
! 		else
! 		{
! 			delayChkpt = pgxact->delayChkpt;
! 			GET_VXID_FROM_PGPROC(vxid, *proc);
! 		}
! 
! 		if (delayChkpt && VirtualTransactionIdIsValid(vxid))
  		{
  			int			i;
  
***************
*** 2795,2800 **** XidCacheRemoveRunningXids(TransactionId xid,
--- 2981,3069 ----
  	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/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
***************
*** 85,91 **** InitRecoveryTransactionEnvironment(void)
  	 */
  	vxid.backendId = MyBackendId;
  	vxid.localTransactionId = GetNextLocalTransactionId();
! 	VirtualXactLockTableInsert(vxid);
  
  	standbyState = STANDBY_INITIALIZED;
  }
--- 85,91 ----
  	 */
  	vxid.backendId = MyBackendId;
  	vxid.localTransactionId = GetNextLocalTransactionId();
! 	VirtualXactLockTableInsert(vxid, false);
  
  	standbyState = STANDBY_INITIALIZED;
  }
*** 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
***************
*** 50,58 ****
  /* This configuration variable is used to set the lock table size */
  int			max_locks_per_xact; /* set by guc.c */
  
! #define NLOCKENTS() \
! 	mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
  
  
  /*
   * Data structures defining the semantics of the standard lock methods.
--- 50,60 ----
  /* This configuration variable is used to set the lock table size */
  int			max_locks_per_xact; /* set by guc.c */
  
! extern PGAutonomousXACT *allPgAutonomousXact;
  
+ #define NLOCKENTS() \
+ 	mul_size(max_locks_per_xact, add_size((MAX_AUTOX_NESTING_LEVEL*MaxConnections), \
+ 						add_size(MaxBackends, max_prepared_xacts)))
  
  /*
   * Data structures defining the semantics of the standard lock methods.
***************
*** 355,360 **** static void LockRefindAndRelease(LockMethod lockMethodTable, PGPROC *proc,
--- 357,365 ----
  					 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,
--- 788,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,1161 ----
  		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,
--- 1286,1293 ----
  	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,
--- 1311,1327 ----
  	 */
  	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,
--- 1360,1385 ----
  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;
+ 
+ 	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,
--- 1435,1446 ----
  	/*
  	 * 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);
  
***************
*** 2823,2844 **** GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
  
  	while (proclock)
  	{
! 		if (conflictMask & proclock->holdMask)
  		{
! 			PGPROC	   *proc = proclock->tag.myProc;
  
! 			/* A backend never blocks itself */
! 			if (proc != MyProc)
  			{
! 				VirtualTransactionId vxid;
  
! 				GET_VXID_FROM_PGPROC(vxid, *proc);
  
! 				/*
! 				 * If we see an invalid VXID, then either the xact has already
! 				 * committed (or aborted), or it's a prepared xact.  In either
! 				 * case we may ignore it.
! 				 */
  				if (VirtualTransactionIdIsValid(vxid))
  				{
  					int			i;
--- 2870,2909 ----
  
  	while (proclock)
  	{
! 		PGPROC	   *proc = proclock->tag.myProc;
! 		/* A backend never blocks itself */
! 		if (proc != MyProc)
  		{
! 			VirtualTransactionId vxid;
! 			int txLevel;
  
! 			/*
! 			 * If we see an invalid VXID, then either the xact has already
! 			 * committed (or aborted), or it's a prepared xact.  In either
! 			 * case we may ignore it.
! 			 */
! 
! 			/* First we should check for autonomous transaction*/
! 			for (txLevel = 0; txLevel < proc->inAutoTXLevel; txLevel++)
  			{
! 				int			pgautoxno = proc->pgprocno * MAX_AUTOX_NESTING_LEVEL;
! 				PGAutonomousXACT *autoxact = &allPgAutonomousXact[pgautoxno
! 																+ txLevel];
  
! 				if (conflictMask & proclock->holdMaskByAutoTX[txLevel])
! 				{
! 					GET_VXID_FROM_PGAUTOXACT(vxid, *proc, *autoxact);
  
! 					/* Auto tx will not be part of FPL, so no need to check*/
! 					if (VirtualTransactionIdIsValid(vxid))
! 						vxids[count++] = vxid;
! 				}
! 			}
! 
! 			/* Then main transaction*/
! 			if (conflictMask & proclock->holdMaskByNormalTX)
! 			{
! 				GET_VXID_FROM_PGPROC(vxid, *proc);
  				if (VirtualTransactionIdIsValid(vxid))
  				{
  					int			i;
***************
*** 3786,3791 **** lock_twophase_recover(TransactionId xid, uint16 info,
--- 3851,3861 ----
  	{
  		proclock->holdMask = 0;
  		proclock->releaseMask = 0;
+ 
+ 		MemSet(proclock->holdMaskByAutoTX, 0, MAX_AUTOX_NESTING_LEVEL *
+ 															(sizeof(LOCKMASK)));
+ 		proclock->holdMaskByNormalTX = 0;
+ 
  		/* Add proclock to appropriate lists */
  		SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
  		SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
***************
*** 3925,3946 **** lock_twophase_postabort(TransactionId xid, uint16 info,
   *		LockReleaseAll() calls VirtualXactLockTableCleanup().
   */
  void
! VirtualXactLockTableInsert(VirtualTransactionId vxid)
  {
  	Assert(VirtualTransactionIdIsValid(vxid));
  
  	LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
  
! 	Assert(MyProc->backendId == vxid.backendId);
! 	Assert(MyProc->fpLocalTransactionId == InvalidLocalTransactionId);
! 	Assert(MyProc->fpVXIDLock == false);
  
! 	MyProc->fpVXIDLock = true;
! 	MyProc->fpLocalTransactionId = vxid.localTransactionId;
  
  	LWLockRelease(MyProc->backendLock);
  }
  
  /*
   *		VirtualXactLockTableCleanup
   *
--- 3995,4055 ----
   *		LockReleaseAll() calls VirtualXactLockTableCleanup().
   */
  void
! VirtualXactLockTableInsert(VirtualTransactionId vxid, bool isAutoTx)
  {
  	Assert(VirtualTransactionIdIsValid(vxid));
  
  	LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
  
! 	if (!isAutoTx)
! 	{
! 		Assert(MyProc->backendId == vxid.backendId);
! 		Assert(MyProc->fpLocalTransactionId == InvalidLocalTransactionId);
! 		Assert(MyProc->fpVXIDLock == false);
  
! 		MyProc->fpVXIDLock = true;
! 		MyProc->fpLocalTransactionId = vxid.localTransactionId;
! 	}
! 	else
! 	{
! 		int autoLevel = MyProc->inAutoTXLevel - 1; /* 0 based index*/
! 		PGAutonomousXACT *autoxact = &MyPgAutonomousXact[autoLevel];
! 
! 		autoxact->fpLocalAuto.fpAutoLxid= autoxact->lxid;
! 		autoxact->fpLocalAuto.fpAutoVXIDLock = true;
! 	}
  
  	LWLockRelease(MyProc->backendLock);
  }
  
+ void
+ VirtualAutoXactLockTableCleanup(void)
+ {
+ 	LocalTransactionId lxid;
+ 	bool fastpath;
+ 	PGAutonomousXACT *myautoxact = GetCurrentPGAutonomousXACT();
+ 
+ 	LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
+ 
+ 	fastpath = myautoxact->fpLocalAuto.fpAutoVXIDLock;
+ 	lxid = myautoxact->fpLocalAuto.fpAutoLxid;
+ 
+ 	LWLockRelease(MyProc->backendLock);
+ 
+ 	if (!fastpath && LocalTransactionIdIsValid(lxid))
+ 	{
+ 		VirtualTransactionId vxid;
+ 		LOCKTAG		locktag;
+ 
+ 		vxid.backendId = MyBackendId;
+ 		vxid.localTransactionId = lxid;
+ 		SET_LOCKTAG_VIRTUALTRANSACTION(locktag, vxid);
+ 
+ 		LockRefindAndRelease(LockMethods[DEFAULT_LOCKMETHOD], MyProc,
+ 							 &locktag, ExclusiveLock, false);
+ 	}
+ }
+ 
  /*
   *		VirtualXactLockTableCleanup
   *
***************
*** 3985,3990 **** VirtualXactLockTableCleanup(void)
--- 4094,4115 ----
  	}
  }
  
+ int VirtualXactInAutoTx(PGPROC *proc, LocalTransactionId lxid)
+ {
+ 	int level;
+ 	int			pgautoxno = proc->pgprocno * MAX_AUTOX_NESTING_LEVEL;
+ 	PGAutonomousXACT *autoxact = &allPgAutonomousXact[pgautoxno];
+ 
+ 
+ 	for (level = 0; level < proc->inAutoTXLevel; level++)
+ 	{
+ 		if (autoxact[level].fpLocalAuto.fpAutoLxid == lxid)
+ 			return level;
+ 	}
+ 
+ 	return -1;
+ }
+ 
  /*
   *		VirtualXactLock
   *
***************
*** 3999,4004 **** VirtualXactLock(VirtualTransactionId vxid, bool wait)
--- 4124,4134 ----
  {
  	LOCKTAG		tag;
  	PGPROC	   *proc;
+ 	int level = -1;
+ 	bool lockEntryReq = false;
+ 	int			pgautoxno;
+ 	PGAutonomousXACT *autoxact;
+ 
  
  	Assert(VirtualTransactionIdIsValid(vxid));
  
***************
*** 4025,4031 **** VirtualXactLock(VirtualTransactionId vxid, bool wait)
  
  	/* If the transaction has ended, our work here is done. */
  	if (proc->backendId != vxid.backendId
! 		|| proc->fpLocalTransactionId != vxid.localTransactionId)
  	{
  		LWLockRelease(proc->backendLock);
  		return true;
--- 4155,4162 ----
  
  	/* If the transaction has ended, our work here is done. */
  	if (proc->backendId != vxid.backendId
! 		|| ((proc->fpLocalTransactionId != vxid.localTransactionId)
! 		&& (level = VirtualXactInAutoTx(proc, vxid.localTransactionId)) == -1 ))
  	{
  		LWLockRelease(proc->backendLock);
  		return true;
***************
*** 4041,4052 **** VirtualXactLock(VirtualTransactionId vxid, bool wait)
  		return false;
  	}
  
  	/*
  	 * OK, we're going to need to sleep on the VXID.  But first, we must set
  	 * up the primary lock table entry, if needed (ie, convert the proc's
  	 * fast-path lock on its VXID to a regular lock).
  	 */
! 	if (proc->fpVXIDLock)
  	{
  		PROCLOCK   *proclock;
  		uint32		hashcode;
--- 4172,4196 ----
  		return false;
  	}
  
+ 	/* Here means transaction corresponding VXID has not ended.*/
+ 	if (level == -1)
+ 	{
+ 		/* Means it is main transaction*/
+ 		lockEntryReq = proc->fpVXIDLock;
+ 	}
+ 	else
+ 	{
+ 		pgautoxno = proc->pgprocno * MAX_AUTOX_NESTING_LEVEL;
+ 		autoxact = &allPgAutonomousXact[pgautoxno + level];
+ 		lockEntryReq = autoxact->fpLocalAuto.fpAutoVXIDLock;
+ 	}
+ 
  	/*
  	 * OK, we're going to need to sleep on the VXID.  But first, we must set
  	 * up the primary lock table entry, if needed (ie, convert the proc's
  	 * fast-path lock on its VXID to a regular lock).
  	 */
! 	if (lockEntryReq)
  	{
  		PROCLOCK   *proclock;
  		uint32		hashcode;
***************
*** 4072,4078 **** VirtualXactLock(VirtualTransactionId vxid, bool wait)
  
  		LWLockRelease(partitionLock);
  
! 		proc->fpVXIDLock = false;
  	}
  
  	/* Done with proc->fpLockBits */
--- 4216,4228 ----
  
  		LWLockRelease(partitionLock);
  
! 		if (level == -1)
! 		{
! 			/* Means it is main transaction*/
! 			proc->fpVXIDLock = false;
! 		}
! 		else
! 			autoxact->fpLocalAuto.fpAutoVXIDLock = false;
  	}
  
  	/* Done with proc->fpLockBits */
***************
*** 4084,4086 **** VirtualXactLock(VirtualTransactionId vxid, bool wait)
--- 4234,4281 ----
  	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,517 ----
  		return false;
  
  	/*
+ 	 * 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;
+ 
+ 	/*
  	 * 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,125 ----
  	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)
--- 170,178 ----
  	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)
--- 221,232 ----
  	MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACT));
  	ProcGlobal->allPgXact = pgxacts;
  
+ 	pgautonomousxacts = (PGAutonomousXACT *) ShmemAlloc(TotalProcs *
+ 							MAX_AUTOX_NESTING_LEVEL * sizeof(PGAutonomousXACT));
+ 	MemSet(pgautonomousxacts, 0,
+ 			TotalProcs * MAX_AUTOX_NESTING_LEVEL * sizeof(PGAutonomousXACT));
+     ProcGlobal->allPgAutonomousXact = pgautonomousxacts;
+ 
  	for (i = 0; i < TotalProcs; i++)
  	{
  		/* Common initialization for all PGPROCs, regardless of type. */
***************
*** 279,284 **** InitProcess(void)
--- 296,302 ----
  {
  	/* 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)
--- 335,343 ----
  
  	if (MyProc != NULL)
  	{
+ 		MyProc->inAutoTXLevel = 0;
+ 
+ 
  		if (IsAnyAutoVacuumProcess())
  			procglobal->autovacFreeProcs = (PGPROC *) MyProc->links.next;
  		else if (IsBackgroundWorker)
***************
*** 340,345 **** InitProcess(void)
--- 361,371 ----
  	}
  	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
***************
*** 389,394 **** InitProcess(void)
--- 415,421 ----
  	/* Initialize fields for sync rep */
  	MyProc->waitLSN = 0;
  	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
+ 
  	SHMQueueElemInit(&(MyProc->syncRepLinks));
  
  	/*
***************
*** 463,468 **** InitAuxiliaryProcess(void)
--- 490,496 ----
  {
  	PGPROC	   *auxproc;
  	int			proctype;
+ 	int			pgautoxno;
  
  	/*
  	 * ProcGlobal should be set up already (if we are a backend, we inherit
***************
*** 514,519 **** InitAuxiliaryProcess(void)
--- 542,551 ----
  	MyProc = auxproc;
  	MyPgXact = &ProcGlobal->allPgXact[auxproc->pgprocno];
  
+ 	pgautoxno = auxproc->pgprocno * MAX_AUTOX_NESTING_LEVEL;
+ 	MyPgAutonomousXact = &ProcGlobal->allPgAutonomousXact[pgautoxno];
+ 
+ 
  	SpinLockRelease(ProcStructLock);
  
  	/*
***************
*** 1666,1668 **** 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/postgres.c
--- b/src/backend/tcop/postgres.c
***************
*** 3853,3858 **** PostgresMain(int argc, char *argv[],
--- 3853,3863 ----
  		debug_query_string = NULL;
  
  		/*
+ 		 * Abort internal autonomous transaction, if started.
+ 		 */
+ 		if (MyProc->isIntAutoTx)
+ 			AbortInternalAutonomousTransaction();
+ 		/*
  		 * Abort the current transaction in order to recover.
  		 */
  		AbortCurrentTransaction();
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 414,419 **** standard_ProcessUtility(Node *parsetree,
--- 414,440 ----
  						UserAbortTransactionBlock();
  						break;
  
+ 					case TRANS_STMT_AUTONOMOUS:
+ 						{
+ 							ListCell   *cell;
+ 							bool readOnly = false;	/* by default read-write*/
+ 
+ 							RequireTransactionChain(isTopLevel, "AUTONOMOUS TRANSACTION");
+ 							/*
+ 							 * As of now only one element in list is expected.
+ 							 * If more elements added to it, handing might need to
+ 							 * be relooked.
+ 							 */
+ 							foreach(cell, stmt->options)
+ 							{
+ 								DefElem    *elem = lfirst(cell);
+ 								if (strcmp(elem->defname, "transaction_read_only") == 0)
+ 									readOnly = (bool)intVal(elem->arg);
+ 							}
+ 							DefineAutonomousTransaction(readOnly);
+ 						}
+ 						break;
+ 
  					case TRANS_STMT_SAVEPOINT:
  						{
  							ListCell   *cell;
***************
*** 1751,1756 **** CreateCommandTag(Node *parsetree)
--- 1772,1781 ----
  						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
***************
*** 1340,1345 **** ReleaseCatCache(HeapTuple tuple)
--- 1340,1412 ----
  		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
***************
*** 799,810 **** 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
--- 799,812 ----
   */
  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
***************
*** 1003,1008 **** AtEOSubXact_Inval(bool isCommit)
--- 1005,1091 ----
  }
  
  /*
+  * 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"
  
  
  /*---------------------------------------------------------------------------
***************
*** 907,912 **** SearchSysCache(int cacheId,
--- 908,916 ----
  		!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);
  }
  
***************
*** 917,922 **** SearchSysCache(int cacheId,
--- 921,933 ----
  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;
  
  
***************
*** 161,166 **** ResourceOwnerCreate(ResourceOwner parent, const char *name)
--- 163,170 ----
  												   sizeof(ResourceOwnerData));
  	owner->name = name;
  
+ 	owner->inAutoTXLevel = MyProc->inAutoTXLevel;
+ 
  	if (parent)
  	{
  		owner->parent = parent;
***************
*** 1339,1341 **** PrintDSMLeakWarning(dsm_segment *seg)
--- 1343,1353 ----
  		 "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,276 ----
  extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
  extern void xact_desc(StringInfo buf, XLogRecord *record);
  
+ extern void DefineAutonomousTransaction(bool readOnly);
+ 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
***************
*** 2371,2377 **** typedef enum TransactionStmtKind
  	TRANS_STMT_ROLLBACK_TO,
  	TRANS_STMT_PREPARE,
  	TRANS_STMT_COMMIT_PREPARED,
! 	TRANS_STMT_ROLLBACK_PREPARED
  } TransactionStmtKind;
  
  typedef struct TransactionStmt
--- 2371,2378 ----
  	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", AUTONOMOUS, UNRESERVED_KEYWORD)
  PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
  PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
  PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
*** a/src/include/storage/lock.h
--- b/src/include/storage/lock.h
***************
*** 77,82 **** typedef struct
--- 77,87 ----
  	((vxid).backendId = (proc).backendId, \
  	 (vxid).localTransactionId = (proc).lxid)
  
+ #define GET_VXID_FROM_PGAUTOXACT(vxid, proc, autoxact) \
+ 	((vxid).backendId = (proc).backendId, \
+ 	 (vxid).localTransactionId = (autoxact).lxid)
+ 
+ #define  MAX_AUTOX_NESTING_LEVEL   3
  
  /*
   * LOCKMODE is an integer (1..N) indicating a lock type.  LOCKMASK is a bit
***************
*** 92,98 **** typedef int LOCKMODE;
  #define LOCKBIT_ON(lockmode) (1 << (lockmode))
  #define LOCKBIT_OFF(lockmode) (~(1 << (lockmode)))
  
- 
  /*
   * This data structure defines the locking semantics associated with a
   * "lock method".  The semantics specify the meaning of each lock mode
--- 97,102 ----
***************
*** 363,368 **** typedef struct PROCLOCK
--- 367,378 ----
  
  	/* data */
  	LOCKMASK	holdMask;		/* bitmask for lock types currently held */
+ 
+ 	/* bitmask for lock types currently held by autonomous TX */
+ 	LOCKMASK	holdMaskByAutoTX[MAX_AUTOX_NESTING_LEVEL];
+ 
+ 	/* bitmask for lock types currently held by normal 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 */
***************
*** 562,569 **** extern void DumpAllLocks(void);
  #endif
  
  /* Lock a VXID (used to wait for a transaction to finish) */
! extern void VirtualXactLockTableInsert(VirtualTransactionId vxid);
  extern void VirtualXactLockTableCleanup(void);
  extern bool VirtualXactLock(VirtualTransactionId vxid, bool wait);
  
  #endif   /* LOCK_H */
--- 572,583 ----
  #endif
  
  /* Lock a VXID (used to wait for a transaction to finish) */
! extern void VirtualXactLockTableInsert(VirtualTransactionId vxid,
! 																bool isAutoTx);
  extern void VirtualXactLockTableCleanup(void);
  extern bool VirtualXactLock(VirtualTransactionId vxid, bool wait);
  
+ extern void VirtualAutoXactLockTableCleanup(void);
+ extern int VirtualXactInAutoTx(PGPROC *proc, LocalTransactionId lxid);
+ 
  #endif   /* LOCK_H */
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
***************
*** 142,147 **** struct PGPROC
--- 142,150 ----
  	bool		fpVXIDLock;		/* are we holding a fast-path VXID lock? */
  	LocalTransactionId fpLocalTransactionId;	/* lxid for fast-path VXID
  												 * lock */
+ 
+ 	uint8 inAutoTXLevel;		/* At what level of autonomous tx*/
+ 	bool  isIntAutoTx;			/* Is any internal autonomous tx started by proc*/
  };
  
  /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */
***************
*** 149,154 **** struct PGPROC
--- 152,158 ----
  
  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
***************
*** 177,182 **** typedef struct PGXACT
--- 181,209 ----
  	uint8		nxids;
  } PGXACT;
  
+ 
+ /* Structure to hold VXID FL for autonomous transaction*/
+ typedef struct AutoXactVXIDFP
+ {
+ 	LocalTransactionId fpAutoLxid;
+ 	bool			   fpAutoVXIDLock;
+ }AutoXactVXIDFP;
+ 
+ /* Structure like PGXACT but for autonomous transaction*/
+ 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 */
+ 	LocalTransactionId	lxid;	/* Local transaction id  for virtual tx*/
+ 	AutoXactVXIDFP	fpLocalAuto;	/* Auto local xid*/
+  } PGAutonomousXACT;
+ 
  /*
   * There is one ProcGlobal struct for the whole database cluster.
   */
***************
*** 186,191 **** typedef struct PROC_HDR
--- 213,222 ----
  	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 */
***************
*** 257,260 **** extern void LockErrorCleanup(void);
--- 288,293 ----
  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,32 ----
  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 */
--- 81,93 ----
  						  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 */
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 5108,5119 **** exec_eval_simple_expr(PLpgSQL_execstate *estate,
  					  Oid *rettype)
  {
  	ExprContext *econtext = estate->eval_econtext;
! 	LocalTransactionId curlxid = MyProc->lxid;
  	CachedPlan *cplan;
  	ParamListInfo paramLI;
  	PLpgSQL_expr *save_cur_expr;
  	MemoryContext oldcontext;
  
  	/*
  	 * Forget it if expression wasn't simple before.
  	 */
--- 5108,5127 ----
  					  Oid *rettype)
  {
  	ExprContext *econtext = estate->eval_econtext;
! 	LocalTransactionId curlxid;
  	CachedPlan *cplan;
  	ParamListInfo paramLI;
  	PLpgSQL_expr *save_cur_expr;
  	MemoryContext oldcontext;
  
+ 	if (MyProc->inAutoTXLevel)
+ 	{
+ 		PGAutonomousXACT *currentautotx = GetCurrentPGAutonomousXACT();
+ 		curlxid = currentautotx->lxid;
+ 	}
+ 	else
+ 		curlxid = MyProc->lxid;
+ 
  	/*
  	 * Forget it if expression wasn't simple before.
  	 */
#38Abhijit Menon-Sen
ams@2ndQuadrant.com
In reply to: Rajeev rastogi (#37)
Re: Autonomous Transaction (WIP)

If I understand correctly, the design of this patch has already been
considered earlier and rejected. So I guess the patch should also be
marked rejected?

-- Abhijit

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#39Pavel Stehule
pavel.stehule@gmail.com
In reply to: Abhijit Menon-Sen (#38)
Re: Autonomous Transaction (WIP)

2014-06-30 12:38 GMT+02:00 Abhijit Menon-Sen <ams@2ndquadrant.com>:

If I understand correctly, the design of this patch has already been
considered earlier and rejected. So I guess the patch should also be
marked rejected?

I didn't find a related message.

?

Regards

Pavel

Show quoted text

-- Abhijit

#40Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Pavel Stehule (#39)
Re: Autonomous Transaction (WIP)

On 30 June 2014 22:50, Pavel Stehule Wrote:
2014-06-30 12:38 GMT+02:00 Abhijit Menon-Sen <ams@2ndquadrant.com<mailto:ams@2ndquadrant.com>>:

If I understand correctly, the design of this patch has already been
considered earlier and rejected. So I guess the patch should also be
marked rejected?

I didn't find a related message.
?

I think there have been some confusion, the design idea were never rejected but yes there were few feedback/ concern, which I had clarified. Also some of the other concerns are already fixed in latest patch.
So I wanted to have this patch in commitfest application, so that we can have a healthy discussion and rectify all the issues.
But now I see that this patch has already been moved to rejected category, which will put break on further review.
So is there any way to bring back and continue reviewing this patch.
Please let me know if any issue or I am missing something.

Thanks and Regards,
Kumar Rajeev Rastogi

#41Pavel Stehule
pavel.stehule@gmail.com
In reply to: Rajeev rastogi (#40)
Re: Autonomous Transaction (WIP)

2014-07-01 8:16 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

On 30 June 2014 22:50, Pavel Stehule Wrote:

2014-06-30 12:38 GMT+02:00 Abhijit Menon-Sen <ams@2ndquadrant.com>:

If I understand correctly, the design of this patch has already been
considered earlier and rejected. So I guess the patch should also be
marked rejected?

I didn't find a related message.
?

I think there have been some confusion, the design idea were never
rejected but yes there were few feedback/ concern, which I had clarified.
Also some of the other concerns are already fixed in latest patch.

So I wanted to have this patch in commitfest application, so that we can
have a healthy discussion and rectify all the issues.

But now I see that this patch has already been moved to rejected category,
which will put break on further review.

So is there any way to bring back and continue reviewing this patch.

Please let me know if any issue or I am missing something.

I didn't watch a discuss about internal implementation, but now, when I am
testing this feature - it works well.

Surely - this feature has important but with relatively large impact and
should be extremely well tested. Now there are no any special test.
Probably we can reuse a tests for nested transactions.

I prefer this feature will be part of first commitfest due high complexity.

Regards

Pavel

Show quoted text

*Thanks and Regards,*

*Kumar Rajeev Rastogi*

#42Amit Kapila
amit.kapila16@gmail.com
In reply to: Rajeev rastogi (#40)
Re: Autonomous Transaction (WIP)

On Tue, Jul 1, 2014 at 11:46 AM, Rajeev rastogi <rajeev.rastogi@huawei.com>
wrote:

On 30 June 2014 22:50, Pavel Stehule Wrote:

I didn't find a related message.
?

I think there have been some confusion, the design idea were never

rejected but yes there were few feedback/ concern, which I had clarified.
Also some of the other concerns are already fixed in latest patch.

Simon has mentioned that exactly this idea has been rejected at
PGCon 2 years back. Please refer that in below mail:
/messages/by-id/BF2827DCCE55594C8D7A8F7FFD3AB7713DDE136A@SZXEML508-MBX.china.huawei.com

As far as I can see, you never came back with the different solution.

Have you checked the discussion in Developer meeting notes. Please
check the same at below link:
http://wiki.postgresql.org/wiki/PgCon_2012_Developer_Meeting#Autonomous_Transactions

So I wanted to have this patch in commitfest application, so that we can

have a healthy discussion and rectify all the issues.

But now I see that this patch has already been moved to rejected

category, which will put break on further review.

I believe ideally this patch should have been marked as
"Returned with feedback" as you already got a feedback long
back and never come up with solution for same.

With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#43Pavel Stehule
pavel.stehule@gmail.com
In reply to: Amit Kapila (#42)
Re: Autonomous Transaction (WIP)

2014-07-01 8:29 GMT+02:00 Amit Kapila <amit.kapila16@gmail.com>:

On Tue, Jul 1, 2014 at 11:46 AM, Rajeev rastogi <rajeev.rastogi@huawei.com>
wrote:

On 30 June 2014 22:50, Pavel Stehule Wrote:

I didn't find a related message.
?

I think there have been some confusion, the design idea were never

rejected but yes there were few feedback/ concern, which I had clarified.
Also some of the other concerns are already fixed in latest patch.

Simon has mentioned that exactly this idea has been rejected at
PGCon 2 years back. Please refer that in below mail:

/messages/by-id/BF2827DCCE55594C8D7A8F7FFD3AB7713DDE136A@SZXEML508-MBX.china.huawei.com

As far as I can see, you never came back with the different solution.

Have you checked the discussion in Developer meeting notes. Please
check the same at below link:

http://wiki.postgresql.org/wiki/PgCon_2012_Developer_Meeting#Autonomous_Transactions

Are these notes still valid?

* Why autonomous transaction should be close to functions? We can
implement AT as first step and next step can be implementation of
integration AT to stored procedures.

* When autonomous transaction is independent on parent transaction, then
locks parent and autonomous transaction should be in conflict

I though about integration to PL/pgSQL and I don't think so close
integration between autonomous transaction and procedure is optimal. More
practical is design so autonomous transaction is similar to subtransaction.

Then we can simply wrote some code like

BEGIN
.. some code
WHEN OTHERS THEN
.. I would to write permanently to log
BEGIN AUTONOMOUS
INSERT INTO log VALUES(..);
WHEN OTHERS
RAISE WARNING 'Cannot to write to log ..';
RAISE EXCEPTION ' ...' forward up exception from autonomous
transaction to parent transaction
END
END;

Now I am thinking so PL/SQL design of autonomous transactions is relatively
limited and is not best to follow it.

Regards

Pavel

Show quoted text

So I wanted to have this patch in commitfest application, so that we can

have a healthy discussion and rectify all the issues.

But now I see that this patch has already been moved to rejected

category, which will put break on further review.

I believe ideally this patch should have been marked as
"Returned with feedback" as you already got a feedback long
back and never come up with solution for same.

With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#44Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Pavel Stehule (#43)
Re: Autonomous Transaction (WIP)

On 01 July 2014 12:26, Pavel Stehule Wrote:

Have you checked the discussion in Developer meeting notes. Please
check the same at below link:
http://wiki.postgresql.org/wiki/PgCon_2012_Developer_Meeting#Autonomous_Transactions

Are these notes still valid?
* Why autonomous transaction should be close to functions? We can implement AT as first step and next step can be implementation of integration AT to stored procedures.

We have implemented AT on the line of sub-transaction. Also we have integrated AT with stored procedure i.e. we can create an autonomous transaction inside the store procedure, which can be also committed.

* When autonomous transaction is independent on parent transaction, then locks parent and autonomous transaction should be in conflict

Yes our implementation makes the autonomous transaction independent of main transaction and hence as per our design parent (main) transaction and autonomous may get conflicted. For which we have implemented deadlock detection mechanism between autonomous transaction and its parent transaction.

I though about integration to PL/pgSQL and I don't think so close integration between autonomous transaction and procedure is optimal. More practical is design so autonomous transaction is similar to subtransaction.

Yes as mentioned above, our implementation of autonomous transaction is on track of subtransaction.

Then we can simply wrote some code like
BEGIN
.. some code
WHEN OTHERS THEN
.. I would to write permanently to log
BEGIN AUTONOMOUS
INSERT INTO log VALUES(..);
WHEN OTHERS
RAISE WARNING 'Cannot to write to log ..';
RAISE EXCEPTION ' ...' forward up exception from autonomous transaction to parent transaction
END
END;
Now I am thinking so PL/SQL design of autonomous transactions is relatively limited and is not best to follow it.

With our approach, we can use autonomous transaction in procedure as given below:
BEGIN
.. some code
WHEN OTHERS THEN
.. I would to write permanently to log
START AUTONOMOUS TRANSACTION
INSERT INTO log VALUES(..);
COMMIT:
WHEN OTHERS
RAISE WARNING 'Cannot to write to log ..';
RAISE EXCEPTION ' ...' forward up exception from autonomous transaction to parent transaction
END
END;
Please let me know if I have missed to answer any of your queries.
Thanks and Regards,
Kumar Rajeev Rastogi

#45Pavel Stehule
pavel.stehule@gmail.com
In reply to: Rajeev rastogi (#44)
Re: Autonomous Transaction (WIP)

2014-07-01 10:38 GMT+02:00 Rajeev rastogi <rajeev.rastogi@huawei.com>:

On 01 July 2014 12:26, Pavel Stehule Wrote:

Have you checked the discussion in Developer meeting notes. Please

check the same at below link:

http://wiki.postgresql.org/wiki/PgCon_2012_Developer_Meeting#Autonomous_Transactions

Are these notes still valid?

* Why autonomous transaction should be close to functions? We can

implement AT as first step and next step can be implementation of
integration AT to stored procedures.

We have implemented AT on the line of sub-transaction. Also we have
integrated AT with stored procedure i.e. we can create an autonomous
transaction inside the store procedure, which can be also committed.

* When autonomous transaction is independent on parent transaction, then

locks parent and autonomous transaction should be in conflict

Yes our implementation makes the autonomous transaction independent of
main transaction and hence as per our design parent (main) transaction and
autonomous may get conflicted. For which we have implemented deadlock
detection mechanism between autonomous transaction and its parent
transaction.

I though about integration to PL/pgSQL and I don't think so close

integration between autonomous transaction and procedure is optimal. More
practical is design so autonomous transaction is similar to subtransaction.

Yes as mentioned above, our implementation of autonomous transaction is on
track of subtransaction.

ok

Then we can simply wrote some code like

BEGIN

.. some code

WHEN OTHERS THEN

.. I would to write permanently to log

BEGIN AUTONOMOUS

INSERT INTO log VALUES(..);

WHEN OTHERS

RAISE WARNING 'Cannot to write to log ..';

RAISE EXCEPTION ' ...' forward up exception from autonomous

transaction to parent transaction

END

END;

Now I am thinking so PL/SQL design of autonomous transactions is

relatively limited and is not best to follow it.

With our approach, we can use autonomous transaction in procedure as given
below:

BEGIN

.. some code

WHEN OTHERS THEN

.. I would to write permanently to log

*START AUTONOMOUS TRANSACTION*

INSERT INTO log VALUES(..);

*COMMIT: *

WHEN OTHERS

RAISE WARNING 'Cannot to write to log ..';

RAISE EXCEPTION ' ...' forward up exception from autonomous
transaction to parent transaction

END

END;

I don't like this design (really) - it can be used in later implementation
of procedures - but I don't like a explicit transaction manipulation in
functions. It is Oracleism (and this part I don't want to follow, because
Oracle design is not lucky) - and it is one reason, why Oracle SP are
significantly complex than PostgreSQL SP. After all I am thinking so
PostgreSQL relation between transactions and procedures are better, simply
for usage, simply for learning. But it is little bit different topic.

Regards

Pavel

Show quoted text

Please let me know if I have missed to answer any of your queries.

Thanks and Regards,

Kumar Rajeev Rastogi

#46Rajeev rastogi
rajeev.rastogi@huawei.com
In reply to: Amit Kapila (#42)
Re: Autonomous Transaction (WIP)

On 01 July 2014 12:00, Amit Kapila Wrote:

On Tue, Jul 1, 2014 at 11:46 AM, Rajeev rastogi <rajeev.rastogi@huawei.com<mailto:rajeev.rastogi@huawei.com>> wrote:

On 30 June 2014 22:50, Pavel Stehule Wrote:

I didn't find a related message.
?

I think there have been some confusion, the design idea were never rejected but yes there were few feedback/ concern, which I had clarified. Also some of the other concerns are already fixed in latest patch.

Simon has mentioned that exactly this idea has been rejected at
PGCon 2 years back. Please refer that in below mail:
/messages/by-id/BF2827DCCE55594C8D7A8F7FFD3AB7713DDE136A@SZXEML508-MBX.china.huawei.com

As far as I can see, you never came back with the different solution.

Yeah right. So for this I tried to search archived mails to get the details about the discussion but I could not find anything regarding design.
So I am not sure how shall I make my solution different from earlier as earlier solution is not accessible to me. Any help regarding this will be really great help to me.

Also from the current Autonomous transaction discussion thread (including CA+U5nMKEUm4abRQBndLYt5LEdekTAe8rbiYW3977YHMeOWQ1kA@mail.gmail.com</messages/by-id/CA+U5nMKEUm4abRQBndLYt5LEdekTAe8rbiYW3977YHMeOWQ1kA@mail.gmail.com&gt;),
I have summarized all important feedbacks as mentioned below along with the resolution suggested:

1. Pavel Stehule (07-04-2014): -1 for Oracle syntax - it is hardly inconsistent with Postgres

Changed the syntax to “START AUTONOMOUS TRANSACTION”

2. Pavan (10-04-2014): Making autonomous transaction properties independent of main transaction.
Made all properties of autonomous transaction (including read-only) independent from main transaction except isolation level, which I did not find very useful to keep different. But others opinion is different then we can make this property also independent.

3. Alvaro Herrarta (09-04-2014): Autonomous transaction to have their own separate proc entry.
This was concluded to not have separate proc entry for autonomous transaction and same concluded.

4. Tom Lane (09-04-2014): The point being that you need to change both pg_subtrans and pg_clog to make that state transition.
This is handled for autonomous transaction.

5. Robert Haas (09-04-2014): Not in favour of current design related to "maintaining lockmask for autonomous transaction".

I had replied for this mail regarding why this design is kept but still if design for this part is not acceptable, then I can rework to make it better. In order to do so I would be very happy to have more discussion to get concrete feedback and direction to improve this.

6. Tom Lane (09-04-2014): no justification for distinguishing normal and autonomous transactions at this level (locking level).
I had replied this also earlier. Reason for distinguishing at this level is to handle any kind of deadlock possibility between main and autonomous transaction. Deadlock handling between main and autonomous transaction was one of the requirement discussed at PGCon 2012 as part of autonomous transaction discussion. Please let me know if I am missing something in this.

All of the above mentioned changes are included in latest patch shared.
Please let me know if I have missed any other important points from the earlier discussion, I would like to address that also.

Have you checked the discussion in Developer meeting notes. Please
check the same at below link:
http://wiki.postgresql.org/wiki/PgCon_2012_Developer_Meeting#Autonomous_Transactions

From the discussion, I am able to make out two important points:

1. Main transaction and autonomous transaction should be independent and can conflict.

This is already included in our latest patch.

2. Utility commands like VACUUM and CREATE INDEX CONCURRENTLY should be able to work from autonomous transaction.

Both of the above mentioned utility commands are not supported even inside the main transaction. So it is not working within autonomous transaction.

Any opinion about this?
Please let me know if I have missed any points from the link given.

So I wanted to have this patch in commitfest application, so that we can have a healthy discussion and rectify all the issues.
But now I see that this patch has already been moved to rejected category, which will put break on further review.

I believe ideally this patch should have been marked as
"Returned with feedback" as you already got a feedback long
back and never come up with solution for same.

Since this patch is very big and complex, it is better we continue discussing from the first CommitFest itself so that we can get ample time to share everyone’s opinion and then address all possible issue.

Any Opinions/Suggestions are welcome. Also let me know if I have missed something.

Thanks and Regards,
Kumar Rajeev Rastogi

#47Amit Kapila
amit.kapila16@gmail.com
In reply to: Rajeev rastogi (#46)
Re: Autonomous Transaction (WIP)

On Thu, Jul 3, 2014 at 12:03 PM, Rajeev rastogi <rajeev.rastogi@huawei.com>
wrote:

On 01 July 2014 12:00, Amit Kapila Wrote:

Simon has mentioned that exactly this idea has been rejected at

PGCon 2 years back. Please refer that in below mail:

/messages/by-id/BF2827DCCE55594C8D7A8F7FFD3AB7713DDE136A@SZXEML508-MBX.china.huawei.com

As far as I can see, you never came back with the different solution.

Yeah right. So for this I tried to search archived mails to get the

details about the discussion but I could not find anything regarding design.

So I am not sure how shall I make my solution different from earlier as

earlier solution is not accessible to me.

I haven't read your idea/patch in any detail, so can't comment
on whether it is good or bad. However I think if one of the
Committers has already mentioned that the same idea has been
rejected previously, then it makes little sense to further review
or update the patch unless you know the reason of rejection and
handle it in an acceptable way.

Now as far as I can understand, the problem seems to be in a way
you have defined Autonomous Transaction Storage which can lead
to consumption of additional client slots, this is just what I could make
sense from above mail but I am not completely sure on this matter.

With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com