Index: src/backend/commands/trigger.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/trigger.c,v retrieving revision 1.147 diff -c -r1.147 trigger.c *** src/backend/commands/trigger.c 2003/03/31 20:47:51 1.147 --- src/backend/commands/trigger.c 2003/04/20 16:01:55 *************** *** 1626,1637 **** --- 1626,1643 ---- * Because this can grow pretty large, we don't use separate List nodes, * but instead thread the list through the dte_next fields of the member * nodes. Saves just a few bytes per entry, but that adds up. + * + * deftrig_events_imm holds the tail pointer as of the last + * deferredTriggerInvokeEvents call, since generally immediate triggers + * can't exist before this point (since they should already have been + * called) excepting SET CONSTRAINTS * * XXX Need to be able to shove this data out to a file if it grows too * large... * ---------- */ static DeferredTriggerEvent deftrig_events; + static DeferredTriggerEvent deftrig_events_imm; static DeferredTriggerEvent deftrig_event_tail; *************** *** 1844,1850 **** static void deferredTriggerInvokeEvents(bool immediate_only) { ! DeferredTriggerEvent event, prev_event = NULL; MemoryContext per_tuple_context; Relation rel = NULL; --- 1850,1856 ---- static void deferredTriggerInvokeEvents(bool immediate_only) { ! DeferredTriggerEvent event = NULL, prev_event = NULL; MemoryContext per_tuple_context; Relation rel = NULL; *************** *** 1857,1880 **** * are going to discard the whole event queue on return anyway, so no * need to bother with "retail" pfree's. * ! * In a scenario with many commands in a transaction and many ! * deferred-to-end-of-transaction triggers, it could get annoying to ! * rescan all the deferred triggers at each command end. To speed this ! * up, we could remember the actual end of the queue at EndQuery and ! * examine only events that are newer. On state changes we simply ! * reset the saved position to the beginning of the queue and process ! * all events once with the new states. */ /* Make a per-tuple memory context for trigger function calls */ per_tuple_context = AllocSetContextCreate(CurrentMemoryContext, ! "DeferredTriggerTupleContext", ! ALLOCSET_DEFAULT_MINSIZE, ! ALLOCSET_DEFAULT_INITSIZE, ! ALLOCSET_DEFAULT_MAXSIZE); - event = deftrig_events; while (event != NULL) { bool still_deferred_ones = false; --- 1863,1894 ---- * are going to discard the whole event queue on return anyway, so no * need to bother with "retail" pfree's. * ! * In immediate_only is true, we only check from the end of the queue ! * at the previous InvokeEvents and examine newer events. On state ! * changes we simply reset the saved position to the beginning of ! * the queue and process all events once with the new states. */ /* Make a per-tuple memory context for trigger function calls */ per_tuple_context = AllocSetContextCreate(CurrentMemoryContext, ! "DeferredTriggerTupleContext", ! ALLOCSET_DEFAULT_MINSIZE, ! ALLOCSET_DEFAULT_INITSIZE, ! ALLOCSET_DEFAULT_MAXSIZE); ! ! /* ! * If immediate_only is true, then the only events that could have fired ! * are those since deftrig_events_imm. ! * The one exception to only since deftrig_events_imm would be ! * SET CONSTRAINTS ... IMMEDIATE so we set it to NULL in there ! * and treat NULL as being equivalent to the entire list. ! */ ! if (immediate_only) ! event = deftrig_events_imm; ! if (event == NULL) ! event = deftrig_events; while (event != NULL) { bool still_deferred_ones = false; *************** *** 1993,2004 **** --- 2007,2022 ---- /* Update list tail pointer in case we just deleted tail event */ deftrig_event_tail = prev_event; + /* Set the immediate event pointer to the tail */ + deftrig_events_imm = prev_event; + /* Release working resources */ if (rel) heap_close(rel, NoLock); FreeTriggerDesc(trigdesc); if (finfo) pfree(finfo); + MemoryContextDelete(per_tuple_context); } *************** *** 2272,2277 **** --- 2290,2303 ---- MemoryContextSwitchTo(oldcxt); } + + /* + * Reset the pointer for the immediate constraints to NULL (ie + * use beginning of list). This is really only necessary for + * dealing when setting to IMMEDIATE, and could really point + * the first constraint we changed, but for now this will do. + */ + deftrig_events_imm = NULL; /* * SQL99 requires that when a constraint is set to IMMEDIATE, any