Skip to content

Commit 20aa341

Browse files
pjungwirCommitfest Bot
authored andcommitted
Add tg_temporal to TriggerData
This needs to be passed to our RI triggers to implement temporal CASCADE/SET NULL/SET DEFAULT when the user command is an UPDATE/DELETE FOR PORTION OF. The triggers will use the FOR PORTION OF bounds to avoid over-applying the change to referencing records. Probably it is useful for user-defined triggers as well, for example auditing or trigger-based replication. Author: Paul A. Jungwirth <[email protected]>
1 parent 7b549b2 commit 20aa341

File tree

4 files changed

+98
-11
lines changed

4 files changed

+98
-11
lines changed

doc/src/sgml/trigger.sgml

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -563,17 +563,18 @@ CALLED_AS_TRIGGER(fcinfo)
563563
<programlisting>
564564
typedef struct TriggerData
565565
{
566-
NodeTag type;
567-
TriggerEvent tg_event;
568-
Relation tg_relation;
569-
HeapTuple tg_trigtuple;
570-
HeapTuple tg_newtuple;
571-
Trigger *tg_trigger;
572-
TupleTableSlot *tg_trigslot;
573-
TupleTableSlot *tg_newslot;
574-
Tuplestorestate *tg_oldtable;
575-
Tuplestorestate *tg_newtable;
576-
const Bitmapset *tg_updatedcols;
566+
NodeTag type;
567+
TriggerEvent tg_event;
568+
Relation tg_relation;
569+
HeapTuple tg_trigtuple;
570+
HeapTuple tg_newtuple;
571+
Trigger *tg_trigger;
572+
TupleTableSlot *tg_trigslot;
573+
TupleTableSlot *tg_newslot;
574+
Tuplestorestate *tg_oldtable;
575+
Tuplestorestate *tg_newtable;
576+
const Bitmapset *tg_updatedcols;
577+
ForPortionOfState *tg_temporal;
577578
} TriggerData;
578579
</programlisting>
579580

@@ -841,6 +842,39 @@ typedef struct Trigger
841842
</para>
842843
</listitem>
843844
</varlistentry>
845+
846+
<varlistentry>
847+
<term><structfield>tg_temporal</structfield></term>
848+
<listitem>
849+
<para>
850+
Set for <literal>UPDATE</literal> and <literal>DELETE</literal> queries
851+
that use <literal>FOR PORTION OF</literal>, otherwise <symbol>NULL</symbol>.
852+
Contains a pointer to a structure of type
853+
<structname>ForPortionOfState</structname>, defined in
854+
<filename>nodes/execnodes.h</filename>:
855+
856+
<programlisting>
857+
typedef struct ForPortionOfState
858+
{
859+
NodeTag type;
860+
861+
char *fp_rangeName; /* the column named in FOR PORTION OF */
862+
Oid fp_rangeType; /* the type of the FOR PORTION OF expression */
863+
int fp_rangeAttno; /* the attno of the range column */
864+
Datum fp_targetRange; /* the range/multirange from FOR PORTION OF */
865+
TypeCacheEntry *fp_leftoverstypcache; /* type cache entry of the range */
866+
} ForPortionOfState;
867+
</programlisting>
868+
869+
where <structfield>fp_rangeName</structfield> is the range
870+
column named in the <literal>FOR PORTION OF</literal> clause,
871+
<structfield>fp_rangeType</structfield> is its range type,
872+
<structfield>fp_rangeAttno</structfield> is its attribute number,
873+
and <structfield>fp_targetRange</structfield> is a rangetype value created
874+
by evaluating the <literal>FOR PORTION OF</literal> bounds.
875+
</para>
876+
</listitem>
877+
</varlistentry>
844878
</variablelist>
845879
</para>
846880

src/backend/commands/tablecmds.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13760,6 +13760,7 @@ validateForeignKeyConstraint(char *conname,
1376013760
trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
1376113761
trigdata.tg_trigslot = slot;
1376213762
trigdata.tg_trigger = &trig;
13763+
trigdata.tg_temporal = NULL;
1376313764

1376413765
fcinfo->context = (Node *) &trigdata;
1376513766

src/backend/commands/trigger.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@
4747
#include "storage/lmgr.h"
4848
#include "utils/acl.h"
4949
#include "utils/builtins.h"
50+
#include "utils/datum.h"
5051
#include "utils/fmgroids.h"
5152
#include "utils/guc_hooks.h"
5253
#include "utils/inval.h"
5354
#include "utils/lsyscache.h"
5455
#include "utils/memutils.h"
5556
#include "utils/plancache.h"
57+
#include "utils/rangetypes.h"
5658
#include "utils/rel.h"
5759
#include "utils/snapmgr.h"
5860
#include "utils/syscache.h"
@@ -2649,6 +2651,7 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
26492651
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
26502652
TRIGGER_EVENT_BEFORE;
26512653
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2654+
LocTriggerData.tg_temporal = relinfo->ri_forPortionOf;
26522655
for (i = 0; i < trigdesc->numtriggers; i++)
26532656
{
26542657
Trigger *trigger = &trigdesc->triggers[i];
@@ -2757,6 +2760,7 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
27572760
TRIGGER_EVENT_ROW |
27582761
TRIGGER_EVENT_BEFORE;
27592762
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2763+
LocTriggerData.tg_temporal = relinfo->ri_forPortionOf;
27602764
for (i = 0; i < trigdesc->numtriggers; i++)
27612765
{
27622766
HeapTuple newtuple;
@@ -2858,6 +2862,7 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
28582862
TRIGGER_EVENT_ROW |
28592863
TRIGGER_EVENT_INSTEAD;
28602864
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2865+
LocTriggerData.tg_temporal = relinfo->ri_forPortionOf;
28612866

28622867
ExecForceStoreHeapTuple(trigtuple, slot, false);
28632868

@@ -2921,6 +2926,7 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
29212926
TRIGGER_EVENT_BEFORE;
29222927
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
29232928
LocTriggerData.tg_updatedcols = updatedCols;
2929+
LocTriggerData.tg_temporal = relinfo->ri_forPortionOf;
29242930
for (i = 0; i < trigdesc->numtriggers; i++)
29252931
{
29262932
Trigger *trigger = &trigdesc->triggers[i];
@@ -3064,6 +3070,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
30643070
TRIGGER_EVENT_ROW |
30653071
TRIGGER_EVENT_BEFORE;
30663072
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3073+
LocTriggerData.tg_temporal = relinfo->ri_forPortionOf;
30673074
updatedCols = ExecGetAllUpdatedCols(relinfo, estate);
30683075
LocTriggerData.tg_updatedcols = updatedCols;
30693076
for (i = 0; i < trigdesc->numtriggers; i++)
@@ -3226,6 +3233,7 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
32263233
TRIGGER_EVENT_ROW |
32273234
TRIGGER_EVENT_INSTEAD;
32283235
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3236+
LocTriggerData.tg_temporal = relinfo->ri_forPortionOf;
32293237

32303238
ExecForceStoreHeapTuple(trigtuple, oldslot, false);
32313239

@@ -3697,6 +3705,7 @@ typedef struct AfterTriggerSharedData
36973705
Oid ats_relid; /* the relation it's on */
36983706
Oid ats_rolid; /* role to execute the trigger */
36993707
CommandId ats_firing_id; /* ID for firing cycle */
3708+
ForPortionOfState *for_portion_of; /* the FOR PORTION OF clause */
37003709
struct AfterTriggersTableData *ats_table; /* transition table access */
37013710
Bitmapset *ats_modifiedcols; /* modified columns */
37023711
} AfterTriggerSharedData;
@@ -3970,6 +3979,7 @@ static SetConstraintState SetConstraintStateCreate(int numalloc);
39703979
static SetConstraintState SetConstraintStateCopy(SetConstraintState origstate);
39713980
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state,
39723981
Oid tgoid, bool tgisdeferred);
3982+
static ForPortionOfState *CopyForPortionOfState(ForPortionOfState *src);
39733983
static void cancel_prior_stmt_triggers(Oid relid, CmdType cmdType, int tgevent);
39743984

39753985

@@ -4177,6 +4187,7 @@ afterTriggerAddEvent(AfterTriggerEventList *events,
41774187
newshared->ats_event == evtshared->ats_event &&
41784188
newshared->ats_firing_id == 0 &&
41794189
newshared->ats_table == evtshared->ats_table &&
4190+
newshared->for_portion_of == evtshared->for_portion_of &&
41804191
newshared->ats_relid == evtshared->ats_relid &&
41814192
newshared->ats_rolid == evtshared->ats_rolid &&
41824193
bms_equal(newshared->ats_modifiedcols,
@@ -4553,6 +4564,9 @@ AfterTriggerExecute(EState *estate,
45534564
LocTriggerData.tg_relation = rel;
45544565
if (TRIGGER_FOR_UPDATE(LocTriggerData.tg_trigger->tgtype))
45554566
LocTriggerData.tg_updatedcols = evtshared->ats_modifiedcols;
4567+
if (TRIGGER_FOR_UPDATE(LocTriggerData.tg_trigger->tgtype) ||
4568+
TRIGGER_FOR_DELETE(LocTriggerData.tg_trigger->tgtype))
4569+
LocTriggerData.tg_temporal = evtshared->for_portion_of;
45564570

45574571
MemoryContextReset(per_tuple_context);
45584572

@@ -6102,6 +6116,42 @@ AfterTriggerPendingOnRel(Oid relid)
61026116
return false;
61036117
}
61046118

6119+
/* ----------
6120+
* ForPortionOfState()
6121+
*
6122+
* Copys a ForPortionOfState into the current memory context.
6123+
*/
6124+
static ForPortionOfState *
6125+
CopyForPortionOfState(ForPortionOfState *src)
6126+
{
6127+
ForPortionOfState *dst = NULL;
6128+
6129+
if (src)
6130+
{
6131+
MemoryContext oldctx;
6132+
RangeType *r;
6133+
TypeCacheEntry *typcache;
6134+
6135+
/*
6136+
* Need to lift the FOR PORTION OF details into a higher memory
6137+
* context because cascading foreign key update/deletes can cause
6138+
* triggers to fire triggers, and the AfterTriggerEvents will outlive
6139+
* the FPO details of the original query.
6140+
*/
6141+
oldctx = MemoryContextSwitchTo(TopTransactionContext);
6142+
dst = makeNode(ForPortionOfState);
6143+
dst->fp_rangeName = pstrdup(src->fp_rangeName);
6144+
dst->fp_rangeType = src->fp_rangeType;
6145+
dst->fp_rangeAttno = src->fp_rangeAttno;
6146+
6147+
r = DatumGetRangeTypeP(src->fp_targetRange);
6148+
typcache = lookup_type_cache(RangeTypeGetOid(r), TYPECACHE_RANGE_INFO);
6149+
dst->fp_targetRange = datumCopy(src->fp_targetRange, typcache->typbyval, typcache->typlen);
6150+
MemoryContextSwitchTo(oldctx);
6151+
}
6152+
return dst;
6153+
}
6154+
61056155
/* ----------
61066156
* AfterTriggerSaveEvent()
61076157
*
@@ -6518,6 +6568,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
65186568
else
65196569
new_shared.ats_table = NULL;
65206570
new_shared.ats_modifiedcols = modifiedCols;
6571+
new_shared.for_portion_of = CopyForPortionOfState(relinfo->ri_forPortionOf);
65216572

65226573
afterTriggerAddEvent(&afterTriggers.query_stack[afterTriggers.query_depth].events,
65236574
&new_event, &new_shared);

src/include/commands/trigger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ typedef struct TriggerData
4141
Tuplestorestate *tg_oldtable;
4242
Tuplestorestate *tg_newtable;
4343
const Bitmapset *tg_updatedcols;
44+
ForPortionOfState *tg_temporal;
4445
} TriggerData;
4546

4647
/*

0 commit comments

Comments
 (0)