aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r--src/backend/commands/trigger.c673
1 files changed, 348 insertions, 325 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 7e5bf0d27f8..c5e588e8011 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -79,16 +79,17 @@ static int MyTriggerDepth = 0;
/* Local function prototypes */
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid);
static void SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger);
-static HeapTuple GetTupleForTrigger(EState *estate,
+static bool GetTupleForTrigger(EState *estate,
EPQState *epqstate,
ResultRelInfo *relinfo,
ItemPointer tid,
LockTupleMode lockmode,
+ TupleTableSlot *oldslot,
TupleTableSlot **newSlot);
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
Trigger *trigger, TriggerEvent event,
Bitmapset *modifiedCols,
- HeapTuple oldtup, HeapTuple newtup);
+ TupleTableSlot *oldslot, TupleTableSlot *newslot);
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
int tgindx,
FmgrInfo *finfo,
@@ -96,7 +97,7 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
MemoryContext per_tuple_context);
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
int event, bool row_trigger,
- HeapTuple oldtup, HeapTuple newtup,
+ TupleTableSlot *oldtup, TupleTableSlot *newtup,
List *recheckIndexes, Bitmapset *modifiedCols,
TransitionCaptureState *transition_capture);
static void AfterTriggerEnlargeQueryState(void);
@@ -2467,10 +2468,10 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
@@ -2510,15 +2511,13 @@ ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo,
false, NULL, NULL, NIL, NULL, transition_capture);
}
-TupleTableSlot *
+bool
ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ HeapTuple newtuple = false;
bool should_free;
- HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
- HeapTuple newtuple = slottuple;
- HeapTuple oldtuple;
TriggerData LocTriggerData;
int i;
@@ -2527,13 +2526,16 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TRIGGER_EVENT_ROW |
TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
+ HeapTuple oldtuple;
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
TRIGGER_TYPE_ROW,
@@ -2541,52 +2543,44 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TRIGGER_TYPE_INSERT))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- NULL, NULL, newtuple))
+ NULL, NULL, slot))
continue;
+ if (!newtuple)
+ newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
+
+ LocTriggerData.tg_trigslot = slot;
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
- if (oldtuple != newtuple && oldtuple != slottuple)
- heap_freetuple(oldtuple);
if (newtuple == NULL)
{
if (should_free)
- heap_freetuple(slottuple);
- return NULL; /* "do nothing" */
+ heap_freetuple(oldtuple);
+ return false; /* "do nothing" */
}
- }
+ else if (newtuple != oldtuple)
+ {
+ ExecForceStoreHeapTuple(newtuple, slot);
- if (newtuple != slottuple)
- {
- /*
- * Return the modified tuple using the es_trig_tuple_slot. We assume
- * the tuple was allocated in per-tuple memory context, and therefore
- * will go away by itself. The tuple table slot should not try to
- * clear it.
- */
- TupleTableSlot *newslot = estate->es_trig_tuple_slot;
- TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
+ if (should_free)
+ heap_freetuple(oldtuple);
- if (newslot->tts_tupleDescriptor != tupdesc)
- ExecSetSlotDescriptor(newslot, tupdesc);
- ExecStoreHeapTuple(newtuple, newslot, false);
- slot = newslot;
+ /* signal tuple should be re-fetched if used */
+ newtuple = NULL;
+ }
}
- if (should_free)
- heap_freetuple(slottuple);
- return slot;
+ return true;
}
void
ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
- HeapTuple trigtuple, List *recheckIndexes,
+ TupleTableSlot *slot, List *recheckIndexes,
TransitionCaptureState *transition_capture)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
@@ -2594,20 +2588,18 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
if ((trigdesc && trigdesc->trig_insert_after_row) ||
(transition_capture && transition_capture->tcs_insert_new_table))
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
- true, NULL, trigtuple,
+ true, NULL, slot,
recheckIndexes, NULL,
transition_capture);
}
-TupleTableSlot *
+bool
ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ HeapTuple newtuple = NULL;
bool should_free;
- HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
- HeapTuple newtuple = slottuple;
- HeapTuple oldtuple;
TriggerData LocTriggerData;
int i;
@@ -2616,13 +2608,16 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TRIGGER_EVENT_ROW |
TRIGGER_EVENT_INSTEAD;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
+ HeapTuple oldtuple;
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
TRIGGER_TYPE_ROW,
@@ -2630,47 +2625,39 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TRIGGER_TYPE_INSERT))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- NULL, NULL, newtuple))
+ NULL, NULL, slot))
continue;
+ if (!newtuple)
+ newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
+
+ LocTriggerData.tg_trigslot = slot;
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
- if (oldtuple != newtuple && oldtuple != slottuple)
- heap_freetuple(oldtuple);
if (newtuple == NULL)
{
if (should_free)
- heap_freetuple(slottuple);
- return NULL; /* "do nothing" */
+ heap_freetuple(oldtuple);
+ return false; /* "do nothing" */
}
- }
+ else if (newtuple != oldtuple)
+ {
+ ExecForceStoreHeapTuple(newtuple, slot);
- if (newtuple != slottuple)
- {
- /*
- * Return the modified tuple using the es_trig_tuple_slot. We assume
- * the tuple was allocated in per-tuple memory context, and therefore
- * will go away by itself. The tuple table slot should not try to
- * clear it.
- */
- TupleTableSlot *newslot = estate->es_trig_tuple_slot;
- TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
+ if (should_free)
+ heap_freetuple(oldtuple);
- if (newslot->tts_tupleDescriptor != tupdesc)
- ExecSetSlotDescriptor(newslot, tupdesc);
- ExecStoreHeapTuple(newtuple, newslot, false);
- slot = newslot;
+ /* signal tuple should be re-fetched if used */
+ newtuple = NULL;
+ }
}
- if (should_free)
- heap_freetuple(slottuple);
- return slot;
+ return true;
}
void
@@ -2698,10 +2685,10 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
@@ -2755,20 +2742,21 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
HeapTuple fdw_trigtuple,
TupleTableSlot **epqslot)
{
+ TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
bool result = true;
TriggerData LocTriggerData;
HeapTuple trigtuple;
- HeapTuple newtuple;
- TupleTableSlot *newSlot;
+ bool should_free = false;
int i;
Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
if (fdw_trigtuple == NULL)
{
- trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
- LockTupleExclusive, &newSlot);
- if (trigtuple == NULL)
+ TupleTableSlot *newSlot;
+
+ if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
+ LockTupleExclusive, slot, &newSlot))
return false;
/*
@@ -2779,24 +2767,32 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
if (newSlot != NULL && epqslot != NULL)
{
*epqslot = newSlot;
- heap_freetuple(trigtuple);
return false;
}
+
+ trigtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
+
}
else
+ {
trigtuple = fdw_trigtuple;
+ ExecForceStoreHeapTuple(trigtuple, slot);
+ }
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
TRIGGER_EVENT_ROW |
TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
+ HeapTuple newtuple;
Trigger *trigger = &trigdesc->triggers[i];
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
@@ -2805,11 +2801,11 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
TRIGGER_TYPE_DELETE))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- NULL, trigtuple, NULL))
+ NULL, slot, NULL))
continue;
+ LocTriggerData.tg_trigslot = slot;
LocTriggerData.tg_trigtuple = trigtuple;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
@@ -2824,7 +2820,7 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
if (newtuple != trigtuple)
heap_freetuple(newtuple);
}
- if (trigtuple != fdw_trigtuple)
+ if (should_free)
heap_freetuple(trigtuple);
return result;
@@ -2837,28 +2833,26 @@ 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))
{
- HeapTuple trigtuple;
-
Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
if (fdw_trigtuple == NULL)
- trigtuple = GetTupleForTrigger(estate,
- NULL,
- relinfo,
- tupleid,
- LockTupleExclusive,
- NULL);
+ GetTupleForTrigger(estate,
+ NULL,
+ relinfo,
+ tupleid,
+ LockTupleExclusive,
+ slot,
+ NULL);
else
- trigtuple = fdw_trigtuple;
+ ExecForceStoreHeapTuple(fdw_trigtuple, slot);
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
- true, trigtuple, NULL, NIL, NULL,
+ true, slot, NULL, NIL, NULL,
transition_capture);
- if (trigtuple != fdw_trigtuple)
- heap_freetuple(trigtuple);
}
}
@@ -2867,8 +2861,8 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
HeapTuple trigtuple)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
TriggerData LocTriggerData;
- HeapTuple rettuple;
int i;
LocTriggerData.type = T_TriggerData;
@@ -2876,12 +2870,18 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
TRIGGER_EVENT_ROW |
TRIGGER_EVENT_INSTEAD;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+
+ ExecForceStoreHeapTuple(trigtuple, slot);
+
for (i = 0; i < trigdesc->numtriggers; i++)
{
+ HeapTuple rettuple;
Trigger *trigger = &trigdesc->triggers[i];
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
@@ -2890,11 +2890,11 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
TRIGGER_TYPE_DELETE))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- NULL, trigtuple, NULL))
+ NULL, slot, NULL))
continue;
+ LocTriggerData.tg_trigslot = slot;
LocTriggerData.tg_trigtuple = trigtuple;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
rettuple = ExecCallTriggerFunc(&LocTriggerData,
i,
@@ -2937,10 +2937,10 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
@@ -2982,20 +2982,20 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
transition_capture);
}
-TupleTableSlot *
+bool
ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple fdw_trigtuple,
- TupleTableSlot *slot)
+ TupleTableSlot *newslot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, NULL);
- HeapTuple newtuple = slottuple;
- TriggerData LocTriggerData;
+ TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
+ HeapTuple newtuple = NULL;
HeapTuple trigtuple;
- HeapTuple oldtuple;
- TupleTableSlot *newSlot;
+ bool should_free_trig = false;
+ bool should_free_new = false;
+ TriggerData LocTriggerData;
int i;
Bitmapset *updatedCols;
LockTupleMode lockmode;
@@ -3006,37 +3006,40 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
if (fdw_trigtuple == NULL)
{
+ TupleTableSlot *newSlot = NULL;
+
/* get a copy of the on-disk tuple we are planning to update */
- trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
- lockmode, &newSlot);
- if (trigtuple == NULL)
- return NULL; /* cancel the update action */
+ if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
+ lockmode, oldslot, &newSlot))
+ return false; /* cancel the update action */
+
+ /*
+ * In READ COMMITTED isolation level it's possible that target tuple
+ * was changed due to concurrent update. In that case we have a raw
+ * subplan output tuple in newSlot, and need to run it through the
+ * junk filter to produce an insertable tuple.
+ *
+ * Caution: more than likely, the passed-in slot is the same as the
+ * junkfilter's output slot, so we are clobbering the original value
+ * of slottuple by doing the filtering. This is OK since neither we
+ * nor our caller have any more interest in the prior contents of that
+ * slot.
+ */
+ if (newSlot != NULL)
+ {
+ TupleTableSlot *slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
+
+ ExecCopySlot(newslot, slot);
+ }
+
+ trigtuple = ExecFetchSlotHeapTuple(oldslot, true, &should_free_trig);
}
else
{
+ ExecForceStoreHeapTuple(fdw_trigtuple, oldslot);
trigtuple = fdw_trigtuple;
- newSlot = NULL;
- }
-
- /*
- * In READ COMMITTED isolation level it's possible that target tuple was
- * changed due to concurrent update. In that case we have a raw subplan
- * output tuple in newSlot, and need to run it through the junk filter to
- * produce an insertable tuple.
- *
- * Caution: more than likely, the passed-in slot is the same as the
- * junkfilter's output slot, so we are clobbering the original value of
- * slottuple by doing the filtering. This is OK since neither we nor our
- * caller have any more interest in the prior contents of that slot.
- */
- if (newSlot != NULL)
- {
- slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
- slottuple = ExecFetchSlotHeapTuple(slot, true, NULL);
- newtuple = slottuple;
}
-
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
TRIGGER_EVENT_ROW |
@@ -3048,6 +3051,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
+ HeapTuple oldtuple;
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
TRIGGER_TYPE_ROW,
@@ -3055,67 +3059,66 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
TRIGGER_TYPE_UPDATE))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- updatedCols, trigtuple, newtuple))
+ updatedCols, oldslot, newslot))
continue;
+ if (!newtuple)
+ newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free_new);
+
+ LocTriggerData.tg_trigslot = oldslot;
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_newtuple = oldtuple = newtuple;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+ LocTriggerData.tg_newslot = newslot;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
- if (oldtuple != newtuple && oldtuple != slottuple)
- heap_freetuple(oldtuple);
+
if (newtuple == NULL)
{
- if (trigtuple != fdw_trigtuple)
+ if (should_free_trig)
heap_freetuple(trigtuple);
- return NULL; /* "do nothing" */
+ if (should_free_new)
+ heap_freetuple(oldtuple);
+ return false; /* "do nothing" */
}
- }
- if (trigtuple != fdw_trigtuple && trigtuple != newtuple)
- heap_freetuple(trigtuple);
+ else if (newtuple != oldtuple)
+ {
+ ExecForceStoreHeapTuple(newtuple, newslot);
- if (newtuple != slottuple)
- {
- /*
- * Return the modified tuple using the es_trig_tuple_slot. We assume
- * the tuple was allocated in per-tuple memory context, and therefore
- * will go away by itself. The tuple table slot should not try to
- * clear it.
- */
- TupleTableSlot *newslot = estate->es_trig_tuple_slot;
- TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
+ if (should_free_new)
+ heap_freetuple(oldtuple);
- if (newslot->tts_tupleDescriptor != tupdesc)
- ExecSetSlotDescriptor(newslot, tupdesc);
- ExecStoreHeapTuple(newtuple, newslot, false);
- slot = newslot;
+ /* signal tuple should be re-fetched if used */
+ newtuple = NULL;
+ }
}
- return slot;
+ if (should_free_trig)
+ heap_freetuple(trigtuple);
+
+ return true;
}
void
ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple fdw_trigtuple,
- HeapTuple newtuple,
+ TupleTableSlot *newslot,
List *recheckIndexes,
TransitionCaptureState *transition_capture)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
+
+ ExecClearTuple(oldslot);
if ((trigdesc && trigdesc->trig_update_after_row) ||
(transition_capture &&
(transition_capture->tcs_update_old_table ||
transition_capture->tcs_update_new_table)))
{
- HeapTuple trigtuple;
-
/*
* Note: if the UPDATE is converted into a DELETE+INSERT as part of
* update-partition-key operation, then this function is also called
@@ -3123,33 +3126,32 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
* In such case, either old tuple or new tuple can be NULL.
*/
if (fdw_trigtuple == NULL && ItemPointerIsValid(tupleid))
- trigtuple = GetTupleForTrigger(estate,
- NULL,
- relinfo,
- tupleid,
- LockTupleExclusive,
- NULL);
- else
- trigtuple = fdw_trigtuple;
+ GetTupleForTrigger(estate,
+ NULL,
+ relinfo,
+ tupleid,
+ LockTupleExclusive,
+ oldslot,
+ NULL);
+ else if (fdw_trigtuple != NULL)
+ ExecForceStoreHeapTuple(fdw_trigtuple, oldslot);
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
- true, trigtuple, newtuple, recheckIndexes,
+ true, oldslot, newslot, recheckIndexes,
GetUpdatedColumns(relinfo, estate),
transition_capture);
- if (trigtuple != fdw_trigtuple)
- heap_freetuple(trigtuple);
}
}
-TupleTableSlot *
+bool
ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
- HeapTuple trigtuple, TupleTableSlot *slot)
+ HeapTuple trigtuple, TupleTableSlot *newslot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, NULL);
- HeapTuple newtuple = slottuple;
+ TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
+ HeapTuple newtuple = false;
+ bool should_free;
TriggerData LocTriggerData;
- HeapTuple oldtuple;
int i;
LocTriggerData.type = T_TriggerData;
@@ -3159,9 +3161,13 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
+
+ ExecForceStoreHeapTuple(trigtuple, oldslot);
+
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
+ HeapTuple oldtuple;
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
TRIGGER_TYPE_ROW,
@@ -3169,42 +3175,40 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
TRIGGER_TYPE_UPDATE))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- NULL, trigtuple, newtuple))
+ NULL, oldslot, newslot))
continue;
+ if (!newtuple)
+ newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free);
+
+ LocTriggerData.tg_trigslot = oldslot;
LocTriggerData.tg_trigtuple = trigtuple;
+ LocTriggerData.tg_newslot = newslot;
LocTriggerData.tg_newtuple = oldtuple = newtuple;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
- if (oldtuple != newtuple && oldtuple != slottuple)
- heap_freetuple(oldtuple);
if (newtuple == NULL)
- return NULL; /* "do nothing" */
- }
+ {
+ return false; /* "do nothing" */
+ }
+ else if (newtuple != oldtuple)
+ {
+ ExecForceStoreHeapTuple(newtuple, newslot);
- if (newtuple != slottuple)
- {
- /*
- * Return the modified tuple using the es_trig_tuple_slot. We assume
- * the tuple was allocated in per-tuple memory context, and therefore
- * will go away by itself. The tuple table slot should not try to
- * clear it.
- */
- TupleTableSlot *newslot = estate->es_trig_tuple_slot;
- TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
+ if (should_free)
+ heap_freetuple(oldtuple);
- if (newslot->tts_tupleDescriptor != tupdesc)
- ExecSetSlotDescriptor(newslot, tupdesc);
- ExecStoreHeapTuple(newtuple, newslot, false);
- slot = newslot;
+ /* signal tuple should be re-fetched if used */
+ newtuple = NULL;
+ }
}
- return slot;
+
+ return true;
}
void
@@ -3227,10 +3231,11 @@ ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_trigtuple = NULL;
LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
@@ -3270,18 +3275,24 @@ ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
}
-static HeapTuple
+static bool
GetTupleForTrigger(EState *estate,
EPQState *epqstate,
ResultRelInfo *relinfo,
ItemPointer tid,
LockTupleMode lockmode,
+ TupleTableSlot *oldslot,
TupleTableSlot **newSlot)
{
Relation relation = relinfo->ri_RelationDesc;
- HeapTupleData tuple;
- HeapTuple result;
+ HeapTuple tuple;
Buffer buffer;
+ BufferHeapTupleTableSlot *boldslot;
+
+ Assert(TTS_IS_BUFFERTUPLE(oldslot));
+ ExecClearTuple(oldslot);
+ boldslot = (BufferHeapTupleTableSlot *) oldslot;
+ tuple = &boldslot->base.tupdata;
if (newSlot != NULL)
{
@@ -3297,8 +3308,8 @@ GetTupleForTrigger(EState *estate,
* lock tuple for update
*/
ltrmark:;
- tuple.t_self = *tid;
- test = heap_lock_tuple(relation, &tuple,
+ tuple->t_self = *tid;
+ test = heap_lock_tuple(relation, tuple,
estate->es_output_cid,
lockmode, LockWaitBlock,
false, &buffer, &hufd);
@@ -3322,9 +3333,11 @@ ltrmark:;
/* treat it as deleted; do not process */
ReleaseBuffer(buffer);
- return NULL;
+ return false;
case HeapTupleMayBeUpdated:
+ ExecStorePinnedBufferHeapTuple(tuple, oldslot, buffer);
+
break;
case HeapTupleUpdated:
@@ -3338,7 +3351,7 @@ ltrmark:;
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
- if (!ItemPointerEquals(&hufd.ctid, &tuple.t_self))
+ if (!ItemPointerEquals(&hufd.ctid, &tuple->t_self))
{
/* it was updated, so look at the updated version */
TupleTableSlot *epqslot;
@@ -3353,6 +3366,7 @@ ltrmark:;
if (!TupIsNull(epqslot))
{
*tid = hufd.ctid;
+
*newSlot = epqslot;
/*
@@ -3369,7 +3383,7 @@ ltrmark:;
* if tuple was deleted or PlanQual failed for updated tuple -
* we must not process this tuple!
*/
- return NULL;
+ return false;
case HeapTupleInvisible:
elog(ERROR, "attempted to lock invisible tuple");
@@ -3378,7 +3392,7 @@ ltrmark:;
default:
ReleaseBuffer(buffer);
elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
- return NULL; /* keep compiler quiet */
+ return false; /* keep compiler quiet */
}
}
else
@@ -3403,18 +3417,17 @@ ltrmark:;
Assert(ItemIdIsNormal(lp));
- tuple.t_data = (HeapTupleHeader) PageGetItem(page, lp);
- tuple.t_len = ItemIdGetLength(lp);
- tuple.t_self = *tid;
- tuple.t_tableOid = RelationGetRelid(relation);
+ tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
+ tuple->t_len = ItemIdGetLength(lp);
+ tuple->t_self = *tid;
+ tuple->t_tableOid = RelationGetRelid(relation);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
- }
- result = heap_copytuple(&tuple);
- ReleaseBuffer(buffer);
+ ExecStorePinnedBufferHeapTuple(tuple, oldslot, buffer);
+ }
- return result;
+ return true;
}
/*
@@ -3424,7 +3437,7 @@ static bool
TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
Trigger *trigger, TriggerEvent event,
Bitmapset *modifiedCols,
- HeapTuple oldtup, HeapTuple newtup)
+ TupleTableSlot *oldslot, TupleTableSlot *newslot)
{
/* Check replication-role-dependent enable state */
if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
@@ -3466,11 +3479,8 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
/* Check for WHEN clause */
if (trigger->tgqual)
{
- TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
ExprState **predicate;
ExprContext *econtext;
- TupleTableSlot *oldslot = NULL;
- TupleTableSlot *newslot = NULL;
MemoryContext oldContext;
int i;
@@ -3510,40 +3520,6 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
econtext = GetPerTupleExprContext(estate);
/*
- * Put OLD and NEW tuples into tupleslots for expression evaluation.
- * These slots can be shared across the whole estate, but be careful
- * that they have the current resultrel's tupdesc.
- */
- if (HeapTupleIsValid(oldtup))
- {
- if (estate->es_trig_oldtup_slot == NULL)
- {
- oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
- estate->es_trig_oldtup_slot =
- ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
- MemoryContextSwitchTo(oldContext);
- }
- oldslot = estate->es_trig_oldtup_slot;
- if (oldslot->tts_tupleDescriptor != tupdesc)
- ExecSetSlotDescriptor(oldslot, tupdesc);
- ExecStoreHeapTuple(oldtup, oldslot, false);
- }
- if (HeapTupleIsValid(newtup))
- {
- if (estate->es_trig_newtup_slot == NULL)
- {
- oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
- estate->es_trig_newtup_slot =
- ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
- MemoryContextSwitchTo(oldContext);
- }
- newslot = estate->es_trig_newtup_slot;
- if (newslot->tts_tupleDescriptor != tupdesc)
- ExecSetSlotDescriptor(newslot, tupdesc);
- ExecStoreHeapTuple(newtup, newslot, false);
- }
-
- /*
* Finally evaluate the expression, making the old and/or new tuples
* available as INNER_VAR/OUTER_VAR respectively.
*/
@@ -3872,12 +3848,15 @@ struct AfterTriggersTableData
AfterTriggerEventList after_trig_events; /* if so, saved list pointer */
Tuplestorestate *old_tuplestore; /* "old" transition table, if any */
Tuplestorestate *new_tuplestore; /* "new" transition table, if any */
+ TupleTableSlot *storeslot; /* for converting to tuplestore's format */
};
static AfterTriggersData afterTriggers;
-static void AfterTriggerExecute(AfterTriggerEvent event,
- Relation rel, TriggerDesc *trigdesc,
+static void AfterTriggerExecute(EState *estate,
+ AfterTriggerEvent event,
+ ResultRelInfo *relInfo,
+ TriggerDesc *trigdesc,
FmgrInfo *finfo,
Instrumentation *instr,
MemoryContext per_tuple_context,
@@ -4211,27 +4190,33 @@ afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs)
* ----------
*/
static void
-AfterTriggerExecute(AfterTriggerEvent event,
- Relation rel, TriggerDesc *trigdesc,
+AfterTriggerExecute(EState *estate,
+ AfterTriggerEvent event,
+ ResultRelInfo *relInfo,
+ TriggerDesc *trigdesc,
FmgrInfo *finfo, Instrumentation *instr,
MemoryContext per_tuple_context,
TupleTableSlot *trig_tuple_slot1,
TupleTableSlot *trig_tuple_slot2)
{
+ Relation rel = relInfo->ri_RelationDesc;
AfterTriggerShared evtshared = GetTriggerSharedData(event);
Oid tgoid = evtshared->ats_tgoid;
TriggerData LocTriggerData;
HeapTupleData tuple1;
HeapTupleData tuple2;
HeapTuple rettuple;
- Buffer buffer1 = InvalidBuffer;
- Buffer buffer2 = InvalidBuffer;
int tgindx;
+ bool should_free_trig = false;
+ bool should_free_new = false;
/*
* Locate trigger in trigdesc.
*/
LocTriggerData.tg_trigger = NULL;
+ LocTriggerData.tg_trigslot = NULL;
+ LocTriggerData.tg_newslot = NULL;
+
for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
{
if (trigdesc->triggers[tgindx].tgoid == tgoid)
@@ -4273,7 +4258,7 @@ AfterTriggerExecute(AfterTriggerEvent event,
case AFTER_TRIGGER_FDW_REUSE:
/*
- * Materialize tuple in the slot so that tg_trigtuple does not
+ * Store tuple in the slot so that tg_trigtuple does not
* reference tuplestore memory. (It is formally possible for the
* trigger function to queue trigger events that add to the same
* tuplestore, which can push other tuples out of memory.) The
@@ -4281,31 +4266,38 @@ AfterTriggerExecute(AfterTriggerEvent event,
* that is stored as a heap tuple, constructed in different memory
* context, in the slot anyway.
*/
- LocTriggerData.tg_trigtuple = ExecFetchSlotHeapTuple(trig_tuple_slot1,
- true, NULL);
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
+ LocTriggerData.tg_trigslot = trig_tuple_slot1;
+ LocTriggerData.tg_trigtuple =
+ ExecFetchSlotHeapTuple(trig_tuple_slot1, true, &should_free_trig);
+ LocTriggerData.tg_newslot = trig_tuple_slot2;
LocTriggerData.tg_newtuple =
((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
TRIGGER_EVENT_UPDATE) ?
- ExecFetchSlotHeapTuple(trig_tuple_slot2, true, NULL) : NULL;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+ ExecFetchSlotHeapTuple(trig_tuple_slot2, true, &should_free_new) : NULL;
break;
default:
if (ItemPointerIsValid(&(event->ate_ctid1)))
{
+ Buffer buffer;
+
+ LocTriggerData.tg_trigslot = ExecGetTriggerOldSlot(estate, relInfo);
+
ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
- if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
+ if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer, false, NULL))
elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
- LocTriggerData.tg_trigtuple = &tuple1;
- LocTriggerData.tg_trigtuplebuf = buffer1;
+ ExecStorePinnedBufferHeapTuple(&tuple1,
+ LocTriggerData.tg_trigslot,
+ buffer);
+ LocTriggerData.tg_trigtuple =
+ ExecFetchSlotHeapTuple(LocTriggerData.tg_trigslot, false,
+ &should_free_trig);
}
else
{
LocTriggerData.tg_trigtuple = NULL;
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
}
/* don't touch ctid2 if not there */
@@ -4313,16 +4305,23 @@ AfterTriggerExecute(AfterTriggerEvent event,
AFTER_TRIGGER_2CTID &&
ItemPointerIsValid(&(event->ate_ctid2)))
{
+ Buffer buffer;
+
+ LocTriggerData.tg_newslot = ExecGetTriggerNewSlot(estate, relInfo);
+
ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
- if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
+ if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer, false, NULL))
elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
- LocTriggerData.tg_newtuple = &tuple2;
- LocTriggerData.tg_newtuplebuf = buffer2;
+ ExecStorePinnedBufferHeapTuple(&tuple2,
+ LocTriggerData.tg_newslot,
+ buffer);
+ LocTriggerData.tg_newtuple =
+ ExecFetchSlotHeapTuple(LocTriggerData.tg_newslot, false,
+ &should_free_new);
}
else
{
LocTriggerData.tg_newtuple = NULL;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
}
}
@@ -4374,12 +4373,17 @@ AfterTriggerExecute(AfterTriggerEvent event,
heap_freetuple(rettuple);
/*
- * Release buffers
+ * Release resources
*/
- if (buffer1 != InvalidBuffer)
- ReleaseBuffer(buffer1);
- if (buffer2 != InvalidBuffer)
- ReleaseBuffer(buffer2);
+ if (should_free_trig)
+ heap_freetuple(LocTriggerData.tg_trigtuple);
+ if (should_free_new)
+ heap_freetuple(LocTriggerData.tg_newtuple);
+
+ if (LocTriggerData.tg_trigslot)
+ ExecClearTuple(LocTriggerData.tg_trigslot);
+ if (LocTriggerData.tg_newslot)
+ ExecClearTuple(LocTriggerData.tg_newslot);
/*
* If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
@@ -4486,6 +4490,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
AfterTriggerEventChunk *chunk;
MemoryContext per_tuple_context;
bool local_estate = false;
+ ResultRelInfo *rInfo;
Relation rel = NULL;
TriggerDesc *trigdesc = NULL;
FmgrInfo *finfo = NULL;
@@ -4527,8 +4532,6 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
*/
if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
{
- ResultRelInfo *rInfo;
-
rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
rel = rInfo->ri_RelationDesc;
trigdesc = rInfo->ri_TrigDesc;
@@ -4556,7 +4559,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
* still set, so recursive examinations of the event list
* won't try to re-fire it.
*/
- AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
+ AfterTriggerExecute(estate, event, rInfo, trigdesc, finfo, instr,
per_tuple_context, slot1, slot2);
/*
@@ -4600,6 +4603,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
if (local_estate)
{
ExecCleanUpTriggerState(estate);
+ ExecResetTupleTable(estate->es_tupleTable, false);
FreeExecutorState(estate);
}
@@ -5737,7 +5741,7 @@ AfterTriggerPendingOnRel(Oid relid)
static void
AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
int event, bool row_trigger,
- HeapTuple oldtup, HeapTuple newtup,
+ TupleTableSlot *oldslot, TupleTableSlot *newslot,
List *recheckIndexes, Bitmapset *modifiedCols,
TransitionCaptureState *transition_capture)
{
@@ -5769,7 +5773,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
*/
if (row_trigger && transition_capture != NULL)
{
- HeapTuple original_insert_tuple = transition_capture->tcs_original_insert_tuple;
+ TupleTableSlot *original_insert_tuple = transition_capture->tcs_original_insert_tuple;
TupleConversionMap *map = transition_capture->tcs_map;
bool delete_old_table = transition_capture->tcs_delete_old_table;
bool update_old_table = transition_capture->tcs_update_old_table;
@@ -5777,20 +5781,19 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
bool insert_new_table = transition_capture->tcs_insert_new_table;
/*
- * For INSERT events newtup should be non-NULL, for DELETE events
- * oldtup should be non-NULL, whereas for UPDATE events normally both
- * oldtup and newtup are non-NULL. But for UPDATE events fired for
- * capturing transition tuples during UPDATE partition-key row
- * movement, oldtup is NULL when the event is for a row being
- * inserted, whereas newtup is NULL when the event is for a row being
- * deleted.
+ * For INSERT events NEW should be non-NULL, for DELETE events OLD
+ * should be non-NULL, whereas for UPDATE events normally both OLD and
+ * NEW are non-NULL. But for UPDATE events fired for capturing
+ * transition tuples during UPDATE partition-key row movement, OLD is
+ * NULL when the event is for a row being inserted, whereas NEW is
+ * NULL when the event is for a row being deleted.
*/
Assert(!(event == TRIGGER_EVENT_DELETE && delete_old_table &&
- oldtup == NULL));
+ TupIsNull(oldslot)));
Assert(!(event == TRIGGER_EVENT_INSERT && insert_new_table &&
- newtup == NULL));
+ TupIsNull(newslot)));
- if (oldtup != NULL &&
+ if (!TupIsNull(oldslot) &&
((event == TRIGGER_EVENT_DELETE && delete_old_table) ||
(event == TRIGGER_EVENT_UPDATE && update_old_table)))
{
@@ -5800,15 +5803,24 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
if (map != NULL)
{
- HeapTuple converted = execute_attr_map_tuple(oldtup, map);
+ TupleTableSlot *storeslot;
+
+ storeslot = transition_capture->tcs_private->storeslot;
+ if (!storeslot)
+ {
+ storeslot = ExecAllocTableSlot(&estate->es_tupleTable,
+ map->outdesc,
+ &TTSOpsVirtual);
+ transition_capture->tcs_private->storeslot = storeslot;
+ }
- tuplestore_puttuple(old_tuplestore, converted);
- pfree(converted);
+ execute_attr_map_slot(map->attrMap, oldslot, storeslot);
+ tuplestore_puttupleslot(old_tuplestore, storeslot);
}
else
- tuplestore_puttuple(old_tuplestore, oldtup);
+ tuplestore_puttupleslot(old_tuplestore, oldslot);
}
- if (newtup != NULL &&
+ if (!TupIsNull(newslot) &&
((event == TRIGGER_EVENT_INSERT && insert_new_table) ||
(event == TRIGGER_EVENT_UPDATE && update_new_table)))
{
@@ -5817,16 +5829,27 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
new_tuplestore = transition_capture->tcs_private->new_tuplestore;
if (original_insert_tuple != NULL)
- tuplestore_puttuple(new_tuplestore, original_insert_tuple);
+ tuplestore_puttupleslot(new_tuplestore,
+ original_insert_tuple);
else if (map != NULL)
{
- HeapTuple converted = execute_attr_map_tuple(newtup, map);
+ TupleTableSlot *storeslot;
+
+ storeslot = transition_capture->tcs_private->storeslot;
+
+ if (!storeslot)
+ {
+ storeslot = ExecAllocTableSlot(&estate->es_tupleTable,
+ map->outdesc,
+ &TTSOpsVirtual);
+ transition_capture->tcs_private->storeslot = storeslot;
+ }
- tuplestore_puttuple(new_tuplestore, converted);
- pfree(converted);
+ execute_attr_map_slot(map->attrMap, newslot, storeslot);
+ tuplestore_puttupleslot(new_tuplestore, storeslot);
}
else
- tuplestore_puttuple(new_tuplestore, newtup);
+ tuplestore_puttupleslot(new_tuplestore, newslot);
}
/*
@@ -5840,7 +5863,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
(event == TRIGGER_EVENT_DELETE && !trigdesc->trig_delete_after_row) ||
(event == TRIGGER_EVENT_INSERT && !trigdesc->trig_insert_after_row) ||
(event == TRIGGER_EVENT_UPDATE && !trigdesc->trig_update_after_row) ||
- (event == TRIGGER_EVENT_UPDATE && ((oldtup == NULL) ^ (newtup == NULL))))
+ (event == TRIGGER_EVENT_UPDATE && (TupIsNull(oldslot) ^ TupIsNull(newslot))))
return;
}
@@ -5862,15 +5885,15 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
tgtype_event = TRIGGER_TYPE_INSERT;
if (row_trigger)
{
- Assert(oldtup == NULL);
- Assert(newtup != NULL);
- ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
+ Assert(oldslot == NULL);
+ Assert(newslot != NULL);
+ ItemPointerCopy(&(newslot->tts_tid), &(new_event.ate_ctid1));
ItemPointerSetInvalid(&(new_event.ate_ctid2));
}
else
{
- Assert(oldtup == NULL);
- Assert(newtup == NULL);
+ Assert(oldslot == NULL);
+ Assert(newslot == NULL);
ItemPointerSetInvalid(&(new_event.ate_ctid1));
ItemPointerSetInvalid(&(new_event.ate_ctid2));
cancel_prior_stmt_triggers(RelationGetRelid(rel),
@@ -5881,15 +5904,15 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
tgtype_event = TRIGGER_TYPE_DELETE;
if (row_trigger)
{
- Assert(oldtup != NULL);
- Assert(newtup == NULL);
- ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
+ Assert(oldslot != NULL);
+ Assert(newslot == NULL);
+ ItemPointerCopy(&(oldslot->tts_tid), &(new_event.ate_ctid1));
ItemPointerSetInvalid(&(new_event.ate_ctid2));
}
else
{
- Assert(oldtup == NULL);
- Assert(newtup == NULL);
+ Assert(oldslot == NULL);
+ Assert(newslot == NULL);
ItemPointerSetInvalid(&(new_event.ate_ctid1));
ItemPointerSetInvalid(&(new_event.ate_ctid2));
cancel_prior_stmt_triggers(RelationGetRelid(rel),
@@ -5900,15 +5923,15 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
tgtype_event = TRIGGER_TYPE_UPDATE;
if (row_trigger)
{
- Assert(oldtup != NULL);
- Assert(newtup != NULL);
- ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
- ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
+ Assert(oldslot != NULL);
+ Assert(newslot != NULL);
+ ItemPointerCopy(&(oldslot->tts_tid), &(new_event.ate_ctid1));
+ ItemPointerCopy(&(newslot->tts_tid), &(new_event.ate_ctid2));
}
else
{
- Assert(oldtup == NULL);
- Assert(newtup == NULL);
+ Assert(oldslot == NULL);
+ Assert(newslot == NULL);
ItemPointerSetInvalid(&(new_event.ate_ctid1));
ItemPointerSetInvalid(&(new_event.ate_ctid2));
cancel_prior_stmt_triggers(RelationGetRelid(rel),
@@ -5917,8 +5940,8 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
break;
case TRIGGER_EVENT_TRUNCATE:
tgtype_event = TRIGGER_TYPE_TRUNCATE;
- Assert(oldtup == NULL);
- Assert(newtup == NULL);
+ Assert(oldslot == NULL);
+ Assert(newslot == NULL);
ItemPointerSetInvalid(&(new_event.ate_ctid1));
ItemPointerSetInvalid(&(new_event.ate_ctid2));
break;
@@ -5945,7 +5968,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
tgtype_event))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, event,
- modifiedCols, oldtup, newtup))
+ modifiedCols, oldslot, newslot))
continue;
if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
@@ -5972,7 +5995,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
case RI_TRIGGER_PK:
/* Update or delete on trigger's PK table */
if (!RI_FKey_pk_upd_check_required(trigger, rel,
- oldtup, newtup))
+ oldslot, newslot))
{
/* skip queuing this event */
continue;
@@ -5982,7 +6005,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
case RI_TRIGGER_FK:
/* Update on trigger's FK table */
if (!RI_FKey_fk_upd_check_required(trigger, rel,
- oldtup, newtup))
+ oldslot, newslot))
{
/* skip queuing this event */
continue;
@@ -6036,10 +6059,10 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
*/
if (fdw_tuplestore)
{
- if (oldtup != NULL)
- tuplestore_puttuple(fdw_tuplestore, oldtup);
- if (newtup != NULL)
- tuplestore_puttuple(fdw_tuplestore, newtup);
+ if (oldslot != NULL)
+ tuplestore_puttupleslot(fdw_tuplestore, oldslot);
+ if (newslot != NULL)
+ tuplestore_puttupleslot(fdw_tuplestore, newslot);
}
}