Index: src/backend/commands/trigger.c =================================================================== RCS file: /home/alvherre/cvs/pgsql-server/src/backend/commands/trigger.c,v retrieving revision 1.148 diff -c -r1.148 trigger.c *** src/backend/commands/trigger.c 20 Apr 2003 17:03:25 -0000 1.148 --- src/backend/commands/trigger.c 27 Apr 2003 16:56:57 -0000 *************** *** 7,13 **** * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION ! * $Header: /home/alvherre/cvs/pgsql-server/src/backend/commands/trigger.c,v 1.148 2003/04/20 17:03:25 tgl Exp $ * *------------------------------------------------------------------------- */ --- 7,13 ---- * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION ! * $Header: /projects/cvsroot/pgsql-server/src/backend/commands/trigger.c,v 1.148 2003/04/20 17:03:25 tgl Exp $ * *------------------------------------------------------------------------- */ *************** *** 1601,1625 **** * ---------- */ ! ! /* ! * Internal data to the deferred trigger mechanism is held over ! * statements/commands in a context which is created at transaction ! * start and destroyed at transaction end. ! */ ! ! static MemoryContext deftrig_cxt = NULL; ! ! /* ---------- ! * Global data that tells which triggers are actually in ! * state IMMEDIATE or DEFERRED. ! * ---------- ! */ ! static bool deftrig_all_isset = false; ! static bool deftrig_all_isdeferred = false; ! static List *deftrig_trigstates; /* ---------- * The list of pending deferred trigger events during the current transaction. * * deftrig_events is the head, deftrig_event_tail is the last entry. --- 1601,1623 ---- * ---------- */ ! typedef struct DeferredTriggerStackData { ! /* Internal data is held in a per-transaction memory context */ ! MemoryContext deftrig_cxt; ! /* ALL DEFERRED or ALL IMMEDIATE */ ! bool deftrig_all_isset; ! bool deftrig_all_isdeferred; ! /* Per trigger state */ ! List *deftrig_trigstates; ! /* List of pending deferred triggers. Previous comment below */ ! DeferredTriggerEvent deftrig_events; ! DeferredTriggerEvent deftrig_events_imm; ! DeferredTriggerEvent deftrig_event_tail; ! struct DeferredTriggerStackData *parent; ! } DeferredTriggerStackData; /* ---------- + * deftrig_events, deftrig_event_tail: * The list of pending deferred trigger events during the current transaction. * * deftrig_events is the head, deftrig_event_tail is the last entry. *************** *** 1636,1645 **** * large... * ---------- */ - static DeferredTriggerEvent deftrig_events; - static DeferredTriggerEvent deftrig_events_imm; - static DeferredTriggerEvent deftrig_event_tail; /* ---------- * deferredTriggerCheckState() --- 1634,1642 ---- * large... * ---------- */ + typedef DeferredTriggerStackData *DeferredTriggerStack; + static DeferredTriggerStack ts; /* ---------- * deferredTriggerCheckState() *************** *** 1665,1671 **** /* * Lookup if we know an individual state for this trigger */ ! foreach(sl, deftrig_trigstates) { trigstate = (DeferredTriggerStatus) lfirst(sl); if (trigstate->dts_tgoid == tgoid) --- 1662,1668 ---- /* * Lookup if we know an individual state for this trigger */ ! foreach(sl, ts->deftrig_trigstates) { trigstate = (DeferredTriggerStatus) lfirst(sl); if (trigstate->dts_tgoid == tgoid) *************** *** 1676,1696 **** * No individual state known - so if the user issued a SET CONSTRAINT * ALL ..., we return that instead of the triggers default state. */ ! if (deftrig_all_isset) ! return deftrig_all_isdeferred; /* * No ALL state known either, remember the default state as the * current and return that. */ ! oldcxt = MemoryContextSwitchTo(deftrig_cxt); trigstate = (DeferredTriggerStatus) palloc(sizeof(DeferredTriggerStatusData)); trigstate->dts_tgoid = tgoid; trigstate->dts_tgisdeferred = ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0); ! deftrig_trigstates = lappend(deftrig_trigstates, trigstate); MemoryContextSwitchTo(oldcxt); --- 1673,1693 ---- * No individual state known - so if the user issued a SET CONSTRAINT * ALL ..., we return that instead of the triggers default state. */ ! if (ts->deftrig_all_isset) ! return ts->deftrig_all_isdeferred; /* * No ALL state known either, remember the default state as the * current and return that. */ ! oldcxt = MemoryContextSwitchTo(ts->deftrig_cxt); trigstate = (DeferredTriggerStatus) palloc(sizeof(DeferredTriggerStatusData)); trigstate->dts_tgoid = tgoid; trigstate->dts_tgisdeferred = ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0); ! ts->deftrig_trigstates = lappend(ts->deftrig_trigstates, trigstate); MemoryContextSwitchTo(oldcxt); *************** *** 1713,1728 **** * "lappend". This avoids O(N^2) behavior for large numbers of events. */ event->dte_next = NULL; ! if (deftrig_event_tail == NULL) { /* first list entry */ ! deftrig_events = event; ! deftrig_event_tail = event; } else { ! deftrig_event_tail->dte_next = event; ! deftrig_event_tail = event; } } --- 1710,1725 ---- * "lappend". This avoids O(N^2) behavior for large numbers of events. */ event->dte_next = NULL; ! if (ts->deftrig_event_tail == NULL) { /* first list entry */ ! ts->deftrig_events = event; ! ts->deftrig_event_tail = event; } else { ! ts->deftrig_event_tail->dte_next = event; ! ts->deftrig_event_tail = event; } } *************** *** 1884,1898 **** * are those since deftrig_events_imm. (But if deftrig_events_imm is * NULL, we must scan the entire list.) */ ! if (immediate_only && deftrig_events_imm != NULL) { ! prev_event = deftrig_events_imm; event = prev_event->dte_next; } else { prev_event = NULL; ! event = deftrig_events; } while (event != NULL) --- 1881,1895 ---- * are those since deftrig_events_imm. (But if deftrig_events_imm is * NULL, we must scan the entire list.) */ ! if (immediate_only && ts->deftrig_events_imm != NULL) { ! prev_event = ts->deftrig_events_imm; event = prev_event->dte_next; } else { prev_event = NULL; ! event = ts->deftrig_events; } while (event != NULL) *************** *** 1994,2000 **** if (prev_event) prev_event->dte_next = next_event; else ! deftrig_events = next_event; pfree(event); } else --- 1991,1997 ---- if (prev_event) prev_event->dte_next = next_event; else ! ts->deftrig_events = next_event; pfree(event); } else *************** *** 2011,2020 **** } /* Update list tail pointer in case we just deleted tail event */ ! deftrig_event_tail = prev_event; /* Set the immediate event pointer for next time */ ! deftrig_events_imm = prev_event; /* Release working resources */ if (rel) --- 2008,2017 ---- } /* Update list tail pointer in case we just deleted tail event */ ! ts->deftrig_event_tail = prev_event; /* Set the immediate event pointer for next time */ ! ts->deftrig_events_imm = prev_event; /* Release working resources */ if (rel) *************** *** 2037,2044 **** void DeferredTriggerInit(void) { ! /* Nothing to do */ ! ; } --- 2034,2040 ---- void DeferredTriggerInit(void) { ! ts = NULL; } *************** *** 2052,2081 **** void DeferredTriggerBeginXact(void) { ! if (deftrig_cxt != NULL) ! elog(ERROR, ! "DeferredTriggerBeginXact() called while inside transaction"); /* * Create the per transaction memory context */ ! deftrig_cxt = AllocSetContextCreate(TopTransactionContext, "DeferredTriggerXact", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); - deftrig_all_isset = false; - /* * If unspecified, constraints default to IMMEDIATE, per SQL */ ! deftrig_all_isdeferred = false; ! deftrig_trigstates = NIL; ! deftrig_events = NULL; ! deftrig_events_imm = NULL; ! deftrig_event_tail = NULL; } --- 2048,2082 ---- void DeferredTriggerBeginXact(void) { ! DeferredTriggerStack tts; ! MemoryContext old_cxt; ! ! old_cxt = MemoryContextSwitchTo(TopTransactionContext); ! tts = (DeferredTriggerStack) palloc(sizeof(DeferredTriggerStackData)); /* * Create the per transaction memory context */ ! tts->deftrig_cxt = AllocSetContextCreate(TopTransactionContext, "DeferredTriggerXact", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * If unspecified, constraints default to IMMEDIATE, per SQL */ ! tts->deftrig_all_isdeferred = false; ! tts->deftrig_all_isset = false; ! ! tts->deftrig_trigstates = NIL; ! tts->deftrig_events = NULL; ! tts->deftrig_events_imm = NULL; ! tts->deftrig_event_tail = NULL; ! tts->parent = ts; ! ts = tts; ! MemoryContextSwitchTo(old_cxt); } *************** *** 2092,2098 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; deferredTriggerInvokeEvents(true); --- 2093,2099 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; deferredTriggerInvokeEvents(true); *************** *** 2112,2124 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; deferredTriggerInvokeEvents(false); ! MemoryContextDelete(deftrig_cxt); ! deftrig_cxt = NULL; } --- 2113,2128 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; deferredTriggerInvokeEvents(false); ! /* ! * The stack item will be freed when the TopTransactionContext ! * is erased, so there's no need to do it manually. ! */ ! ts = ts->parent; } *************** *** 2136,2146 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; ! MemoryContextDelete(deftrig_cxt); ! deftrig_cxt = NULL; } --- 2140,2153 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; ! /* ! * The stack item will be freed when the TopTransactionContext ! * is erased, so there's no need to do it manually. ! */ ! ts = ts->parent; } *************** *** 2158,2164 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; /* --- 2165,2171 ---- /* * Ignore call if we aren't in a transaction. */ ! if (ts == NULL) return; /* *************** *** 2170,2176 **** * Drop all per-transaction information about individual trigger * states. */ ! l = deftrig_trigstates; while (l != NIL) { List *next = lnext(l); --- 2177,2183 ---- * Drop all per-transaction information about individual trigger * states. */ ! l = ts->deftrig_trigstates; while (l != NIL) { List *next = lnext(l); *************** *** 2179,2191 **** pfree(l); l = next; } ! deftrig_trigstates = NIL; /* * Set the per-transaction ALL state to known. */ ! deftrig_all_isset = true; ! deftrig_all_isdeferred = stmt->deferred; } else { --- 2186,2198 ---- pfree(l); l = next; } ! ts->deftrig_trigstates = NIL; /* * Set the per-transaction ALL state to known. */ ! ts->deftrig_all_isset = true; ! ts->deftrig_all_isdeferred = stmt->deferred; } else { *************** *** 2267,2278 **** * Inside of a transaction block set the trigger states of * individual triggers on transaction level. */ ! oldcxt = MemoryContextSwitchTo(deftrig_cxt); foreach(l, loid) { found = false; ! foreach(ls, deftrig_trigstates) { state = (DeferredTriggerStatus) lfirst(ls); if (state->dts_tgoid == lfirsto(l)) --- 2274,2285 ---- * Inside of a transaction block set the trigger states of * individual triggers on transaction level. */ ! oldcxt = MemoryContextSwitchTo(ts->deftrig_cxt); foreach(l, loid) { found = false; ! foreach(ls, ts->deftrig_trigstates) { state = (DeferredTriggerStatus) lfirst(ls); if (state->dts_tgoid == lfirsto(l)) *************** *** 2289,2296 **** state->dts_tgoid = lfirsto(l); state->dts_tgisdeferred = stmt->deferred; ! deftrig_trigstates = ! lappend(deftrig_trigstates, state); } } --- 2296,2303 ---- state->dts_tgoid = lfirsto(l); state->dts_tgisdeferred = stmt->deferred; ! ts->deftrig_trigstates = ! lappend(ts->deftrig_trigstates, state); } } *************** *** 2308,2314 **** * tail pointer to make it rescan the entire list, in case some deferred * events are now immediately invokable. */ ! deftrig_events_imm = NULL; } --- 2315,2321 ---- * tail pointer to make it rescan the entire list, in case some deferred * events are now immediately invokable. */ ! ts->deftrig_events_imm = NULL; } *************** *** 2337,2343 **** ItemPointerData oldctid; ItemPointerData newctid; ! if (deftrig_cxt == NULL) elog(ERROR, "DeferredTriggerSaveEvent() called outside of transaction"); --- 2344,2350 ---- ItemPointerData oldctid; ItemPointerData newctid; ! if (ts == NULL) elog(ERROR, "DeferredTriggerSaveEvent() called outside of transaction"); *************** *** 2387,2393 **** /* * Create a new event */ ! oldcxt = MemoryContextSwitchTo(deftrig_cxt); new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + n_enabled_triggers * sizeof(DeferredTriggerEventItem); --- 2394,2400 ---- /* * Create a new event */ ! oldcxt = MemoryContextSwitchTo(ts->deftrig_cxt); new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + n_enabled_triggers * sizeof(DeferredTriggerEventItem);