8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
* NOTES
14
14
* Transaction aborts can now occur two ways:
@@ -1589,7 +1589,8 @@ CleanupTransaction(void)
1589
1589
* State should still be TRANS_ABORT from AbortTransaction().
1590
1590
*/
1591
1591
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 ));
1593
1594
1594
1595
/*
1595
1596
* do abort cleanup processing
@@ -1773,7 +1774,7 @@ CommitTransactionCommand(void)
1773
1774
1774
1775
/*
1775
1776
* We were just issued a SAVEPOINT inside a transaction block.
1776
- * Start a subtransaction. (BeginTransactionBlock already
1777
+ * Start a subtransaction. (DefineSavepoint already
1777
1778
* did PushTransaction, so as to have someplace to put the
1778
1779
* SUBBEGIN state.)
1779
1780
*/
@@ -1853,6 +1854,7 @@ CleanupAbortedSubTransactions(bool returnName)
1853
1854
AssertState (PointerIsValid (s -> parent ));
1854
1855
Assert (s -> parent -> blockState == TBLOCK_SUBINPROGRESS ||
1855
1856
s -> parent -> blockState == TBLOCK_INPROGRESS ||
1857
+ s -> parent -> blockState == TBLOCK_STARTED ||
1856
1858
s -> parent -> blockState == TBLOCK_SUBABORT_PENDING );
1857
1859
1858
1860
/*
@@ -1878,7 +1880,8 @@ CleanupAbortedSubTransactions(bool returnName)
1878
1880
}
1879
1881
1880
1882
AssertState (s -> blockState == TBLOCK_SUBINPROGRESS ||
1881
- s -> blockState == TBLOCK_INPROGRESS );
1883
+ s -> blockState == TBLOCK_INPROGRESS ||
1884
+ s -> blockState == TBLOCK_STARTED );
1882
1885
1883
1886
return name ;
1884
1887
}
@@ -2468,7 +2471,7 @@ DefineSavepoint(char *name)
2468
2471
case TBLOCK_SUBABORT_PENDING :
2469
2472
case TBLOCK_SUBENDABORT_RELEASE :
2470
2473
case TBLOCK_SUBEND :
2471
- elog (FATAL , "BeginTransactionBlock : unexpected state %s" ,
2474
+ elog (FATAL , "DefineSavepoint : unexpected state %s" ,
2472
2475
BlockStateAsString (s -> blockState ));
2473
2476
break ;
2474
2477
}
@@ -2657,20 +2660,126 @@ RollbackToSavepoint(List *options)
2657
2660
}
2658
2661
2659
2662
/*
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
2661
2738
*
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.
2664
2742
*/
2665
2743
void
2666
- RollbackAndReleaseSavepoint ( List * options )
2744
+ RollbackAndReleaseCurrentSubTransaction ( void )
2667
2745
{
2668
- TransactionState s ;
2746
+ TransactionState s = CurrentTransactionState ;
2669
2747
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 ();
2673
2779
s -> blockState = TBLOCK_SUBENDABORT_RELEASE ;
2780
+
2781
+ /* And clean it up, too */
2782
+ CleanupAbortedSubTransactions (false);
2674
2783
}
2675
2784
2676
2785
/*
@@ -2748,7 +2857,7 @@ AbortOutOfAnyTransaction(void)
2748
2857
* Commit everything from the current transaction level
2749
2858
* up to the specified level (inclusive).
2750
2859
*/
2751
- void
2860
+ static void
2752
2861
CommitTransactionToLevel (int level )
2753
2862
{
2754
2863
TransactionState s = CurrentTransactionState ;
0 commit comments