In an attempt to simplify my life I'm submitting this patch that
authorBruce Momjian
Tue, 24 Jun 2003 23:25:44 +0000 (23:25 +0000)
committerBruce Momjian
Tue, 24 Jun 2003 23:25:44 +0000 (23:25 +0000)
restructures the deferred trigger queue.  The fundamental change is to
put all the static variables to hold the deferred triggers in a single
structure.

Alvaro Herrera

src/backend/commands/trigger.c

index 8a62986ec445906345aa448d4c6d3a83fbf2bad6..db30014bf9bef6048310844bdd9140ccb866ebe8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.148 2003/04/20 17:03:25 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.149 2003/06/24 23:25:44 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1601,25 +1601,22 @@ ltrmark:;
  * ----------
  */
 
-
-/*
- * 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;
+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,10 +1633,10 @@ static List *deftrig_trigstates;
  *    large...
  * ----------
  */
-static DeferredTriggerEvent deftrig_events;
-static DeferredTriggerEvent deftrig_events_imm;
-static DeferredTriggerEvent deftrig_event_tail;
 
+typedef DeferredTriggersData *DeferredTriggers;
+
+static DeferredTriggers    deferredTriggers;
 
 /* ----------
  * deferredTriggerCheckState()
@@ -1665,7 +1662,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
    /*
     * Lookup if we know an individual state for this trigger
     */
-   foreach(sl, deftrig_trigstates)
+   foreach(sl, deferredTriggers->deftrig_trigstates)
    {
        trigstate = (DeferredTriggerStatus) lfirst(sl);
        if (trigstate->dts_tgoid == tgoid)
@@ -1676,21 +1673,22 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
     * 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;
+   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(deftrig_cxt);
+   oldcxt = MemoryContextSwitchTo(deferredTriggers->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);
+   deferredTriggers->deftrig_trigstates =
+       lappend(deferredTriggers->deftrig_trigstates, trigstate);
 
    MemoryContextSwitchTo(oldcxt);
 
@@ -1713,16 +1711,16 @@ deferredTriggerAddEvent(DeferredTriggerEvent event)
     * "lappend". This avoids O(N^2) behavior for large numbers of events.
     */
    event->dte_next = NULL;
-   if (deftrig_event_tail == NULL)
+   if (deferredTriggers->deftrig_event_tail == NULL)
    {
        /* first list entry */
-       deftrig_events = event;
-       deftrig_event_tail = event;
+       deferredTriggers->deftrig_events = event;
+       deferredTriggers->deftrig_event_tail = event;
    }
    else
    {
-       deftrig_event_tail->dte_next = event;
-       deftrig_event_tail = event;
+       deferredTriggers->deftrig_event_tail->dte_next = event;
+       deferredTriggers->deftrig_event_tail = event;
    }
 }
 
@@ -1884,15 +1882,15 @@ deferredTriggerInvokeEvents(bool immediate_only)
     * 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)
+   if (immediate_only && deferredTriggers->deftrig_events_imm != NULL)
    {
-       prev_event = deftrig_events_imm;
+       prev_event = deferredTriggers->deftrig_events_imm;
        event = prev_event->dte_next;
    }
    else
    {
        prev_event = NULL;
-       event = deftrig_events;
+       event = deferredTriggers->deftrig_events;
    }
 
    while (event != NULL)
@@ -1994,7 +1992,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
                if (prev_event)
                    prev_event->dte_next = next_event;
                else
-                   deftrig_events = next_event;
+                   deferredTriggers->deftrig_events = next_event;
                pfree(event);
            }
            else
@@ -2011,10 +2009,10 @@ deferredTriggerInvokeEvents(bool immediate_only)
    }
 
    /* Update list tail pointer in case we just deleted tail event */
-   deftrig_event_tail = prev_event;
+   deferredTriggers->deftrig_event_tail = prev_event;
 
    /* Set the immediate event pointer for next time */
-   deftrig_events_imm = prev_event;
+   deferredTriggers->deftrig_events_imm = prev_event;
 
    /* Release working resources */
    if (rel)
@@ -2052,30 +2050,32 @@ DeferredTriggerInit(void)
 void
 DeferredTriggerBeginXact(void)
 {
-   if (deftrig_cxt != NULL)
-       elog(ERROR,
-          "DeferredTriggerBeginXact() called while inside transaction");
+   /*
+    * 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
     */
-   deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
+   deferredTriggers->deftrig_cxt = AllocSetContextCreate(cxt,
                                        "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;
+   deferredTriggers->deftrig_all_isdeferred = false;
+   deferredTriggers->deftrig_all_isset = false;
 
-   deftrig_trigstates = NIL;
-
-   deftrig_events = NULL;
-   deftrig_events_imm = NULL;
-   deftrig_event_tail = NULL;
+   deferredTriggers->deftrig_trigstates = NIL;
+   deferredTriggers->deftrig_events = NULL;
+   deferredTriggers->deftrig_events_imm = NULL;
+   deferredTriggers->deftrig_event_tail = NULL;
 }
 
 
@@ -2092,7 +2092,7 @@ DeferredTriggerEndQuery(void)
    /*
     * Ignore call if we aren't in a transaction.
     */
-   if (deftrig_cxt == NULL)
+   if (deferredTriggers == NULL)
        return;
 
    deferredTriggerInvokeEvents(true);
@@ -2112,13 +2112,12 @@ DeferredTriggerEndXact(void)
    /*
     * Ignore call if we aren't in a transaction.
     */
-   if (deftrig_cxt == NULL)
+   if (deferredTriggers == NULL)
        return;
 
    deferredTriggerInvokeEvents(false);
 
-   MemoryContextDelete(deftrig_cxt);
-   deftrig_cxt = NULL;
+   deferredTriggers = NULL;
 }
 
 
@@ -2136,11 +2135,13 @@ DeferredTriggerAbortXact(void)
    /*
     * Ignore call if we aren't in a transaction.
     */
-   if (deftrig_cxt == NULL)
-       return;
+   if (deferredTriggers == NULL)
+           return;
 
-   MemoryContextDelete(deftrig_cxt);
-   deftrig_cxt = NULL;
+   /*
+    * Forget everything we know about deferred triggers.
+    */
+   deferredTriggers = NULL;
 }
 
 
@@ -2158,7 +2159,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
    /*
     * Ignore call if we aren't in a transaction.
     */
-   if (deftrig_cxt == NULL)
+   if (deferredTriggers == NULL)
        return;
 
    /*
@@ -2170,7 +2171,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
         * Drop all per-transaction information about individual trigger
         * states.
         */
-       l = deftrig_trigstates;
+       l = deferredTriggers->deftrig_trigstates;
        while (l != NIL)
        {
            List       *next = lnext(l);
@@ -2179,13 +2180,13 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
            pfree(l);
            l = next;
        }
-       deftrig_trigstates = NIL;
+       deferredTriggers->deftrig_trigstates = NIL;
 
        /*
         * Set the per-transaction ALL state to known.
         */
-       deftrig_all_isset = true;
-       deftrig_all_isdeferred = stmt->deferred;
+       deferredTriggers->deftrig_all_isset = true;
+       deferredTriggers->deftrig_all_isdeferred = stmt->deferred;
    }
    else
    {
@@ -2267,12 +2268,12 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
         * Inside of a transaction block set the trigger states of
         * individual triggers on transaction level.
         */
-       oldcxt = MemoryContextSwitchTo(deftrig_cxt);
+       oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt);
 
        foreach(l, loid)
        {
            found = false;
-           foreach(ls, deftrig_trigstates)
+           foreach(ls, deferredTriggers->deftrig_trigstates)
            {
                state = (DeferredTriggerStatus) lfirst(ls);
                if (state->dts_tgoid == lfirsto(l))
@@ -2289,8 +2290,8 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
                state->dts_tgoid = lfirsto(l);
                state->dts_tgisdeferred = stmt->deferred;
 
-               deftrig_trigstates =
-                   lappend(deftrig_trigstates, state);
+               deferredTriggers->deftrig_trigstates =
+                   lappend(deferredTriggers->deftrig_trigstates, state);
            }
        }
 
@@ -2308,7 +2309,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
     * tail pointer to make it rescan the entire list, in case some deferred
     * events are now immediately invokable.
     */
-   deftrig_events_imm = NULL;
+   deferredTriggers->deftrig_events_imm = NULL;
 }
 
 
@@ -2337,7 +2338,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
    ItemPointerData oldctid;
    ItemPointerData newctid;
 
-   if (deftrig_cxt == NULL)
+   if (deferredTriggers == NULL)
        elog(ERROR,
             "DeferredTriggerSaveEvent() called outside of transaction");
 
@@ -2387,7 +2388,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
    /*
     * Create a new event
     */
-   oldcxt = MemoryContextSwitchTo(deftrig_cxt);
+   oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt);
 
    new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
        n_enabled_triggers * sizeof(DeferredTriggerEventItem);