88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.169 2004/07/0100:49:42 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.170 2004/07/0120:11:02 tgl Exp $
1212 *
1313 * NOTES
1414 *Transaction aborts can now occur two ways:
@@ -196,6 +196,7 @@ static void StartSubTransaction(void);
196196static void CommitSubTransaction (void );
197197static void AbortSubTransaction (void );
198198static void CleanupSubTransaction (void );
199+ static void StartAbortedSubTransaction (void );
199200static void PushTransaction (void );
200201static void PopTransaction (void );
201202
@@ -317,7 +318,7 @@ IsAbortedTransactionBlockState(void)
317318TransactionState s = CurrentTransactionState ;
318319
319320if (s -> blockState == TBLOCK_ABORT ||
320- s -> blockState == TBLOCK_SUBABORT )
321+ s -> blockState == TBLOCK_SUBABORT )
321322return true;
322323
323324return false;
@@ -1579,10 +1580,9 @@ StartTransactionCommand(void)
15791580break ;
15801581
15811582/*
1582- * This is the case when are somewhere in a transaction block
1583+ * This is the case whenwe are somewhere in a transaction block
15831584 * and about to start a new command. For now we do nothing
1584- * but someday we may do command-local resource
1585- * initialization.
1585+ * but someday we may do command-local resource initialization.
15861586 */
15871587case TBLOCK_INPROGRESS :
15881588case TBLOCK_SUBINPROGRESS :
@@ -1699,7 +1699,9 @@ CommitTransactionCommand(void)
16991699
17001700/*
17011701 * We were just issued a BEGIN inside a transaction block.
1702- * Start a subtransaction.
1702+ * Start a subtransaction. (BeginTransactionBlock already
1703+ * did PushTransaction, so as to have someplace to put the
1704+ * SUBBEGIN state.)
17031705 */
17041706case TBLOCK_SUBBEGIN :
17051707StartSubTransaction ();
@@ -1711,8 +1713,7 @@ CommitTransactionCommand(void)
17111713 * Start a subtransaction, and put it in aborted state.
17121714 */
17131715case TBLOCK_SUBBEGINABORT :
1714- StartSubTransaction ();
1715- AbortSubTransaction ();
1716+ StartAbortedSubTransaction ();
17161717s -> blockState = TBLOCK_SUBABORT ;
17171718break ;
17181719
@@ -1724,7 +1725,7 @@ CommitTransactionCommand(void)
17241725break ;
17251726
17261727/*
1727- * Wewhere issued a COMMIT command, so we end the current
1728+ * Wewere issued a COMMIT command, so we end the current
17281729 * subtransaction and return to the parent transaction.
17291730 */
17301731case TBLOCK_SUBEND :
@@ -1740,7 +1741,7 @@ CommitTransactionCommand(void)
17401741break ;
17411742
17421743/*
1743- * We are endinga subtransactionthat aborted nicely ,
1744+ * We are endingan aborted subtransactionvia ROLLBACK ,
17441745 * so the parent can be allowed to live.
17451746 */
17461747case TBLOCK_SUBENDABORT_OK :
@@ -1750,9 +1751,8 @@ CommitTransactionCommand(void)
17501751break ;
17511752
17521753/*
1753- * We are ending a subtransaction that aborted in a unclean
1754- * way (e.g. the user issued COMMIT in an aborted subtrasaction.)
1755- * Abort the subtransaction, and abort the parent too.
1754+ * We are ending an aborted subtransaction via COMMIT.
1755+ * End the subtransaction, and abort the parent too.
17561756 */
17571757case TBLOCK_SUBENDABORT_ERROR :
17581758CleanupSubTransaction ();
@@ -1791,7 +1791,7 @@ AbortCurrentTransaction(void)
17911791break ;
17921792
17931793/*
1794- * If we are inthe TBLOCK_BEGIN it means something screwed up
1794+ * If we are in TBLOCK_BEGIN it means something screwed up
17951795 * right after reading "BEGIN TRANSACTION" so we enter the
17961796 * abort state. Eventually an "END TRANSACTION" will fix
17971797 * things.
@@ -1803,10 +1803,10 @@ AbortCurrentTransaction(void)
18031803break ;
18041804
18051805/*
1806- * This is the case when are somewhere in a transaction block
1807- *which aborted so we abort the transaction and set the ABORT
1808- *state. Eventually an "END TRANSACTION" willfix things and
1809- *restore us to a normal state .
1806+ * This is the case whenwe are somewhere in a transaction block
1807+ *and we've gotten a failure, so we abort the transaction and
1808+ *set up the persistent ABORT state. We willstay in ABORT
1809+ *until we get an "END TRANSACTION" .
18101810 */
18111811case TBLOCK_INPROGRESS :
18121812AbortTransaction ();
@@ -1817,7 +1817,7 @@ AbortCurrentTransaction(void)
18171817/*
18181818 * Here, the system was fouled up just after the user wanted
18191819 * to end the transaction block so we abort the transaction
1820- * andput us back into the default state.
1820+ * andreturn to the default state.
18211821 */
18221822case TBLOCK_END :
18231823AbortTransaction ();
@@ -1852,10 +1852,7 @@ AbortCurrentTransaction(void)
18521852 */
18531853case TBLOCK_SUBBEGIN :
18541854case TBLOCK_SUBBEGINABORT :
1855- PushTransaction ();
1856- s = CurrentTransactionState ;/* changed by push */
1857- StartSubTransaction ();
1858- AbortSubTransaction ();
1855+ StartAbortedSubTransaction ();
18591856s -> blockState = TBLOCK_SUBABORT ;
18601857break ;
18611858
@@ -2092,8 +2089,10 @@ CallEOXactCallbacks(bool isCommit)
20922089 * transaction block support
20932090 * ----------------------------------------------------------------
20942091 */
2092+
20952093/*
20962094 *BeginTransactionBlock
2095+ *This executes a BEGIN command.
20972096 */
20982097void
20992098BeginTransactionBlock (void )
@@ -2102,7 +2101,7 @@ BeginTransactionBlock(void)
21022101
21032102switch (s -> blockState ) {
21042103/*
2105- * We are inside a transaction, so allowa transaction block
2104+ * We arenot inside a transaction block , so allowone
21062105 * to begin.
21072106 */
21082107case TBLOCK_STARTED :
@@ -2149,6 +2148,7 @@ BeginTransactionBlock(void)
21492148
21502149/*
21512150 *EndTransactionBlock
2151+ *This executes a COMMIT command.
21522152 */
21532153void
21542154EndTransactionBlock (void )
@@ -2176,9 +2176,9 @@ EndTransactionBlock(void)
21762176break ;
21772177
21782178/*
2179- * here, we are in a transaction block which aborted and since the
2180- * AbortTransaction() was already done, wedo whatever is needed
2181- *and change to the special "END ABORT" state. The upcoming
2179+ * here, we are in a transaction block which aborted. Since the
2180+ * AbortTransaction() was already done, weneed only
2181+ * change to the special "END ABORT" state. The upcoming
21822182 * CommitTransactionCommand() will recognise this and then put us
21832183 * back in the default state.
21842184 */
@@ -2189,7 +2189,8 @@ EndTransactionBlock(void)
21892189/*
21902190 * here we are in an aborted subtransaction. Signal
21912191 * CommitTransactionCommand() to clean up and return to the
2192- * parent transaction.
2192+ * parent transaction. Since the user said COMMIT, we must
2193+ * fail the parent transaction.
21932194 */
21942195case TBLOCK_SUBABORT :
21952196s -> blockState = TBLOCK_SUBENDABORT_ERROR ;
@@ -2209,7 +2210,7 @@ EndTransactionBlock(void)
22092210s -> blockState = TBLOCK_ENDABORT ;
22102211break ;
22112212
2212- /*These cases are invalid. Reject them altogether . */
2213+ /*these cases are invalid. */
22132214case TBLOCK_DEFAULT :
22142215case TBLOCK_BEGIN :
22152216case TBLOCK_ENDABORT :
@@ -2227,6 +2228,7 @@ EndTransactionBlock(void)
22272228
22282229/*
22292230 *UserAbortTransactionBlock
2231+ *This executes a ROLLBACK command.
22302232 */
22312233void
22322234UserAbortTransactionBlock (void )
@@ -2244,7 +2246,10 @@ UserAbortTransactionBlock(void)
22442246s -> blockState = TBLOCK_ENDABORT ;
22452247break ;
22462248
2247- /* Ditto, for a subtransaction. */
2249+ /*
2250+ * Ditto, for a subtransaction. Here it is okay to allow the
2251+ * parent transaction to continue.
2252+ */
22482253case TBLOCK_SUBABORT :
22492254s -> blockState = TBLOCK_SUBENDABORT_OK ;
22502255break ;
@@ -2336,8 +2341,8 @@ AbortOutOfAnyTransaction(void)
23362341case TBLOCK_SUBBEGIN :
23372342case TBLOCK_SUBBEGINABORT :
23382343/*
2339- *Just starting a new transaction -- return to parent.
2340- *FIXME -- Is this correct?
2344+ *We didn't get as far as starting the subxact, so there's
2345+ *nothing to abort. Just pop back to parent.
23412346 */
23422347PopTransaction ();
23432348s = CurrentTransactionState ;/* changed by pop */
@@ -2353,6 +2358,7 @@ AbortOutOfAnyTransaction(void)
23532358case TBLOCK_SUBABORT :
23542359case TBLOCK_SUBENDABORT_OK :
23552360case TBLOCK_SUBENDABORT_ERROR :
2361+ /* As above, but AbortSubTransaction already done */
23562362CleanupSubTransaction ();
23572363PopTransaction ();
23582364s = CurrentTransactionState ;/* changed by pop */
@@ -2521,6 +2527,8 @@ CommitSubTransaction(void)
25212527AtSubCommit_Portals (s -> parent -> transactionIdData );
25222528DeferredTriggerEndSubXact (true);
25232529
2530+ s -> state = TRANS_COMMIT ;
2531+
25242532/* Mark subtransaction as subcommitted */
25252533CommandCounterIncrement ();
25262534RecordSubTransactionCommit ();
@@ -2642,6 +2650,49 @@ CleanupSubTransaction(void)
26422650s -> state = TRANS_DEFAULT ;
26432651}
26442652
2653+ /*
2654+ * StartAbortedSubTransaction
2655+ *
2656+ * This function is used to start a subtransaction and put it immediately
2657+ * into aborted state. The end result should be equivalent to
2658+ * StartSubTransaction immediately followed by AbortSubTransaction.
2659+ * The reason we don't implement it just that way is that many of the backend
2660+ * modules aren't designed to handle starting a subtransaction when not
2661+ * inside a valid transaction. Rather than making them all capable of
2662+ * doing that, we just omit the paired start and abort calls in this path.
2663+ */
2664+ static void
2665+ StartAbortedSubTransaction (void )
2666+ {
2667+ TransactionState s = CurrentTransactionState ;
2668+
2669+ if (s -> state != TRANS_DEFAULT )
2670+ elog (WARNING ,"StartAbortedSubTransaction and not in default state" );
2671+
2672+ s -> state = TRANS_START ;
2673+
2674+ /*
2675+ * We don't bother to generate a new Xid, so the end state is not
2676+ * *exactly* like we had done a full Start/AbortSubTransaction...
2677+ */
2678+ s -> transactionIdData = InvalidTransactionId ;
2679+
2680+ /* Make sure currentUser is reasonably valid */
2681+ Assert (s -> parent != NULL );
2682+ s -> currentUser = s -> parent -> currentUser ;
2683+
2684+ /*
2685+ * Initialize only what has to be there for CleanupSubTransaction to work.
2686+ */
2687+ AtSubStart_Memory ();
2688+
2689+ s -> state = TRANS_ABORT ;
2690+
2691+ AtSubAbort_Memory ();
2692+
2693+ ShowTransactionState ("StartAbortedSubTransaction" );
2694+ }
2695+
26452696/*
26462697 * PushTransaction
26472698 *Set up transaction state for a subtransaction
@@ -2672,6 +2723,7 @@ PushTransaction(void)
26722723 */
26732724s -> transactionIdData = p -> transactionIdData ;
26742725s -> curTransactionContext = p -> curTransactionContext ;
2726+ s -> currentUser = p -> currentUser ;
26752727
26762728CurrentTransactionState = s ;
26772729}