77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.168 2004/08/29 05:06:41 momjian Exp $
10+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.169 2004/09/06 23:32:54 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -1669,8 +1669,11 @@ ltrmark:;
16691669 * state data; each subtransaction level that modifies that state first
16701670 * saves a copy, which we use to restore the state if we abort.
16711671 *
1672- * numpushed and numalloc keep control of allocation and storage in the above
1673- * stacks.numpushed is essentially the current subtransaction nesting depth.
1672+ * We use GetCurrentTransactionNestLevel() to determine the correct array
1673+ * index in these stacks. numalloc is the number of allocated entries in
1674+ * each stack. (By not keeping our own stack pointer, we can avoid trouble
1675+ * in cases where errors during subxact abort cause multiple invocations
1676+ * of DeferredTriggerEndSubXact() at the same nesting depth.)
16741677 *
16751678 * XXX We need to be able to save the per-event data in a file if it grows too
16761679 * large.
@@ -1742,7 +1745,6 @@ typedef struct DeferredTriggersData
17421745DeferredTriggerEvent * tail_stack ;
17431746DeferredTriggerEvent * imm_stack ;
17441747DeferredTriggerState * state_stack ;
1745- int numpushed ;
17461748int numalloc ;
17471749}DeferredTriggersData ;
17481750
@@ -2165,7 +2167,6 @@ DeferredTriggerBeginXact(void)
21652167deferredTriggers -> imm_stack = NULL ;
21662168deferredTriggers -> state_stack = NULL ;
21672169deferredTriggers -> numalloc = 0 ;
2168- deferredTriggers -> numpushed = 0 ;
21692170}
21702171
21712172
@@ -2251,6 +2252,8 @@ DeferredTriggerAbortXact(void)
22512252void
22522253DeferredTriggerBeginSubXact (void )
22532254{
2255+ int my_level = GetCurrentTransactionNestLevel ();
2256+
22542257/*
22552258 * Ignore call if the transaction is in aborted state.
22562259 */
@@ -2260,7 +2263,7 @@ DeferredTriggerBeginSubXact(void)
22602263/*
22612264 * Allocate more space in the stacks if needed.
22622265 */
2263- if ( deferredTriggers -> numpushed = =deferredTriggers -> numalloc )
2266+ while ( my_level > =deferredTriggers -> numalloc )
22642267{
22652268if (deferredTriggers -> numalloc == 0 )
22662269{
@@ -2282,32 +2285,28 @@ DeferredTriggerBeginSubXact(void)
22822285else
22832286{
22842287/* repalloc will keep the stacks in the same context */
2285- deferredTriggers -> numalloc *= 2 ;
2288+ int new_alloc = deferredTriggers -> numalloc * 2 ;
22862289
22872290deferredTriggers -> tail_stack = (DeferredTriggerEvent * )
22882291repalloc (deferredTriggers -> tail_stack ,
2289- deferredTriggers -> numalloc * sizeof (DeferredTriggerEvent ));
2292+ new_alloc * sizeof (DeferredTriggerEvent ));
22902293deferredTriggers -> imm_stack = (DeferredTriggerEvent * )
22912294repalloc (deferredTriggers -> imm_stack ,
2292- deferredTriggers -> numalloc * sizeof (DeferredTriggerEvent ));
2295+ new_alloc * sizeof (DeferredTriggerEvent ));
22932296deferredTriggers -> state_stack = (DeferredTriggerState * )
22942297repalloc (deferredTriggers -> state_stack ,
2295- deferredTriggers -> numalloc * sizeof (DeferredTriggerState ));
2298+ new_alloc * sizeof (DeferredTriggerState ));
2299+ deferredTriggers -> numalloc = new_alloc ;
22962300}
22972301}
22982302
22992303/*
2300- * Push the current list position into the stack and reset the
2301- * pointer.
2304+ * Push the current information into the stack.
23022305 */
2303- deferredTriggers -> tail_stack [deferredTriggers -> numpushed ]=
2304- deferredTriggers -> tail_thisxact ;
2305- deferredTriggers -> imm_stack [deferredTriggers -> numpushed ]=
2306- deferredTriggers -> events_imm ;
2306+ deferredTriggers -> tail_stack [my_level ]= deferredTriggers -> tail_thisxact ;
2307+ deferredTriggers -> imm_stack [my_level ]= deferredTriggers -> events_imm ;
23072308/* State is not saved until/unless changed */
2308- deferredTriggers -> state_stack [deferredTriggers -> numpushed ]= NULL ;
2309-
2310- deferredTriggers -> numpushed ++ ;
2309+ deferredTriggers -> state_stack [my_level ]= NULL ;
23112310}
23122311
23132312/*
@@ -2318,6 +2317,7 @@ DeferredTriggerBeginSubXact(void)
23182317void
23192318DeferredTriggerEndSubXact (bool isCommit )
23202319{
2320+ int my_level = GetCurrentTransactionNestLevel ();
23212321DeferredTriggerState state ;
23222322
23232323/*
@@ -2327,28 +2327,28 @@ DeferredTriggerEndSubXact(bool isCommit)
23272327return ;
23282328
23292329/*
2330- *Move back the"top of the stack."
2330+ *Pop theprior state if needed.
23312331 */
2332- Assert (deferredTriggers -> numpushed > 0 );
2333-
2334- deferredTriggers -> numpushed -- ;
2332+ Assert (my_level < deferredTriggers -> numalloc );
23352333
23362334if (isCommit )
23372335{
23382336/* If we saved a prior state, we don't need it anymore */
2339- state = deferredTriggers -> state_stack [deferredTriggers -> numpushed ];
2337+ state = deferredTriggers -> state_stack [my_level ];
23402338if (state != NULL )
23412339pfree (state );
2340+ /* this avoids double pfree if error later: */
2341+ deferredTriggers -> state_stack [my_level ]= NULL ;
23422342}
23432343else
23442344{
23452345/*
23462346 * Aborting --- restore the pointers from the stacks.
23472347 */
23482348deferredTriggers -> tail_thisxact =
2349- deferredTriggers -> tail_stack [deferredTriggers -> numpushed ];
2349+ deferredTriggers -> tail_stack [my_level ];
23502350deferredTriggers -> events_imm =
2351- deferredTriggers -> imm_stack [deferredTriggers -> numpushed ];
2351+ deferredTriggers -> imm_stack [my_level ];
23522352
23532353/*
23542354 * Cleanup the head and the tail of the list.
@@ -2367,12 +2367,14 @@ DeferredTriggerEndSubXact(bool isCommit)
23672367 * Restore the trigger state. If the saved state is NULL, then
23682368 * this subxact didn't save it, so it doesn't need restoring.
23692369 */
2370- state = deferredTriggers -> state_stack [deferredTriggers -> numpushed ];
2370+ state = deferredTriggers -> state_stack [my_level ];
23712371if (state != NULL )
23722372{
23732373pfree (deferredTriggers -> state );
23742374deferredTriggers -> state = state ;
23752375}
2376+ /* this avoids double pfree if error later: */
2377+ deferredTriggers -> state_stack [my_level ]= NULL ;
23762378}
23772379}
23782380
@@ -2457,6 +2459,8 @@ DeferredTriggerStateAddItem(DeferredTriggerState state,
24572459void
24582460DeferredTriggerSetState (ConstraintsSetStmt * stmt )
24592461{
2462+ int my_level = GetCurrentTransactionNestLevel ();
2463+
24602464/*
24612465 * Ignore call if we aren't in a transaction.
24622466 */
@@ -2468,10 +2472,10 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
24682472 * already, save it so it can be restored if the subtransaction
24692473 * aborts.
24702474 */
2471- if (deferredTriggers -> numpushed > 0 &&
2472- deferredTriggers -> state_stack [deferredTriggers -> numpushed - 1 ]== NULL )
2475+ if (my_level > 1 &&
2476+ deferredTriggers -> state_stack [my_level ]== NULL )
24732477{
2474- deferredTriggers -> state_stack [deferredTriggers -> numpushed - 1 ]=
2478+ deferredTriggers -> state_stack [my_level ]=
24752479DeferredTriggerStateCopy (deferredTriggers -> state );
24762480}
24772481