88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.173 2004/07/28 14:23:27 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.174 2004/07/31 07:39:18 tgl Exp $
1212 *
1313 * NOTES
1414 * Transaction aborts can now occur two ways:
@@ -1589,7 +1589,8 @@ CleanupTransaction(void)
15891589 * State should still be TRANS_ABORT from AbortTransaction().
15901590 */
15911591 if (s -> state != TRANS_ABORT )
1592- elog (FATAL , "CleanupTransaction and not in abort state" );
1592+ elog (FATAL , "CleanupTransaction: unexpected state %s" ,
1593+ TransStateAsString (s -> state ));
15931594
15941595 /*
15951596 * do abort cleanup processing
@@ -1773,7 +1774,7 @@ CommitTransactionCommand(void)
17731774
17741775 /*
17751776 * We were just issued a SAVEPOINT inside a transaction block.
1776- * Start a subtransaction. (BeginTransactionBlock already
1777+ * Start a subtransaction. (DefineSavepoint already
17771778 * did PushTransaction, so as to have someplace to put the
17781779 * SUBBEGIN state.)
17791780 */
@@ -1853,6 +1854,7 @@ CleanupAbortedSubTransactions(bool returnName)
18531854 AssertState (PointerIsValid (s -> parent ));
18541855 Assert (s -> parent -> blockState == TBLOCK_SUBINPROGRESS ||
18551856 s -> parent -> blockState == TBLOCK_INPROGRESS ||
1857+ s -> parent -> blockState == TBLOCK_STARTED ||
18561858 s -> parent -> blockState == TBLOCK_SUBABORT_PENDING );
18571859
18581860 /*
@@ -1878,7 +1880,8 @@ CleanupAbortedSubTransactions(bool returnName)
18781880 }
18791881
18801882 AssertState (s -> blockState == TBLOCK_SUBINPROGRESS ||
1881- s -> blockState == TBLOCK_INPROGRESS );
1883+ s -> blockState == TBLOCK_INPROGRESS ||
1884+ s -> blockState == TBLOCK_STARTED );
18821885
18831886 return name ;
18841887}
@@ -2468,7 +2471,7 @@ DefineSavepoint(char *name)
24682471 case TBLOCK_SUBABORT_PENDING :
24692472 case TBLOCK_SUBENDABORT_RELEASE :
24702473 case TBLOCK_SUBEND :
2471- elog (FATAL , "BeginTransactionBlock : unexpected state %s" ,
2474+ elog (FATAL , "DefineSavepoint : unexpected state %s" ,
24722475 BlockStateAsString (s -> blockState ));
24732476 break ;
24742477 }
@@ -2657,20 +2660,126 @@ RollbackToSavepoint(List *options)
26572660}
26582661
26592662/*
2660- * RollbackAndReleaseSavepoint
2663+ * BeginInternalSubTransaction
2664+ * This is the same as DefineSavepoint except it allows TBLOCK_STARTED
2665+ * state, and therefore it can safely be used in a function that might
2666+ * be called when not inside a BEGIN block. Also, we automatically
2667+ * cycle through CommitTransactionCommand/StartTransactionCommand
2668+ * instead of expecting the caller to do it.
2669+ *
2670+ * Optionally, name can be NULL to create an unnamed savepoint.
2671+ */
2672+ void
2673+ BeginInternalSubTransaction (char * name )
2674+ {
2675+ TransactionState s = CurrentTransactionState ;
2676+
2677+ switch (s -> blockState )
2678+ {
2679+ case TBLOCK_STARTED :
2680+ case TBLOCK_INPROGRESS :
2681+ case TBLOCK_SUBINPROGRESS :
2682+ /* Normal subtransaction start */
2683+ PushTransaction ();
2684+ s = CurrentTransactionState ; /* changed by push */
2685+ /*
2686+ * Note that we are allocating the savepoint name in the
2687+ * parent transaction's CurTransactionContext, since we
2688+ * don't yet have a transaction context for the new guy.
2689+ */
2690+ if (name )
2691+ s -> name = MemoryContextStrdup (CurTransactionContext , name );
2692+ s -> blockState = TBLOCK_SUBBEGIN ;
2693+ break ;
2694+
2695+ /* These cases are invalid. Reject them altogether. */
2696+ case TBLOCK_DEFAULT :
2697+ case TBLOCK_BEGIN :
2698+ case TBLOCK_SUBBEGIN :
2699+ case TBLOCK_ABORT :
2700+ case TBLOCK_SUBABORT :
2701+ case TBLOCK_ENDABORT :
2702+ case TBLOCK_END :
2703+ case TBLOCK_SUBENDABORT_ALL :
2704+ case TBLOCK_SUBENDABORT :
2705+ case TBLOCK_SUBABORT_PENDING :
2706+ case TBLOCK_SUBENDABORT_RELEASE :
2707+ case TBLOCK_SUBEND :
2708+ elog (FATAL , "BeginInternalSubTransaction: unexpected state %s" ,
2709+ BlockStateAsString (s -> blockState ));
2710+ break ;
2711+ }
2712+
2713+ CommitTransactionCommand ();
2714+ StartTransactionCommand ();
2715+ }
2716+
2717+ /*
2718+ * ReleaseCurrentSubTransaction
2719+ *
2720+ * RELEASE (ie, commit) the innermost subtransaction, regardless of its
2721+ * savepoint name (if any).
2722+ * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
2723+ */
2724+ void
2725+ ReleaseCurrentSubTransaction (void )
2726+ {
2727+ TransactionState s = CurrentTransactionState ;
2728+
2729+ if (s -> blockState != TBLOCK_SUBINPROGRESS )
2730+ elog (ERROR , "ReleaseCurrentSubTransaction: unexpected state %s" ,
2731+ BlockStateAsString (s -> blockState ));
2732+ MemoryContextSwitchTo (CurTransactionContext );
2733+ CommitTransactionToLevel (GetCurrentTransactionNestLevel ());
2734+ }
2735+
2736+ /*
2737+ * RollbackAndReleaseCurrentSubTransaction
26612738 *
2662- * Executes a ROLLBACK TO command, immediately followed by a RELEASE
2663- * of the same savepoint.
2739+ * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
2740+ * of its savepoint name (if any).
2741+ * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
26642742 */
26652743void
2666- RollbackAndReleaseSavepoint ( List * options )
2744+ RollbackAndReleaseCurrentSubTransaction ( void )
26672745{
2668- TransactionState s ;
2746+ TransactionState s = CurrentTransactionState ;
26692747
2670- RollbackToSavepoint (options );
2671- s = CurrentTransactionState ;
2672- Assert (s -> blockState == TBLOCK_SUBENDABORT );
2748+ switch (s -> blockState )
2749+ {
2750+ /* Must be in a subtransaction */
2751+ case TBLOCK_SUBABORT :
2752+ case TBLOCK_SUBINPROGRESS :
2753+ break ;
2754+
2755+ /* these cases are invalid. */
2756+ case TBLOCK_DEFAULT :
2757+ case TBLOCK_STARTED :
2758+ case TBLOCK_ABORT :
2759+ case TBLOCK_INPROGRESS :
2760+ case TBLOCK_BEGIN :
2761+ case TBLOCK_END :
2762+ case TBLOCK_ENDABORT :
2763+ case TBLOCK_SUBEND :
2764+ case TBLOCK_SUBENDABORT_ALL :
2765+ case TBLOCK_SUBENDABORT :
2766+ case TBLOCK_SUBABORT_PENDING :
2767+ case TBLOCK_SUBENDABORT_RELEASE :
2768+ case TBLOCK_SUBBEGIN :
2769+ elog (FATAL , "RollbackAndReleaseCurrentSubTransaction: unexpected state %s" ,
2770+ BlockStateAsString (s -> blockState ));
2771+ break ;
2772+ }
2773+
2774+ /*
2775+ * Abort the current subtransaction, if needed.
2776+ */
2777+ if (s -> blockState == TBLOCK_SUBINPROGRESS )
2778+ AbortSubTransaction ();
26732779 s -> blockState = TBLOCK_SUBENDABORT_RELEASE ;
2780+
2781+ /* And clean it up, too */
2782+ CleanupAbortedSubTransactions (false);
26742783}
26752784
26762785/*
@@ -2748,7 +2857,7 @@ AbortOutOfAnyTransaction(void)
27482857 * Commit everything from the current transaction level
27492858 * up to the specified level (inclusive).
27502859 */
2751- void
2860+ static void
27522861CommitTransactionToLevel (int level )
27532862{
27542863 TransactionState s = CurrentTransactionState ;
0 commit comments