diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 49283ed81eecacd35c1c0b97fd20039d15c252d6..4eefbb91abef79f9b4de90511f44c334c28a7f4e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.164 2004/02/11 22:55:24 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.165 2004/04/05 03:11:39 momjian Exp $
  *
  * NOTES
  *		Transaction aborts can now occur two ways:
@@ -239,36 +239,6 @@ static void *_RollbackData = NULL;
  * ----------------------------------------------------------------
  */
 
-#ifdef NOT_USED
-
-/* --------------------------------
- *	TransactionFlushEnabled()
- *	SetTransactionFlushEnabled()
- *
- *	These are used to test and set the "TransactionFlushState"
- *	variable.  If this variable is true (the default), then
- *	the system will flush all dirty buffers to disk at the end
- *	of each transaction.   If false then we are assuming the
- *	buffer pool resides in stable main memory, in which case we
- *	only do writes as necessary.
- * --------------------------------
- */
-static int	TransactionFlushState = 1;
-
-int
-TransactionFlushEnabled(void)
-{
-	return TransactionFlushState;
-}
-
-void
-SetTransactionFlushEnabled(bool state)
-{
-	TransactionFlushState = (state == true);
-}
-#endif
-
-
 /*
  *	IsTransactionState
  *
@@ -1171,6 +1141,15 @@ StartTransactionCommand(void)
 			 */
 		case TBLOCK_DEFAULT:
 			StartTransaction();
+			s->blockState = TBLOCK_STARTED;
+			break;
+
+			/*
+			 * We should never experience this -- it means the STARTED state
+			 * was not changed in the previous CommitTransactionCommand.
+			 */
+		case TBLOCK_STARTED:
+			elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_STARTED");
 			break;
 
 			/*
@@ -1202,9 +1181,9 @@ StartTransactionCommand(void)
 			 */
 		case TBLOCK_END:
 			elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
-			s->blockState = TBLOCK_DEFAULT;
 			CommitTransaction();
 			StartTransaction();
+			s->blockState = TBLOCK_DEFAULT;
 			break;
 
 			/*
@@ -1246,12 +1225,22 @@ CommitTransactionCommand(void)
 
 	switch (s->blockState)
 	{
+			/*
+			 * This shouldn't happen, because it means the previous
+			 * StartTransactionCommand didn't set the STARTED state
+			 * appropiately.
+			 */
+		case TBLOCK_DEFAULT:
+			elog(WARNING, "CommitTransactionCommand: unexpected TBLOCK_DEFAULT");
+			break;
+
 			/*
 			 * If we aren't in a transaction block, just do our usual
 			 * transaction commit.
 			 */
-		case TBLOCK_DEFAULT:
+		case TBLOCK_STARTED:
 			CommitTransaction();
+			s->blockState = TBLOCK_DEFAULT;
 			break;
 
 			/*
@@ -1314,13 +1303,20 @@ AbortCurrentTransaction(void)
 
 	switch (s->blockState)
 	{
+		/*
+		 * we aren't in a transaction, so we do nothing.
+		 */
+		case TBLOCK_DEFAULT:
+			break;
+
 			/*
 			 * if we aren't in a transaction block, we just do the basic
 			 * abort & cleanup transaction.
 			 */
-		case TBLOCK_DEFAULT:
+		case TBLOCK_STARTED:
 			AbortTransaction();
 			CleanupTransaction();
+			s->blockState = TBLOCK_DEFAULT;
 			break;
 
 			/*
@@ -1330,9 +1326,9 @@ AbortCurrentTransaction(void)
 			 * things.
 			 */
 		case TBLOCK_BEGIN:
-			s->blockState = TBLOCK_ABORT;
 			AbortTransaction();
-			/* CleanupTransaction happens when we exit TBLOCK_ABORT */
+			s->blockState = TBLOCK_ABORT;
+			/* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
 			break;
 
 			/*
@@ -1342,9 +1338,9 @@ AbortCurrentTransaction(void)
 			 * restore us to a normal state.
 			 */
 		case TBLOCK_INPROGRESS:
-			s->blockState = TBLOCK_ABORT;
 			AbortTransaction();
-			/* CleanupTransaction happens when we exit TBLOCK_ABORT */
+			s->blockState = TBLOCK_ABORT;
+			/* CleanupTransaction happens when we exit TBLOCK_ENDABORT */
 			break;
 
 			/*
@@ -1353,9 +1349,9 @@ AbortCurrentTransaction(void)
 			 * and put us back into the default state.
 			 */
 		case TBLOCK_END:
-			s->blockState = TBLOCK_DEFAULT;
 			AbortTransaction();
 			CleanupTransaction();
+			s->blockState = TBLOCK_DEFAULT;
 			break;
 
 			/*
@@ -1420,7 +1416,8 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
 		/* translator: %s represents an SQL statement name */
 			 errmsg("%s cannot be executed from a function", stmtType)));
 	/* If we got past IsTransactionBlock test, should be in default state */
-	if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
+	if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
+			CurrentTransactionState->blockState != TBLOCK_STARTED)
 		elog(ERROR, "cannot prevent transaction chain");
 	/* all okay */
 }
@@ -1534,28 +1531,37 @@ BeginTransactionBlock(void)
 {
 	TransactionState s = CurrentTransactionState;
 
-	/*
-	 * check the current transaction state
-	 */
-	if (s->blockState != TBLOCK_DEFAULT)
-		ereport(WARNING,
-				(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
-				 errmsg("there is already a transaction in progress")));
+	switch (s->blockState) {
+			/*
+			 * We are inside a transaction, so allow a transaction block
+			 * to begin.
+			 */
+		case TBLOCK_STARTED:
+			s->blockState = TBLOCK_BEGIN;
+			break;
 
-	/*
-	 * set the current transaction block state information appropriately
-	 * during begin processing
-	 */
-	s->blockState = TBLOCK_BEGIN;
+			/* Already a transaction block in progress. */
+		case TBLOCK_INPROGRESS:
+			ereport(WARNING,
+					(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
+					 errmsg("there is already a transaction in progress")));
 
-	/*
-	 * do begin processing here.  Nothing to do at present.
-	 */
+			/*
+			 * This shouldn't happen, because a transaction in aborted state
+			 * will not be allowed to call BeginTransactionBlock.
+			 */
+		case TBLOCK_ABORT:
+			elog(WARNING, "BeginTransactionBlock: unexpected TBLOCK_ABORT");
+			break;
 
-	/*
-	 * done with begin processing, set block state to inprogress
-	 */
-	s->blockState = TBLOCK_INPROGRESS;
+			/* These cases are invalid.  Reject them altogether. */
+		case TBLOCK_DEFAULT:
+		case TBLOCK_BEGIN:
+		case TBLOCK_ENDABORT:
+		case TBLOCK_END:
+			elog(FATAL, "BeginTransactionBlock: not in a user-allowed state!");
+			break;
+	}
 }
 
 /*
@@ -1566,85 +1572,51 @@ EndTransactionBlock(void)
 {
 	TransactionState s = CurrentTransactionState;
 
-	/*
-	 * check the current transaction state
-	 */
-	if (s->blockState == TBLOCK_INPROGRESS)
-	{
+	switch (s->blockState) {
 		/*
 		 * here we are in a transaction block which should commit when we
 		 * get to the upcoming CommitTransactionCommand() so we set the
 		 * state to "END".	CommitTransactionCommand() will recognize this
 		 * and commit the transaction and return us to the default state
 		 */
-		s->blockState = TBLOCK_END;
-		return;
-	}
-
-	if (s->blockState == TBLOCK_ABORT)
-	{
-		/*
-		 * here, we are in a transaction block which aborted and since the
-		 * AbortTransaction() was already done, we do whatever is needed
-		 * and change to the special "END ABORT" state.  The upcoming
-		 * CommitTransactionCommand() will recognise this and then put us
-		 * back in the default state.
-		 */
-		s->blockState = TBLOCK_ENDABORT;
-		return;
-	}
+		case TBLOCK_INPROGRESS:
+			s->blockState = TBLOCK_END;
+			break;
 
-	/*
-	 * here, the user issued COMMIT when not inside a transaction. Issue a
-	 * WARNING and go to abort state.  The upcoming call to
-	 * CommitTransactionCommand() will then put us back into the default
-	 * state.
-	 */
-	ereport(WARNING,
-			(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
-			 errmsg("there is no transaction in progress")));
-	AbortTransaction();
-	s->blockState = TBLOCK_ENDABORT;
-}
+			/*
+			 * here, we are in a transaction block which aborted and since the
+			 * AbortTransaction() was already done, we do whatever is needed
+			 * and change to the special "END ABORT" state.  The upcoming
+			 * CommitTransactionCommand() will recognise this and then put us
+			 * back in the default state.
+			 */
+		case TBLOCK_ABORT:
+			s->blockState = TBLOCK_ENDABORT;
+			break;
 
-/*
- *	AbortTransactionBlock
- */
-#ifdef NOT_USED
-static void
-AbortTransactionBlock(void)
-{
-	TransactionState s = CurrentTransactionState;
+		case TBLOCK_STARTED:
+			/*
+			 * here, the user issued COMMIT when not inside a transaction. Issue a
+			 * WARNING and go to abort state.  The upcoming call to
+			 * CommitTransactionCommand() will then put us back into the default
+			 * state.
+			 */
+			ereport(WARNING,
+					(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
+					 errmsg("there is no transaction in progress")));
+			AbortTransaction();
+			s->blockState = TBLOCK_ENDABORT;
+			break;
 
-	/*
-	 * check the current transaction state
-	 */
-	if (s->blockState == TBLOCK_INPROGRESS)
-	{
-		/*
-		 * here we were inside a transaction block something screwed up
-		 * inside the system so we enter the abort state, do the abort
-		 * processing and then return. We remain in the abort state until
-		 * we see an END TRANSACTION command.
-		 */
-		s->blockState = TBLOCK_ABORT;
-		AbortTransaction();
-		return;
+			/* These cases are invalid.  Reject them altogether. */
+		case TBLOCK_DEFAULT:
+		case TBLOCK_BEGIN:
+		case TBLOCK_ENDABORT:
+		case TBLOCK_END:
+			elog(FATAL, "EndTransactionBlock and not in a user-allowed state");
+			break;
 	}
-
-	/*
-	 * here, the user issued ABORT when not inside a transaction. Issue a
-	 * WARNING and go to abort state.  The upcoming call to
-	 * CommitTransactionCommand() will then put us back into the default
-	 * state.
-	 */
-	ereport(WARNING,
-			(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
-			 errmsg("there is no transaction in progress")));
-	AbortTransaction();
-	s->blockState = TBLOCK_ENDABORT;
 }
-#endif
 
 /*
  *	UserAbortTransactionBlock
@@ -1669,10 +1641,9 @@ UserAbortTransactionBlock(void)
 	{
 		/*
 		 * here we were inside a transaction block and we got an abort
-		 * command from the user, so we move to the abort state, do the
-		 * abort processing and then change to the ENDABORT state so we
-		 * will end up in the default state after the upcoming
-		 * CommitTransactionCommand().
+		 * command from the user, so we move to the ENDABORT state and
+		 * do abort processing so we will end up in the default state
+		 * after the upcoming CommitTransactionCommand().
 		 */
 		s->blockState = TBLOCK_ABORT;
 		AbortTransaction();
@@ -1706,28 +1677,30 @@ AbortOutOfAnyTransaction(void)
 	TransactionState s = CurrentTransactionState;
 
 	/*
-	 * Get out of any low-level transaction
+	 * Get out of any transaction
 	 */
-	switch (s->state)
+	switch (s->blockState)
 	{
-		case TRANS_START:
-		case TRANS_INPROGRESS:
-		case TRANS_COMMIT:
+		case TBLOCK_DEFAULT:
+			/* Not in a transaction, do nothing */
+			break;
+		case TBLOCK_STARTED:
+		case TBLOCK_BEGIN:
+		case TBLOCK_INPROGRESS:
+		case TBLOCK_END:
 			/* In a transaction, so clean up */
 			AbortTransaction();
 			CleanupTransaction();
 			break;
-		case TRANS_ABORT:
+		case TBLOCK_ABORT:
+		case TBLOCK_ENDABORT:
 			/* AbortTransaction already done, still need Cleanup */
 			CleanupTransaction();
 			break;
-		case TRANS_DEFAULT:
-			/* Not in a transaction, do nothing */
-			break;
 	}
 
 	/*
-	 * Now reset the high-level state
+	 * Now reset the transaction state
 	 */
 	s->blockState = TBLOCK_DEFAULT;
 }
@@ -1740,7 +1713,7 @@ IsTransactionBlock(void)
 {
 	TransactionState s = CurrentTransactionState;
 
-	if (s->blockState == TBLOCK_DEFAULT)
+	if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
 		return false;
 
 	return true;
@@ -1758,7 +1731,7 @@ IsTransactionOrTransactionBlock(void)
 {
 	TransactionState s = CurrentTransactionState;
 
-	if (s->blockState == TBLOCK_DEFAULT && s->state == TRANS_DEFAULT)
+	if (s->blockState == TBLOCK_DEFAULT)
 		return false;
 
 	return true;
@@ -1775,6 +1748,7 @@ TransactionBlockStatusCode(void)
 	switch (s->blockState)
 	{
 		case TBLOCK_DEFAULT:
+		case TBLOCK_STARTED:
 			return 'I';			/* idle --- not in transaction */
 		case TBLOCK_BEGIN:
 		case TBLOCK_INPROGRESS:
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 95de83dc461c1da6c3e3fad76d00f997dbe86fa3..3eb334b30e37795ae307640e88879b4ed4adee76 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.61 2004/02/11 22:55:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.62 2004/04/05 03:11:39 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,6 +58,7 @@ typedef enum TransState
 typedef enum TBlockState
 {
 	TBLOCK_DEFAULT,
+	TBLOCK_STARTED,
 	TBLOCK_BEGIN,
 	TBLOCK_INPROGRESS,
 	TBLOCK_END,