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 11 Jun 2003 21:18:41 -0000 *************** *** 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,1622 ---- * ---------- */ ! typedef struct DeferredTriggersData { ! /* 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; ! } DeferredTriggersData; /* ---------- + * 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() --- 1633,1642 ---- * large... * ---------- */ + typedef DeferredTriggersData *DeferredTriggers; + + static DeferredTriggers deferredTriggers; /* ---------- * 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, deferredTriggers->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,1694 ---- * No individual state known - so if the user issued a SET CONSTRAINT * ALL ..., we return that instead of the triggers default state. */ ! if (deferredTriggers->deftrig_all_isset) ! return deferredTriggers->deftrig_all_isdeferred; /* * No ALL state known either, remember the default state as the * current and return that. */ ! oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt); trigstate = (DeferredTriggerStatus) palloc(sizeof(DeferredTriggerStatusData)); trigstate->dts_tgoid = tgoid; trigstate->dts_tgisdeferred = ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0); ! deferredTriggers->deftrig_trigstates = ! lappend(deferredTriggers->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; } } --- 1711,1726 ---- * "lappend". This avoids O(N^2) behavior for large numbers of events. */ event->dte_next = NULL; ! if (deferredTriggers->deftrig_event_tail == NULL) { /* first list entry */ ! deferredTriggers->deftrig_events = event; ! deferredTriggers->deftrig_event_tail = event; } else { ! deferredTriggers->deftrig_event_tail->dte_next = event; ! deferredTriggers->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) --- 1882,1896 ---- * are those since deftrig_events_imm. (But if deftrig_events_imm is * NULL, we must scan the entire list.) */ ! if (immediate_only && deferredTriggers->deftrig_events_imm != NULL) { ! prev_event = deferredTriggers->deftrig_events_imm; event = prev_event->dte_next; } else { prev_event = NULL; ! event = deferredTriggers->deftrig_events; } while (event != NULL) *************** *** 1994,2000 **** if (prev_event) prev_event->dte_next = next_event; else ! deftrig_events = next_event; pfree(event); } else --- 1992,1998 ---- if (prev_event) prev_event->dte_next = next_event; else ! deferredTriggers->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) --- 2009,2018 ---- } /* Update list tail pointer in case we just deleted tail event */ ! deferredTriggers->deftrig_event_tail = prev_event; /* Set the immediate event pointer for next time */ ! deferredTriggers->deftrig_events_imm = prev_event; /* Release working resources */ if (rel) *************** *** 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; } --- 2050,2081 ---- void DeferredTriggerBeginXact(void) { ! /* ! * This will be changed to a special context when ! * the nested transactions project moves forward. ! */ ! MemoryContext cxt = TopTransactionContext; ! deferredTriggers = (DeferredTriggers) MemoryContextAlloc(TopTransactionContext, ! sizeof(DeferredTriggersData)); /* * Create the per transaction memory context */ ! deferredTriggers->deftrig_cxt = AllocSetContextCreate(cxt, "DeferredTriggerXact", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * If unspecified, constraints default to IMMEDIATE, per SQL */ ! deferredTriggers->deftrig_all_isdeferred = false; ! deferredTriggers->deftrig_all_isset = false; ! deferredTriggers->deftrig_trigstates = NIL; ! deferredTriggers->deftrig_events = NULL; ! deferredTriggers->deftrig_events_imm = NULL; ! deferredTriggers->deftrig_event_tail = NULL; } *************** *** 2092,2098 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; deferredTriggerInvokeEvents(true); --- 2092,2098 ---- /* * Ignore call if we aren't in a transaction. */ ! if (deferredTriggers == 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; } --- 2112,2123 ---- /* * Ignore call if we aren't in a transaction. */ ! if (deferredTriggers == NULL) return; deferredTriggerInvokeEvents(false); ! deferredTriggers = NULL; } *************** *** 2136,2146 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) ! return; ! MemoryContextDelete(deftrig_cxt); ! deftrig_cxt = NULL; } --- 2135,2147 ---- /* * Ignore call if we aren't in a transaction. */ ! if (deferredTriggers == NULL) ! return; ! /* ! * Forget everything we know about deferred triggers. ! */ ! deferredTriggers = NULL; } *************** *** 2158,2164 **** /* * Ignore call if we aren't in a transaction. */ ! if (deftrig_cxt == NULL) return; /* --- 2159,2165 ---- /* * Ignore call if we aren't in a transaction. */ ! if (deferredTriggers == NULL) return; /* *************** *** 2170,2176 **** * Drop all per-transaction information about individual trigger * states. */ ! l = deftrig_trigstates; while (l != NIL) { List *next = lnext(l); --- 2171,2177 ---- * Drop all per-transaction information about individual trigger * states. */ ! l = deferredTriggers->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 { --- 2180,2192 ---- pfree(l); l = next; } ! deferredTriggers->deftrig_trigstates = NIL; /* * Set the per-transaction ALL state to known. */ ! deferredTriggers->deftrig_all_isset = true; ! deferredTriggers->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)) --- 2268,2279 ---- * Inside of a transaction block set the trigger states of * individual triggers on transaction level. */ ! oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt); foreach(l, loid) { found = false; ! foreach(ls, deferredTriggers->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); } } --- 2290,2297 ---- state->dts_tgoid = lfirsto(l); state->dts_tgisdeferred = stmt->deferred; ! deferredTriggers->deftrig_trigstates = ! lappend(deferredTriggers->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; } --- 2309,2315 ---- * tail pointer to make it rescan the entire list, in case some deferred * events are now immediately invokable. */ ! deferredTriggers->deftrig_events_imm = NULL; } *************** *** 2337,2343 **** ItemPointerData oldctid; ItemPointerData newctid; ! if (deftrig_cxt == NULL) elog(ERROR, "DeferredTriggerSaveEvent() called outside of transaction"); --- 2338,2344 ---- ItemPointerData oldctid; ItemPointerData newctid; ! if (deferredTriggers == 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); --- 2388,2394 ---- /* * Create a new event */ ! oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt); new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + n_enabled_triggers * sizeof(DeferredTriggerEventItem);