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.147 2003/03/31 20:47:51 momjian Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.148 2003/04/20 17:03:25 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -1626,12 +1626,18 @@ static List *deftrig_trigstates;
16261626 * Because this can grow pretty large, we don't use separate List nodes,
16271627 * but instead thread the list through the dte_next fields of the member
16281628 * nodes. Saves just a few bytes per entry, but that adds up.
1629+ *
1630+ * deftrig_events_imm holds the tail pointer as of the last
1631+ * deferredTriggerInvokeEvents call; we can use this to avoid rescanning
1632+ * entries unnecessarily. It is NULL if deferredTriggerInvokeEvents
1633+ * hasn't run since the last state change.
16291634 *
16301635 * XXX Need to be able to shove this data out to a file if it grows too
16311636 * large...
16321637 * ----------
16331638 */
16341639static DeferredTriggerEvent deftrig_events ;
1640+ static DeferredTriggerEvent deftrig_events_imm ;
16351641static DeferredTriggerEvent deftrig_event_tail ;
16361642
16371643
@@ -1845,7 +1851,7 @@ static void
18451851deferredTriggerInvokeEvents (bool immediate_only )
18461852{
18471853DeferredTriggerEvent event ,
1848- prev_event = NULL ;
1854+ prev_event ;
18491855MemoryContext per_tuple_context ;
18501856Relation rel = NULL ;
18511857TriggerDesc * trigdesc = NULL ;
@@ -1857,13 +1863,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
18571863 * are going to discard the whole event queue on return anyway, so no
18581864 * need to bother with "retail" pfree's.
18591865 *
1860- * In a scenario with many commands in a transaction and many
1861- * deferred-to-end-of-transaction triggers, it could get annoying to
1862- * rescan all the deferred triggers at each command end. To speed this
1863- * up, we could remember the actual end of the queue at EndQuery and
1864- * examine only events that are newer. On state changes we simply
1865- * reset the saved position to the beginning of the queue and process
1866- * all events once with the new states.
1866+ * If immediate_only is true, we need only scan from where the end of
1867+ * the queue was at the previous deferredTriggerInvokeEvents call;
1868+ * any non-deferred events before that point are already fired.
1869+ * (But if the deferral state changes, we must reset the saved position
1870+ * to the beginning of the queue, so as to process all events once with
1871+ * the new states. See DeferredTriggerSetState.)
18671872 */
18681873
18691874/* Make a per-tuple memory context for trigger function calls */
@@ -1874,7 +1879,22 @@ deferredTriggerInvokeEvents(bool immediate_only)
18741879ALLOCSET_DEFAULT_INITSIZE ,
18751880ALLOCSET_DEFAULT_MAXSIZE );
18761881
1877- event = deftrig_events ;
1882+ /*
1883+ * If immediate_only is true, then the only events that could need firing
1884+ * are those since deftrig_events_imm. (But if deftrig_events_imm is
1885+ * NULL, we must scan the entire list.)
1886+ */
1887+ if (immediate_only && deftrig_events_imm != NULL )
1888+ {
1889+ prev_event = deftrig_events_imm ;
1890+ event = prev_event -> dte_next ;
1891+ }
1892+ else
1893+ {
1894+ prev_event = NULL ;
1895+ event = deftrig_events ;
1896+ }
1897+
18781898while (event != NULL )
18791899{
18801900bool still_deferred_ones = false;
@@ -1993,6 +2013,9 @@ deferredTriggerInvokeEvents(bool immediate_only)
19932013/* Update list tail pointer in case we just deleted tail event */
19942014deftrig_event_tail = prev_event ;
19952015
2016+ /* Set the immediate event pointer for next time */
2017+ deftrig_events_imm = prev_event ;
2018+
19962019/* Release working resources */
19972020if (rel )
19982021heap_close (rel ,NoLock );
@@ -2051,6 +2074,7 @@ DeferredTriggerBeginXact(void)
20512074deftrig_trigstates = NIL ;
20522075
20532076deftrig_events = NULL ;
2077+ deftrig_events_imm = NULL ;
20542078deftrig_event_tail = NULL ;
20552079}
20562080
@@ -2280,8 +2304,11 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
22802304 * CONSTRAINTS command applies retroactively. This happens "for free"
22812305 * since we have already made the necessary modifications to the
22822306 * constraints, and deferredTriggerEndQuery() is called by
2283- * finish_xact_command().
2307+ * finish_xact_command(). But we must reset deferredTriggerInvokeEvents'
2308+ * tail pointer to make it rescan the entire list, in case some deferred
2309+ * events are now immediately invokable.
22842310 */
2311+ deftrig_events_imm = NULL ;
22852312}
22862313
22872314