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.c126
1 files changed, 89 insertions, 37 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index fce79b02a57..13cb516752b 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -84,7 +84,8 @@ static bool GetTupleForTrigger(EState *estate,
ItemPointer tid,
LockTupleMode lockmode,
TupleTableSlot *oldslot,
- TupleTableSlot **newSlot);
+ TupleTableSlot **newSlot,
+ TM_FailureData *tmfpd);
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
Trigger *trigger, TriggerEvent event,
Bitmapset *modifiedCols,
@@ -2713,7 +2714,8 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
TupleTableSlot *epqslot_candidate = NULL;
if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
- LockTupleExclusive, slot, &epqslot_candidate))
+ LockTupleExclusive, slot, &epqslot_candidate,
+ NULL))
return false;
/*
@@ -2728,7 +2730,6 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
}
trigtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
-
}
else
{
@@ -2804,6 +2805,7 @@ ExecARDeleteTriggers(EState *estate,
tupleid,
LockTupleExclusive,
slot,
+ NULL,
NULL);
else
ExecForceStoreHeapTuple(fdw_trigtuple, slot, false);
@@ -2944,7 +2946,8 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple fdw_trigtuple,
- TupleTableSlot *newslot)
+ TupleTableSlot *newslot,
+ TM_FailureData *tmfd)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
@@ -2967,7 +2970,8 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
/* get a copy of the on-disk tuple we are planning to update */
if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
- lockmode, oldslot, &epqslot_candidate))
+ lockmode, oldslot, &epqslot_candidate,
+ tmfd))
return false; /* cancel the update action */
/*
@@ -3121,6 +3125,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
tupleid,
LockTupleExclusive,
oldslot,
+ NULL,
NULL);
else if (fdw_trigtuple != NULL)
ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
@@ -3275,7 +3280,8 @@ GetTupleForTrigger(EState *estate,
ItemPointer tid,
LockTupleMode lockmode,
TupleTableSlot *oldslot,
- TupleTableSlot **epqslot)
+ TupleTableSlot **epqslot,
+ TM_FailureData *tmfdp)
{
Relation relation = relinfo->ri_RelationDesc;
@@ -3301,6 +3307,10 @@ GetTupleForTrigger(EState *estate,
lockflags,
&tmfd);
+ /* Let the caller know about the status of this operation */
+ if (tmfdp)
+ *tmfdp = tmfd;
+
switch (test)
{
case TM_SelfModified:
@@ -3821,8 +3831,23 @@ struct AfterTriggersTableData
bool before_trig_done; /* did we already queue BS triggers? */
bool after_trig_done; /* did we already queue AS triggers? */
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 */
+
+ /*
+ * We maintain separate transition tables for UPDATE/INSERT/DELETE since
+ * MERGE can run all three actions in a single statement. Note that UPDATE
+ * needs both old and new transition tables whereas INSERT needs only new,
+ * and DELETE needs only old.
+ */
+
+ /* "old" transition table for UPDATE, if any */
+ Tuplestorestate *old_upd_tuplestore;
+ /* "new" transition table for UPDATE, if any */
+ Tuplestorestate *new_upd_tuplestore;
+ /* "old" transition table for DELETE, if any */
+ Tuplestorestate *old_del_tuplestore;
+ /* "new" transition table for INSERT, if any */
+ Tuplestorestate *new_ins_tuplestore;
+
TupleTableSlot *storeslot; /* for converting to tuplestore's format */
};
@@ -4374,13 +4399,19 @@ AfterTriggerExecute(EState *estate,
{
if (LocTriggerData.tg_trigger->tgoldtable)
{
- LocTriggerData.tg_oldtable = evtshared->ats_table->old_tuplestore;
+ if (TRIGGER_FIRED_BY_UPDATE(evtshared->ats_event))
+ LocTriggerData.tg_oldtable = evtshared->ats_table->old_upd_tuplestore;
+ else
+ LocTriggerData.tg_oldtable = evtshared->ats_table->old_del_tuplestore;
evtshared->ats_table->closed = true;
}
if (LocTriggerData.tg_trigger->tgnewtable)
{
- LocTriggerData.tg_newtable = evtshared->ats_table->new_tuplestore;
+ if (TRIGGER_FIRED_BY_INSERT(evtshared->ats_event))
+ LocTriggerData.tg_newtable = evtshared->ats_table->new_ins_tuplestore;
+ else
+ LocTriggerData.tg_newtable = evtshared->ats_table->new_upd_tuplestore;
evtshared->ats_table->closed = true;
}
}
@@ -4794,8 +4825,10 @@ TransitionCaptureState *
MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
{
TransitionCaptureState *state;
- bool need_old,
- need_new;
+ bool need_old_upd,
+ need_new_upd,
+ need_old_del,
+ need_new_ins;
AfterTriggersTableData *table;
MemoryContext oldcxt;
ResourceOwner saveResourceOwner;
@@ -4807,23 +4840,31 @@ MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
switch (cmdType)
{
case CMD_INSERT:
- need_old = false;
- need_new = trigdesc->trig_insert_new_table;
+ need_old_upd = need_old_del = need_new_upd = false;
+ need_new_ins = trigdesc->trig_insert_new_table;
break;
case CMD_UPDATE:
- need_old = trigdesc->trig_update_old_table;
- need_new = trigdesc->trig_update_new_table;
+ need_old_upd = trigdesc->trig_update_old_table;
+ need_new_upd = trigdesc->trig_update_new_table;
+ need_old_del = need_new_ins = false;
break;
case CMD_DELETE:
- need_old = trigdesc->trig_delete_old_table;
- need_new = false;
+ need_old_del = trigdesc->trig_delete_old_table;
+ need_old_upd = need_new_upd = need_new_ins = false;
+ break;
+ case CMD_MERGE:
+ need_old_upd = trigdesc->trig_update_old_table;
+ need_new_upd = trigdesc->trig_update_new_table;
+ need_old_del = trigdesc->trig_delete_old_table;
+ need_new_ins = trigdesc->trig_insert_new_table;
break;
default:
elog(ERROR, "unexpected CmdType: %d", (int) cmdType);
- need_old = need_new = false; /* keep compiler quiet */
+ /* keep compiler quiet */
+ need_old_upd = need_new_upd = need_old_del = need_new_ins = false;
break;
}
- if (!need_old && !need_new)
+ if (!need_old_upd && !need_new_upd && !need_new_ins && !need_old_del)
return NULL;
/* Check state, like AfterTriggerSaveEvent. */
@@ -4853,10 +4894,14 @@ MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = CurTransactionResourceOwner;
- if (need_old && table->old_tuplestore == NULL)
- table->old_tuplestore = tuplestore_begin_heap(false, false, work_mem);
- if (need_new && table->new_tuplestore == NULL)
- table->new_tuplestore = tuplestore_begin_heap(false, false, work_mem);
+ if (need_old_upd && table->old_upd_tuplestore == NULL)
+ table->old_upd_tuplestore = tuplestore_begin_heap(false, false, work_mem);
+ if (need_new_upd && table->new_upd_tuplestore == NULL)
+ table->new_upd_tuplestore = tuplestore_begin_heap(false, false, work_mem);
+ if (need_old_del && table->old_del_tuplestore == NULL)
+ table->old_del_tuplestore = tuplestore_begin_heap(false, false, work_mem);
+ if (need_new_ins && table->new_ins_tuplestore == NULL)
+ table->new_ins_tuplestore = tuplestore_begin_heap(false, false, work_mem);
CurrentResourceOwner = saveResourceOwner;
MemoryContextSwitchTo(oldcxt);
@@ -5045,12 +5090,20 @@ AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
{
AfterTriggersTableData *table = (AfterTriggersTableData *) lfirst(lc);
- ts = table->old_tuplestore;
- table->old_tuplestore = NULL;
+ ts = table->old_upd_tuplestore;
+ table->old_upd_tuplestore = NULL;
+ if (ts)
+ tuplestore_end(ts);
+ ts = table->new_upd_tuplestore;
+ table->new_upd_tuplestore = NULL;
+ if (ts)
+ tuplestore_end(ts);
+ ts = table->old_del_tuplestore;
+ table->old_del_tuplestore = NULL;
if (ts)
tuplestore_end(ts);
- ts = table->new_tuplestore;
- table->new_tuplestore = NULL;
+ ts = table->new_ins_tuplestore;
+ table->new_ins_tuplestore = NULL;
if (ts)
tuplestore_end(ts);
if (table->storeslot)
@@ -5356,17 +5409,17 @@ GetAfterTriggersTransitionTable(int event,
{
Assert(TupIsNull(newslot));
if (event == TRIGGER_EVENT_DELETE && delete_old_table)
- tuplestore = transition_capture->tcs_private->old_tuplestore;
+ tuplestore = transition_capture->tcs_private->old_del_tuplestore;
else if (event == TRIGGER_EVENT_UPDATE && update_old_table)
- tuplestore = transition_capture->tcs_private->old_tuplestore;
+ tuplestore = transition_capture->tcs_private->old_upd_tuplestore;
}
else if (!TupIsNull(newslot))
{
Assert(TupIsNull(oldslot));
if (event == TRIGGER_EVENT_INSERT && insert_new_table)
- tuplestore = transition_capture->tcs_private->new_tuplestore;
+ tuplestore = transition_capture->tcs_private->new_ins_tuplestore;
else if (event == TRIGGER_EVENT_UPDATE && update_new_table)
- tuplestore = transition_capture->tcs_private->new_tuplestore;
+ tuplestore = transition_capture->tcs_private->new_upd_tuplestore;
}
return tuplestore;
@@ -5980,6 +6033,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
*/
if (row_trigger && transition_capture != NULL)
{
+ TupleTableSlot *original_insert_tuple = transition_capture->tcs_original_insert_tuple;
/*
* Capture the old tuple in the appropriate transition table based on
@@ -6010,17 +6064,15 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
newslot,
transition_capture);
TransitionTableAddTuple(estate, transition_capture, relinfo,
- newslot,
- transition_capture->tcs_original_insert_tuple,
- new_tuplestore);
+ newslot, original_insert_tuple, new_tuplestore);
}
/*
* If transition tables are the only reason we're here, return. As
* mentioned above, we can also be here during update tuple routing in
* presence of transition tables, in which case this function is
- * called separately for oldtup and newtup, so we expect exactly one
- * of them to be NULL.
+ * called separately for OLD and NEW, so we expect exactly one of them
+ * to be NULL.
*/
if (trigdesc == NULL ||
(event == TRIGGER_EVENT_DELETE && !trigdesc->trig_delete_after_row) ||