From 65158f497a7d7523ad438b2034d01a560fafe6bd Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 30 Mar 2021 20:01:27 -0400 Subject: [PATCH] Remove small inefficiency in ExecARDeleteTriggers/ExecARUpdateTriggers. Whilst poking at nodeModifyTable.c, I chanced to notice that while its calls to ExecBR*Triggers and ExecIR*Triggers are protected by tests to see if there are any relevant triggers to fire, its calls to ExecAR*Triggers are not; the latter functions do the equivalent tests themselves. This seems possibly reasonable given the more complex conditions involved, but what's less reasonable is that the ExecAR* functions aren't careful to do no work when there is no work to be done. ExecARInsertTriggers gets this right, but the other two will both force creation of a slot that the query may have no use for. ExecARUpdateTriggers additionally performed a usually-useless ExecClearTuple() on that slot. This is probably all pretty microscopic in real workloads, but a cycle shaved is a cycle earned. --- src/backend/commands/trigger.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 7383d5994ebed..0ee318b340991 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -2546,11 +2546,12 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo); if ((trigdesc && trigdesc->trig_delete_after_row) || (transition_capture && transition_capture->tcs_delete_old_table)) { + TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo); + Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid)); if (fdw_trigtuple == NULL) GetTupleForTrigger(estate, @@ -2829,9 +2830,6 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo); - - ExecClearTuple(oldslot); if ((trigdesc && trigdesc->trig_update_after_row) || (transition_capture && @@ -2844,6 +2842,8 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, * separately for DELETE and INSERT to capture transition table rows. * In such case, either old tuple or new tuple can be NULL. */ + TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo); + if (fdw_trigtuple == NULL && ItemPointerIsValid(tupleid)) GetTupleForTrigger(estate, NULL, @@ -2854,6 +2854,8 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, NULL); else if (fdw_trigtuple != NULL) ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false); + else + ExecClearTuple(oldslot); AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE, true, oldslot, newslot, recheckIndexes,