@@ -341,6 +341,9 @@ static void CommitTransaction(void);
341341static TransactionId RecordTransactionAbort (bool isSubXact );
342342static void StartTransaction (void );
343343
344+ static void CommitTransactionCommandInternal (void );
345+ static void AbortCurrentTransactionInternal (void );
346+
344347static void StartSubTransaction (void );
345348static void CommitSubTransaction (void );
346349static void AbortSubTransaction (void );
@@ -3041,16 +3044,58 @@ RestoreTransactionCharacteristics(const SavedTransactionCharacteristics *s)
30413044 XactDeferrable = s -> save_XactDeferrable ;
30423045}
30433046
3044-
30453047/*
3046- * CommitTransactionCommand
3048+ * CommitTransactionCommand -- a wrapper function handling the
3049+ * loop over subtransactions to avoid a potentially dangerous recursion
3050+ * in CommitTransactionCommandInternal().
30473051 */
30483052void
30493053CommitTransactionCommand (void )
3054+ {
3055+ while (true)
3056+ {
3057+ switch (CurrentTransactionState -> blockState )
3058+ {
3059+ /*
3060+ * The current already-failed subtransaction is ending due to
3061+ * a ROLLBACK or ROLLBACK TO command, so pop it and
3062+ * recursively examine the parent (which could be in any of
3063+ * several states).
3064+ */
3065+ case TBLOCK_SUBABORT_END :
3066+ CleanupSubTransaction ();
3067+ continue ;
3068+
3069+ /*
3070+ * As above, but it's not dead yet, so abort first.
3071+ */
3072+ case TBLOCK_SUBABORT_PENDING :
3073+ AbortSubTransaction ();
3074+ CleanupSubTransaction ();
3075+ continue ;
3076+ default :
3077+ break ;
3078+ }
3079+ CommitTransactionCommandInternal ();
3080+ break ;
3081+ }
3082+ }
3083+
3084+ /*
3085+ * CommitTransactionCommandInternal - a function doing all the material work
3086+ * regarding handling the commit transaction command except for loop over
3087+ * subtransactions.
3088+ */
3089+ static void
3090+ CommitTransactionCommandInternal (void )
30503091{
30513092 TransactionState s = CurrentTransactionState ;
30523093 SavedTransactionCharacteristics savetc ;
30533094
3095+ /* This states are handled in CommitTransactionCommand() */
3096+ Assert (s -> blockState != TBLOCK_SUBABORT_END &&
3097+ s -> blockState != TBLOCK_SUBABORT_PENDING );
3098+
30543099 /* Must save in case we need to restore below */
30553100 SaveTransactionCharacteristics (& savetc );
30563101
@@ -3234,25 +3279,6 @@ CommitTransactionCommand(void)
32343279 BlockStateAsString (s -> blockState ));
32353280 break ;
32363281
3237- /*
3238- * The current already-failed subtransaction is ending due to a
3239- * ROLLBACK or ROLLBACK TO command, so pop it and recursively
3240- * examine the parent (which could be in any of several states).
3241- */
3242- case TBLOCK_SUBABORT_END :
3243- CleanupSubTransaction ();
3244- CommitTransactionCommand ();
3245- break ;
3246-
3247- /*
3248- * As above, but it's not dead yet, so abort first.
3249- */
3250- case TBLOCK_SUBABORT_PENDING :
3251- AbortSubTransaction ();
3252- CleanupSubTransaction ();
3253- CommitTransactionCommand ();
3254- break ;
3255-
32563282 /*
32573283 * The current subtransaction is the target of a ROLLBACK TO
32583284 * command. Abort and pop it, then start a new subtransaction
@@ -3310,17 +3336,73 @@ CommitTransactionCommand(void)
33103336 s -> blockState = TBLOCK_SUBINPROGRESS ;
33113337 }
33123338 break ;
3339+ default :
3340+ /* Keep compiler quiet */
3341+ break ;
33133342 }
33143343}
33153344
33163345/*
3317- * AbortCurrentTransaction
3346+ * AbortCurrentTransaction -- a wrapper function handling the
3347+ * loop over subtransactions to avoid potentially dangerous recursion in
3348+ * AbortCurrentTransactionInternal().
33183349 */
33193350void
33203351AbortCurrentTransaction (void )
3352+ {
3353+ while (true)
3354+ {
3355+ switch (CurrentTransactionState -> blockState )
3356+ {
3357+ /*
3358+ * If we failed while trying to create a subtransaction, clean
3359+ * up the broken subtransaction and abort the parent. The
3360+ * same applies if we get a failure while ending a
3361+ * subtransaction.
3362+ */
3363+ case TBLOCK_SUBBEGIN :
3364+ case TBLOCK_SUBRELEASE :
3365+ case TBLOCK_SUBCOMMIT :
3366+ case TBLOCK_SUBABORT_PENDING :
3367+ case TBLOCK_SUBRESTART :
3368+ AbortSubTransaction ();
3369+ CleanupSubTransaction ();
3370+ continue ;
3371+
3372+ /*
3373+ * Same as above, except the Abort() was already done.
3374+ */
3375+ case TBLOCK_SUBABORT_END :
3376+ case TBLOCK_SUBABORT_RESTART :
3377+ CleanupSubTransaction ();
3378+ continue ;
3379+ default :
3380+ break ;
3381+ }
3382+ AbortCurrentTransactionInternal ();
3383+ break ;
3384+ }
3385+ }
3386+
3387+ /*
3388+ * AbortCurrentTransactionInternal - a function doing all the material work
3389+ * regarding handling the abort transaction command except for loop over
3390+ * subtransactions.
3391+ */
3392+ static void
3393+ AbortCurrentTransactionInternal (void )
33213394{
33223395 TransactionState s = CurrentTransactionState ;
33233396
3397+ /* This states are handled in AbortCurrentTransaction() */
3398+ Assert (s -> blockState != TBLOCK_SUBBEGIN &&
3399+ s -> blockState != TBLOCK_SUBRELEASE &&
3400+ s -> blockState != TBLOCK_SUBCOMMIT &&
3401+ s -> blockState != TBLOCK_SUBABORT_PENDING &&
3402+ s -> blockState != TBLOCK_SUBRESTART &&
3403+ s -> blockState != TBLOCK_SUBABORT_END &&
3404+ s -> blockState != TBLOCK_SUBABORT_RESTART );
3405+
33243406 switch (s -> blockState )
33253407 {
33263408 case TBLOCK_DEFAULT :
@@ -3441,29 +3523,8 @@ AbortCurrentTransaction(void)
34413523 AbortSubTransaction ();
34423524 s -> blockState = TBLOCK_SUBABORT ;
34433525 break ;
3444-
3445- /*
3446- * If we failed while trying to create a subtransaction, clean up
3447- * the broken subtransaction and abort the parent. The same
3448- * applies if we get a failure while ending a subtransaction.
3449- */
3450- case TBLOCK_SUBBEGIN :
3451- case TBLOCK_SUBRELEASE :
3452- case TBLOCK_SUBCOMMIT :
3453- case TBLOCK_SUBABORT_PENDING :
3454- case TBLOCK_SUBRESTART :
3455- AbortSubTransaction ();
3456- CleanupSubTransaction ();
3457- AbortCurrentTransaction ();
3458- break ;
3459-
3460- /*
3461- * Same as above, except the Abort() was already done.
3462- */
3463- case TBLOCK_SUBABORT_END :
3464- case TBLOCK_SUBABORT_RESTART :
3465- CleanupSubTransaction ();
3466- AbortCurrentTransaction ();
3526+ default :
3527+ /* Keep compiler quiet */
34673528 break ;
34683529 }
34693530}
0 commit comments