From a713a831c464cd629ffc9d8627199b9ab88a41ba Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 24 Feb 2020 10:12:10 +0100 Subject: [PATCH 2/2] Add tg_updatedcols to TriggerData This allows a trigger function to determine for an UPDATE trigger which columns were actually updated. This allows some optimizations in generic trigger functions such as lo_manage and tsvector_update_trigger. --- contrib/lo/lo.c | 3 ++- doc/src/sgml/trigger.sgml | 20 ++++++++++++++++++++ src/backend/commands/trigger.c | 6 ++++++ src/backend/utils/adt/tsvector_op.c | 29 +++++++++++++++++++++-------- src/include/commands/trigger.h | 1 + 5 files changed, 50 insertions(+), 9 deletions(-) diff --git a/contrib/lo/lo.c b/contrib/lo/lo.c index 4585923ee2..b9847081db 100644 --- a/contrib/lo/lo.c +++ b/contrib/lo/lo.c @@ -74,7 +74,8 @@ lo_manage(PG_FUNCTION_ARGS) * Here, if the value of the monitored attribute changes, then the large * object associated with the original value is unlinked. */ - if (newtuple != NULL) + if (newtuple != NULL && + bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols)) { char *orig = SPI_getvalue(trigtuple, tupdesc, attnum); char *newv = SPI_getvalue(newtuple, tupdesc, attnum); diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml index ba94acad69..bda7866ecb 100644 --- a/doc/src/sgml/trigger.sgml +++ b/doc/src/sgml/trigger.sgml @@ -515,6 +515,7 @@ Writing Trigger Functions in C TupleTableSlot *tg_newslot; Tuplestorestate *tg_oldtable; Tuplestorestate *tg_newtable; + const Bitmapset *tg_updatedcols; } TriggerData; @@ -757,6 +758,25 @@ Writing Trigger Functions in C + + tg_updatedcols + + + For UPDATE triggers, a bitmap set indicating the + columns that were updated by the triggering command. Generic trigger + functions can use this to optimize actions by not having to deal with + columns that were not changed. + + + + As an example, to determine whether a column with attribute number + attnum (1-based) is a member of this bitmap set, + call bms_is_member(attnum - + FirstLowInvalidHeapAttributeNumber, + trigdata->tg_updatedcols)). + + + diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 26593576fd..9bb5afc8d9 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -2909,6 +2909,7 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; + LocTriggerData.tg_updatedcols = updatedCols; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -3017,6 +3018,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; updatedCols = GetAllUpdatedColumns(relinfo, estate); + LocTriggerData.tg_updatedcols = updatedCols; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -3573,6 +3575,7 @@ typedef struct AfterTriggerSharedData Oid ats_relid; /* the relation it's on */ CommandId ats_firing_id; /* ID for firing cycle */ struct AfterTriggersTableData *ats_table; /* transition table access */ + Bitmapset *ats_modifiedcols; /* modified columns */ } AfterTriggerSharedData; typedef struct AfterTriggerEventData *AfterTriggerEvent; @@ -4272,6 +4275,8 @@ AfterTriggerExecute(EState *estate, LocTriggerData.tg_event = evtshared->ats_event & (TRIGGER_EVENT_OPMASK | TRIGGER_EVENT_ROW); LocTriggerData.tg_relation = rel; + if (TRIGGER_FOR_UPDATE(LocTriggerData.tg_trigger->tgtype)) + LocTriggerData.tg_updatedcols = evtshared->ats_modifiedcols; MemoryContextReset(per_tuple_context); @@ -5959,6 +5964,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, new_shared.ats_table = transition_capture->tcs_private; else new_shared.ats_table = NULL; + new_shared.ats_modifiedcols = modifiedCols; afterTriggerAddEvent(&afterTriggers.query_stack[afterTriggers.query_depth].events, &new_event, &new_shared); diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index cab6874e70..784132aecf 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -2416,6 +2416,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) bool isnull; text *txt; Oid cfgId; + bool update_needed; /* Check call context */ if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */ @@ -2428,9 +2429,15 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) elog(ERROR, "tsvector_update_trigger: must be fired BEFORE event"); if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) + { rettuple = trigdata->tg_trigtuple; + update_needed = true; + } else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) + { rettuple = trigdata->tg_newtuple; + update_needed = false; /* computed below */ + } else elog(ERROR, "tsvector_update_trigger: must be fired for INSERT or UPDATE"); @@ -2518,6 +2525,9 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) errmsg("column \"%s\" is not of a character type", trigger->tgargs[i]))); + if (bms_is_member(numattr - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols)) + update_needed = true; + datum = SPI_getbinval(rettuple, rel->rd_att, numattr, &isnull); if (isnull) continue; @@ -2530,16 +2540,19 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) pfree(txt); } - /* make tsvector value */ - datum = TSVectorGetDatum(make_tsvector(&prs)); - isnull = false; + if (update_needed) + { + /* make tsvector value */ + datum = TSVectorGetDatum(make_tsvector(&prs)); + isnull = false; - /* and insert it into tuple */ - rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, - 1, &tsvector_attr_num, - &datum, &isnull); + /* and insert it into tuple */ + rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, + 1, &tsvector_attr_num, + &datum, &isnull); - pfree(DatumGetPointer(datum)); + pfree(DatumGetPointer(datum)); + } return PointerGetDatum(rettuple); } diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index 5d69192643..a40ddf5db5 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -39,6 +39,7 @@ typedef struct TriggerData TupleTableSlot *tg_newslot; Tuplestorestate *tg_oldtable; Tuplestorestate *tg_newtable; + const Bitmapset *tg_updatedcols; } TriggerData; /* -- 2.25.0