7
7
* Portions Copyright (c) 1994, Regents of the University of California
8
8
*
9
9
* 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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -1669,8 +1669,11 @@ ltrmark:;
1669
1669
* state data; each subtransaction level that modifies that state first
1670
1670
* saves a copy, which we use to restore the state if we abort.
1671
1671
*
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.)
1674
1677
*
1675
1678
* XXX We need to be able to save the per-event data in a file if it grows too
1676
1679
* large.
@@ -1742,7 +1745,6 @@ typedef struct DeferredTriggersData
1742
1745
DeferredTriggerEvent * tail_stack ;
1743
1746
DeferredTriggerEvent * imm_stack ;
1744
1747
DeferredTriggerState * state_stack ;
1745
- int numpushed ;
1746
1748
int numalloc ;
1747
1749
} DeferredTriggersData ;
1748
1750
@@ -2165,7 +2167,6 @@ DeferredTriggerBeginXact(void)
2165
2167
deferredTriggers -> imm_stack = NULL ;
2166
2168
deferredTriggers -> state_stack = NULL ;
2167
2169
deferredTriggers -> numalloc = 0 ;
2168
- deferredTriggers -> numpushed = 0 ;
2169
2170
}
2170
2171
2171
2172
@@ -2251,6 +2252,8 @@ DeferredTriggerAbortXact(void)
2251
2252
void
2252
2253
DeferredTriggerBeginSubXact (void )
2253
2254
{
2255
+ int my_level = GetCurrentTransactionNestLevel ();
2256
+
2254
2257
/*
2255
2258
* Ignore call if the transaction is in aborted state.
2256
2259
*/
@@ -2260,7 +2263,7 @@ DeferredTriggerBeginSubXact(void)
2260
2263
/*
2261
2264
* Allocate more space in the stacks if needed.
2262
2265
*/
2263
- if ( deferredTriggers -> numpushed = = deferredTriggers -> numalloc )
2266
+ while ( my_level > = deferredTriggers -> numalloc )
2264
2267
{
2265
2268
if (deferredTriggers -> numalloc == 0 )
2266
2269
{
@@ -2282,32 +2285,28 @@ DeferredTriggerBeginSubXact(void)
2282
2285
else
2283
2286
{
2284
2287
/* repalloc will keep the stacks in the same context */
2285
- deferredTriggers -> numalloc *= 2 ;
2288
+ int new_alloc = deferredTriggers -> numalloc * 2 ;
2286
2289
2287
2290
deferredTriggers -> tail_stack = (DeferredTriggerEvent * )
2288
2291
repalloc (deferredTriggers -> tail_stack ,
2289
- deferredTriggers -> numalloc * sizeof (DeferredTriggerEvent ));
2292
+ new_alloc * sizeof (DeferredTriggerEvent ));
2290
2293
deferredTriggers -> imm_stack = (DeferredTriggerEvent * )
2291
2294
repalloc (deferredTriggers -> imm_stack ,
2292
- deferredTriggers -> numalloc * sizeof (DeferredTriggerEvent ));
2295
+ new_alloc * sizeof (DeferredTriggerEvent ));
2293
2296
deferredTriggers -> state_stack = (DeferredTriggerState * )
2294
2297
repalloc (deferredTriggers -> state_stack ,
2295
- deferredTriggers -> numalloc * sizeof (DeferredTriggerState ));
2298
+ new_alloc * sizeof (DeferredTriggerState ));
2299
+ deferredTriggers -> numalloc = new_alloc ;
2296
2300
}
2297
2301
}
2298
2302
2299
2303
/*
2300
- * Push the current list position into the stack and reset the
2301
- * pointer.
2304
+ * Push the current information into the stack.
2302
2305
*/
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 ;
2307
2308
/* 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 ;
2311
2310
}
2312
2311
2313
2312
/*
@@ -2318,6 +2317,7 @@ DeferredTriggerBeginSubXact(void)
2318
2317
void
2319
2318
DeferredTriggerEndSubXact (bool isCommit )
2320
2319
{
2320
+ int my_level = GetCurrentTransactionNestLevel ();
2321
2321
DeferredTriggerState state ;
2322
2322
2323
2323
/*
@@ -2327,28 +2327,28 @@ DeferredTriggerEndSubXact(bool isCommit)
2327
2327
return ;
2328
2328
2329
2329
/*
2330
- * Move back the "top of the stack."
2330
+ * Pop the prior state if needed.
2331
2331
*/
2332
- Assert (deferredTriggers -> numpushed > 0 );
2333
-
2334
- deferredTriggers -> numpushed -- ;
2332
+ Assert (my_level < deferredTriggers -> numalloc );
2335
2333
2336
2334
if (isCommit )
2337
2335
{
2338
2336
/* 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 ];
2340
2338
if (state != NULL )
2341
2339
pfree (state );
2340
+ /* this avoids double pfree if error later: */
2341
+ deferredTriggers -> state_stack [my_level ] = NULL ;
2342
2342
}
2343
2343
else
2344
2344
{
2345
2345
/*
2346
2346
* Aborting --- restore the pointers from the stacks.
2347
2347
*/
2348
2348
deferredTriggers -> tail_thisxact =
2349
- deferredTriggers -> tail_stack [deferredTriggers -> numpushed ];
2349
+ deferredTriggers -> tail_stack [my_level ];
2350
2350
deferredTriggers -> events_imm =
2351
- deferredTriggers -> imm_stack [deferredTriggers -> numpushed ];
2351
+ deferredTriggers -> imm_stack [my_level ];
2352
2352
2353
2353
/*
2354
2354
* Cleanup the head and the tail of the list.
@@ -2367,12 +2367,14 @@ DeferredTriggerEndSubXact(bool isCommit)
2367
2367
* Restore the trigger state. If the saved state is NULL, then
2368
2368
* this subxact didn't save it, so it doesn't need restoring.
2369
2369
*/
2370
- state = deferredTriggers -> state_stack [deferredTriggers -> numpushed ];
2370
+ state = deferredTriggers -> state_stack [my_level ];
2371
2371
if (state != NULL )
2372
2372
{
2373
2373
pfree (deferredTriggers -> state );
2374
2374
deferredTriggers -> state = state ;
2375
2375
}
2376
+ /* this avoids double pfree if error later: */
2377
+ deferredTriggers -> state_stack [my_level ] = NULL ;
2376
2378
}
2377
2379
}
2378
2380
@@ -2457,6 +2459,8 @@ DeferredTriggerStateAddItem(DeferredTriggerState state,
2457
2459
void
2458
2460
DeferredTriggerSetState (ConstraintsSetStmt * stmt )
2459
2461
{
2462
+ int my_level = GetCurrentTransactionNestLevel ();
2463
+
2460
2464
/*
2461
2465
* Ignore call if we aren't in a transaction.
2462
2466
*/
@@ -2468,10 +2472,10 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
2468
2472
* already, save it so it can be restored if the subtransaction
2469
2473
* aborts.
2470
2474
*/
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 )
2473
2477
{
2474
- deferredTriggers -> state_stack [deferredTriggers -> numpushed - 1 ] =
2478
+ deferredTriggers -> state_stack [my_level ] =
2475
2479
DeferredTriggerStateCopy (deferredTriggers -> state );
2476
2480
}
2477
2481
0 commit comments