7
7
* Portions Copyright (c) 1994, Regents of the University of California
8
8
*
9
9
* 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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -1626,12 +1626,18 @@ static List *deftrig_trigstates;
1626
1626
* Because this can grow pretty large, we don't use separate List nodes,
1627
1627
* but instead thread the list through the dte_next fields of the member
1628
1628
* 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.
1629
1634
*
1630
1635
* XXX Need to be able to shove this data out to a file if it grows too
1631
1636
* large...
1632
1637
* ----------
1633
1638
*/
1634
1639
static DeferredTriggerEvent deftrig_events ;
1640
+ static DeferredTriggerEvent deftrig_events_imm ;
1635
1641
static DeferredTriggerEvent deftrig_event_tail ;
1636
1642
1637
1643
@@ -1845,7 +1851,7 @@ static void
1845
1851
deferredTriggerInvokeEvents (bool immediate_only )
1846
1852
{
1847
1853
DeferredTriggerEvent event ,
1848
- prev_event = NULL ;
1854
+ prev_event ;
1849
1855
MemoryContext per_tuple_context ;
1850
1856
Relation rel = NULL ;
1851
1857
TriggerDesc * trigdesc = NULL ;
@@ -1857,13 +1863,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
1857
1863
* are going to discard the whole event queue on return anyway, so no
1858
1864
* need to bother with "retail" pfree's.
1859
1865
*
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.)
1867
1872
*/
1868
1873
1869
1874
/* Make a per-tuple memory context for trigger function calls */
@@ -1874,7 +1879,22 @@ deferredTriggerInvokeEvents(bool immediate_only)
1874
1879
ALLOCSET_DEFAULT_INITSIZE ,
1875
1880
ALLOCSET_DEFAULT_MAXSIZE );
1876
1881
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
+
1878
1898
while (event != NULL )
1879
1899
{
1880
1900
bool still_deferred_ones = false;
@@ -1993,6 +2013,9 @@ deferredTriggerInvokeEvents(bool immediate_only)
1993
2013
/* Update list tail pointer in case we just deleted tail event */
1994
2014
deftrig_event_tail = prev_event ;
1995
2015
2016
+ /* Set the immediate event pointer for next time */
2017
+ deftrig_events_imm = prev_event ;
2018
+
1996
2019
/* Release working resources */
1997
2020
if (rel )
1998
2021
heap_close (rel , NoLock );
@@ -2051,6 +2074,7 @@ DeferredTriggerBeginXact(void)
2051
2074
deftrig_trigstates = NIL ;
2052
2075
2053
2076
deftrig_events = NULL ;
2077
+ deftrig_events_imm = NULL ;
2054
2078
deftrig_event_tail = NULL ;
2055
2079
}
2056
2080
@@ -2280,8 +2304,11 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
2280
2304
* CONSTRAINTS command applies retroactively. This happens "for free"
2281
2305
* since we have already made the necessary modifications to the
2282
2306
* 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.
2284
2310
*/
2311
+ deftrig_events_imm = NULL ;
2285
2312
}
2286
2313
2287
2314
0 commit comments