77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.148 2003/04/20 17:03:25 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.149 2003/06/24 23:25:44 momjian Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -1601,25 +1601,22 @@ ltrmark:;
16011601 * ----------
16021602 */
16031603
1604-
1605- /*
1606- * Internal data to the deferred trigger mechanism is held over
1607- * statements/commands in a context which is created at transaction
1608- * start and destroyed at transaction end.
1609- */
1610-
1611- static MemoryContext deftrig_cxt = NULL ;
1612-
1613- /* ----------
1614- * Global data that tells which triggers are actually in
1615- * state IMMEDIATE or DEFERRED.
1616- * ----------
1617- */
1618- static bool deftrig_all_isset = false;
1619- static bool deftrig_all_isdeferred = false;
1620- static List * deftrig_trigstates ;
1604+ typedef struct DeferredTriggersData {
1605+ /* Internal data is held in a per-transaction memory context */
1606+ MemoryContext deftrig_cxt ;
1607+ /* ALL DEFERRED or ALL IMMEDIATE */
1608+ bool deftrig_all_isset ;
1609+ bool deftrig_all_isdeferred ;
1610+ /* Per trigger state */
1611+ List * deftrig_trigstates ;
1612+ /* List of pending deferred triggers. Previous comment below */
1613+ DeferredTriggerEvent deftrig_events ;
1614+ DeferredTriggerEvent deftrig_events_imm ;
1615+ DeferredTriggerEvent deftrig_event_tail ;
1616+ }DeferredTriggersData ;
16211617
16221618/* ----------
1619+ * deftrig_events, deftrig_event_tail:
16231620 * The list of pending deferred trigger events during the current transaction.
16241621 *
16251622 * deftrig_events is the head, deftrig_event_tail is the last entry.
@@ -1636,10 +1633,10 @@ static List *deftrig_trigstates;
16361633 * large...
16371634 * ----------
16381635 */
1639- static DeferredTriggerEvent deftrig_events ;
1640- static DeferredTriggerEvent deftrig_events_imm ;
1641- static DeferredTriggerEvent deftrig_event_tail ;
16421636
1637+ typedef DeferredTriggersData * DeferredTriggers ;
1638+
1639+ static DeferredTriggers deferredTriggers ;
16431640
16441641/* ----------
16451642 * deferredTriggerCheckState()
@@ -1665,7 +1662,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
16651662/*
16661663 * Lookup if we know an individual state for this trigger
16671664 */
1668- foreach (sl ,deftrig_trigstates )
1665+ foreach (sl ,deferredTriggers -> deftrig_trigstates )
16691666{
16701667trigstate = (DeferredTriggerStatus )lfirst (sl );
16711668if (trigstate -> dts_tgoid == tgoid )
@@ -1676,21 +1673,22 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
16761673 * No individual state known - so if the user issued a SET CONSTRAINT
16771674 * ALL ..., we return that instead of the triggers default state.
16781675 */
1679- if (deftrig_all_isset )
1680- return deftrig_all_isdeferred ;
1676+ if (deferredTriggers -> deftrig_all_isset )
1677+ return deferredTriggers -> deftrig_all_isdeferred ;
16811678
16821679/*
16831680 * No ALL state known either, remember the default state as the
16841681 * current and return that.
16851682 */
1686- oldcxt = MemoryContextSwitchTo (deftrig_cxt );
1683+ oldcxt = MemoryContextSwitchTo (deferredTriggers -> deftrig_cxt );
16871684
16881685trigstate = (DeferredTriggerStatus )
16891686palloc (sizeof (DeferredTriggerStatusData ));
16901687trigstate -> dts_tgoid = tgoid ;
16911688trigstate -> dts_tgisdeferred =
16921689((itemstate & TRIGGER_DEFERRED_INITDEFERRED )!= 0 );
1693- deftrig_trigstates = lappend (deftrig_trigstates ,trigstate );
1690+ deferredTriggers -> deftrig_trigstates =
1691+ lappend (deferredTriggers -> deftrig_trigstates ,trigstate );
16941692
16951693MemoryContextSwitchTo (oldcxt );
16961694
@@ -1713,16 +1711,16 @@ deferredTriggerAddEvent(DeferredTriggerEvent event)
17131711 * "lappend". This avoids O(N^2) behavior for large numbers of events.
17141712 */
17151713event -> dte_next = NULL ;
1716- if (deftrig_event_tail == NULL )
1714+ if (deferredTriggers -> deftrig_event_tail == NULL )
17171715{
17181716/* first list entry */
1719- deftrig_events = event ;
1720- deftrig_event_tail = event ;
1717+ deferredTriggers -> deftrig_events = event ;
1718+ deferredTriggers -> deftrig_event_tail = event ;
17211719}
17221720else
17231721{
1724- deftrig_event_tail -> dte_next = event ;
1725- deftrig_event_tail = event ;
1722+ deferredTriggers -> deftrig_event_tail -> dte_next = event ;
1723+ deferredTriggers -> deftrig_event_tail = event ;
17261724}
17271725}
17281726
@@ -1884,15 +1882,15 @@ deferredTriggerInvokeEvents(bool immediate_only)
18841882 * are those since deftrig_events_imm. (But if deftrig_events_imm is
18851883 * NULL, we must scan the entire list.)
18861884 */
1887- if (immediate_only && deftrig_events_imm != NULL )
1885+ if (immediate_only && deferredTriggers -> deftrig_events_imm != NULL )
18881886{
1889- prev_event = deftrig_events_imm ;
1887+ prev_event = deferredTriggers -> deftrig_events_imm ;
18901888event = prev_event -> dte_next ;
18911889}
18921890else
18931891{
18941892prev_event = NULL ;
1895- event = deftrig_events ;
1893+ event = deferredTriggers -> deftrig_events ;
18961894}
18971895
18981896while (event != NULL )
@@ -1994,7 +1992,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
19941992if (prev_event )
19951993prev_event -> dte_next = next_event ;
19961994else
1997- deftrig_events = next_event ;
1995+ deferredTriggers -> deftrig_events = next_event ;
19981996pfree (event );
19991997}
20001998else
@@ -2011,10 +2009,10 @@ deferredTriggerInvokeEvents(bool immediate_only)
20112009}
20122010
20132011/* Update list tail pointer in case we just deleted tail event */
2014- deftrig_event_tail = prev_event ;
2012+ deferredTriggers -> deftrig_event_tail = prev_event ;
20152013
20162014/* Set the immediate event pointer for next time */
2017- deftrig_events_imm = prev_event ;
2015+ deferredTriggers -> deftrig_events_imm = prev_event ;
20182016
20192017/* Release working resources */
20202018if (rel )
@@ -2052,30 +2050,32 @@ DeferredTriggerInit(void)
20522050void
20532051DeferredTriggerBeginXact (void )
20542052{
2055- if (deftrig_cxt != NULL )
2056- elog (ERROR ,
2057- "DeferredTriggerBeginXact() called while inside transaction" );
2053+ /*
2054+ * This will be changed to a special context when
2055+ * the nested transactions project moves forward.
2056+ */
2057+ MemoryContext cxt = TopTransactionContext ;
2058+ deferredTriggers = (DeferredTriggers )MemoryContextAlloc (TopTransactionContext ,
2059+ sizeof (DeferredTriggersData ));
20582060
20592061/*
20602062 * Create the per transaction memory context
20612063 */
2062- deftrig_cxt = AllocSetContextCreate (TopTransactionContext ,
2064+ deferredTriggers -> deftrig_cxt = AllocSetContextCreate (cxt ,
20632065"DeferredTriggerXact" ,
20642066ALLOCSET_DEFAULT_MINSIZE ,
20652067ALLOCSET_DEFAULT_INITSIZE ,
20662068ALLOCSET_DEFAULT_MAXSIZE );
2067- deftrig_all_isset = false;
2068-
20692069/*
20702070 * If unspecified, constraints default to IMMEDIATE, per SQL
20712071 */
2072- deftrig_all_isdeferred = false;
2072+ deferredTriggers -> deftrig_all_isdeferred = false;
2073+ deferredTriggers -> deftrig_all_isset = false;
20732074
2074- deftrig_trigstates = NIL ;
2075-
2076- deftrig_events = NULL ;
2077- deftrig_events_imm = NULL ;
2078- deftrig_event_tail = NULL ;
2075+ deferredTriggers -> deftrig_trigstates = NIL ;
2076+ deferredTriggers -> deftrig_events = NULL ;
2077+ deferredTriggers -> deftrig_events_imm = NULL ;
2078+ deferredTriggers -> deftrig_event_tail = NULL ;
20792079}
20802080
20812081
@@ -2092,7 +2092,7 @@ DeferredTriggerEndQuery(void)
20922092/*
20932093 * Ignore call if we aren't in a transaction.
20942094 */
2095- if (deftrig_cxt == NULL )
2095+ if (deferredTriggers == NULL )
20962096return ;
20972097
20982098deferredTriggerInvokeEvents (true);
@@ -2112,13 +2112,12 @@ DeferredTriggerEndXact(void)
21122112/*
21132113 * Ignore call if we aren't in a transaction.
21142114 */
2115- if (deftrig_cxt == NULL )
2115+ if (deferredTriggers == NULL )
21162116return ;
21172117
21182118deferredTriggerInvokeEvents (false);
21192119
2120- MemoryContextDelete (deftrig_cxt );
2121- deftrig_cxt = NULL ;
2120+ deferredTriggers = NULL ;
21222121}
21232122
21242123
@@ -2136,11 +2135,13 @@ DeferredTriggerAbortXact(void)
21362135/*
21372136 * Ignore call if we aren't in a transaction.
21382137 */
2139- if (deftrig_cxt == NULL )
2140- return ;
2138+ if (deferredTriggers == NULL )
2139+ return ;
21412140
2142- MemoryContextDelete (deftrig_cxt );
2143- deftrig_cxt = NULL ;
2141+ /*
2142+ * Forget everything we know about deferred triggers.
2143+ */
2144+ deferredTriggers = NULL ;
21442145}
21452146
21462147
@@ -2158,7 +2159,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
21582159/*
21592160 * Ignore call if we aren't in a transaction.
21602161 */
2161- if (deftrig_cxt == NULL )
2162+ if (deferredTriggers == NULL )
21622163return ;
21632164
21642165/*
@@ -2170,7 +2171,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
21702171 * Drop all per-transaction information about individual trigger
21712172 * states.
21722173 */
2173- l = deftrig_trigstates ;
2174+ l = deferredTriggers -> deftrig_trigstates ;
21742175while (l != NIL )
21752176{
21762177List * next = lnext (l );
@@ -2179,13 +2180,13 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
21792180pfree (l );
21802181l = next ;
21812182}
2182- deftrig_trigstates = NIL ;
2183+ deferredTriggers -> deftrig_trigstates = NIL ;
21832184
21842185/*
21852186 * Set the per-transaction ALL state to known.
21862187 */
2187- deftrig_all_isset = true;
2188- deftrig_all_isdeferred = stmt -> deferred ;
2188+ deferredTriggers -> deftrig_all_isset = true;
2189+ deferredTriggers -> deftrig_all_isdeferred = stmt -> deferred ;
21892190}
21902191else
21912192{
@@ -2267,12 +2268,12 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
22672268 * Inside of a transaction block set the trigger states of
22682269 * individual triggers on transaction level.
22692270 */
2270- oldcxt = MemoryContextSwitchTo (deftrig_cxt );
2271+ oldcxt = MemoryContextSwitchTo (deferredTriggers -> deftrig_cxt );
22712272
22722273foreach (l ,loid )
22732274{
22742275found = false;
2275- foreach (ls ,deftrig_trigstates )
2276+ foreach (ls ,deferredTriggers -> deftrig_trigstates )
22762277{
22772278state = (DeferredTriggerStatus )lfirst (ls );
22782279if (state -> dts_tgoid == lfirsto (l ))
@@ -2289,8 +2290,8 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
22892290state -> dts_tgoid = lfirsto (l );
22902291state -> dts_tgisdeferred = stmt -> deferred ;
22912292
2292- deftrig_trigstates =
2293- lappend (deftrig_trigstates ,state );
2293+ deferredTriggers -> deftrig_trigstates =
2294+ lappend (deferredTriggers -> deftrig_trigstates ,state );
22942295}
22952296}
22962297
@@ -2308,7 +2309,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
23082309 * tail pointer to make it rescan the entire list, in case some deferred
23092310 * events are now immediately invokable.
23102311 */
2311- deftrig_events_imm = NULL ;
2312+ deferredTriggers -> deftrig_events_imm = NULL ;
23122313}
23132314
23142315
@@ -2337,7 +2338,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
23372338ItemPointerData oldctid ;
23382339ItemPointerData newctid ;
23392340
2340- if (deftrig_cxt == NULL )
2341+ if (deferredTriggers == NULL )
23412342elog (ERROR ,
23422343"DeferredTriggerSaveEvent() called outside of transaction" );
23432344
@@ -2387,7 +2388,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
23872388/*
23882389 * Create a new event
23892390 */
2390- oldcxt = MemoryContextSwitchTo (deftrig_cxt );
2391+ oldcxt = MemoryContextSwitchTo (deferredTriggers -> deftrig_cxt );
23912392
23922393new_size = offsetof(DeferredTriggerEventData ,dte_item [0 ])+
23932394n_enabled_triggers * sizeof (DeferredTriggerEventItem );