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.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 28b98d10ae8..59289f8d4d3 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -89,6 +89,8 @@ static bool GetTupleForTrigger(EState *estate,
LockTupleMode lockmode,
TupleTableSlot *oldslot,
TupleTableSlot **newSlot);
+static HeapTuple MaterializeTupleForTrigger(TupleTableSlot *slot,
+ bool *shouldFree);
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
Trigger *trigger, TriggerEvent event,
Bitmapset *modifiedCols,
@@ -2672,7 +2674,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
ExecCopySlot(newslot, epqslot_clean);
}
- trigtuple = ExecFetchSlotHeapTuple(oldslot, true, &should_free_trig);
+ trigtuple = MaterializeTupleForTrigger(oldslot, &should_free_trig);
}
else
{
@@ -2925,6 +2927,9 @@ ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
}
+/*
+ * Fetch tuple into "oldslot", dealing with locking and EPQ if necessary
+ */
static bool
GetTupleForTrigger(EState *estate,
EPQState *epqstate,
@@ -3039,6 +3044,40 @@ GetTupleForTrigger(EState *estate,
}
/*
+ * Extract a HeapTuple that we can pass off to trigger functions.
+ *
+ * We must materialize the tuple and make sure it is not dependent on any
+ * attrmissing data. This is needed for the old row in BEFORE UPDATE
+ * triggers, since they can choose to pass back this exact tuple as the update
+ * result, causing the tuple to be inserted into an executor slot that lacks
+ * the attrmissing data.
+ *
+ * Currently we don't seem to need to remove the attrmissing dependency in any
+ * other cases, but keep this as a separate function to simplify fixing things
+ * if that changes.
+ */
+static HeapTuple
+MaterializeTupleForTrigger(TupleTableSlot *slot, bool *shouldFree)
+{
+ HeapTuple tup;
+ TupleDesc tupdesc = slot->tts_tupleDescriptor;
+
+ tup = ExecFetchSlotHeapTuple(slot, true, shouldFree);
+ if (HeapTupleHeaderGetNatts(tup->t_data) < tupdesc->natts &&
+ tupdesc->constr && tupdesc->constr->missing)
+ {
+ HeapTuple newtup;
+
+ newtup = heap_expand_tuple(tup, tupdesc);
+ if (*shouldFree)
+ heap_freetuple(tup);
+ *shouldFree = true;
+ tup = newtup;
+ }
+ return tup;
+}
+
+/*
* Is trigger enabled to fire?
*/
static bool