Skip to content

Commit 4b2d440

Browse files
MERGE post-commit review
Review comments from Andres Freund * Consolidate code into AfterTriggerGetTransitionTable() * Rename nodeMerge.c to execMerge.c * Rename nodeMerge.h to execMerge.h * Move MERGE handling in ExecInitModifyTable() into a execMerge.c ExecInitMerge() * Move mt_merge_subcommands flags into execMerge.h * Rename opt_and_condition to opt_merge_when_and_condition * Wordsmith various comments Author: Pavan Deolasee Reviewer: Simon Riggs
1 parent 1fd8690 commit 4b2d440

File tree

11 files changed

+384
-325
lines changed

11 files changed

+384
-325
lines changed

src/backend/commands/trigger.c

+113-79
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
9696
FmgrInfo *finfo,
9797
Instrumentation *instr,
9898
MemoryContext per_tuple_context);
99+
static Tuplestorestate *AfterTriggerGetTransitionTable(int event,
100+
HeapTuple oldtup,
101+
HeapTuple newtup,
102+
TransitionCaptureState *transition_capture);
103+
static void TransitionTableAddTuple(HeapTuple heaptup, Tuplestorestate *tuplestore,
104+
TupleConversionMap *map);
99105
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
100106
int event, bool row_trigger,
101107
HeapTuple oldtup, HeapTuple newtup,
@@ -3846,6 +3852,14 @@ struct AfterTriggersTableData
38463852
bool before_trig_done; /* did we already queue BS triggers? */
38473853
bool after_trig_done; /* did we already queue AS triggers? */
38483854
AfterTriggerEventList after_trig_events; /* if so, saved list pointer */
3855+
3856+
/*
3857+
* We maintain separate transaction tables for UPDATE/INSERT/DELETE since
3858+
* MERGE can run all three actions in a single statement. Note that UPDATE
3859+
* needs both old and new transition tables whereas INSERT needs only new
3860+
* and DELETE needs only old.
3861+
*/
3862+
38493863
/* "old" transition table for UPDATE, if any */
38503864
Tuplestorestate *old_upd_tuplestore;
38513865
/* "new" transition table for UPDATE, if any */
@@ -5716,6 +5730,84 @@ AfterTriggerPendingOnRel(Oid relid)
57165730
return false;
57175731
}
57185732

5733+
/*
5734+
* Get the transition table for the given event and depending on whether we are
5735+
* processing the old or the new tuple.
5736+
*/
5737+
static Tuplestorestate *
5738+
AfterTriggerGetTransitionTable(int event,
5739+
HeapTuple oldtup,
5740+
HeapTuple newtup,
5741+
TransitionCaptureState *transition_capture)
5742+
{
5743+
Tuplestorestate *tuplestore = NULL;
5744+
bool delete_old_table = transition_capture->tcs_delete_old_table;
5745+
bool update_old_table = transition_capture->tcs_update_old_table;
5746+
bool update_new_table = transition_capture->tcs_update_new_table;
5747+
bool insert_new_table = transition_capture->tcs_insert_new_table;;
5748+
5749+
/*
5750+
* For INSERT events newtup should be non-NULL, for DELETE events
5751+
* oldtup should be non-NULL, whereas for UPDATE events normally both
5752+
* oldtup and newtup are non-NULL. But for UPDATE events fired for
5753+
* capturing transition tuples during UPDATE partition-key row
5754+
* movement, oldtup is NULL when the event is for a row being inserted,
5755+
* whereas newtup is NULL when the event is for a row being deleted.
5756+
*/
5757+
Assert(!(event == TRIGGER_EVENT_DELETE && delete_old_table &&
5758+
oldtup == NULL));
5759+
Assert(!(event == TRIGGER_EVENT_INSERT && insert_new_table &&
5760+
newtup == NULL));
5761+
5762+
/*
5763+
* We're called either for the newtup or the oldtup, but not both at the
5764+
* same time.
5765+
*/
5766+
Assert((oldtup != NULL) ^ (newtup != NULL));
5767+
5768+
if (oldtup != NULL)
5769+
{
5770+
if (event == TRIGGER_EVENT_DELETE && delete_old_table)
5771+
tuplestore = transition_capture->tcs_private->old_del_tuplestore;
5772+
else if (event == TRIGGER_EVENT_UPDATE && update_old_table)
5773+
tuplestore = transition_capture->tcs_private->old_upd_tuplestore;
5774+
}
5775+
5776+
if (newtup != NULL)
5777+
{
5778+
if (event == TRIGGER_EVENT_INSERT && insert_new_table)
5779+
tuplestore = transition_capture->tcs_private->new_ins_tuplestore;
5780+
else if (event == TRIGGER_EVENT_UPDATE && update_new_table)
5781+
tuplestore = transition_capture->tcs_private->new_upd_tuplestore;
5782+
}
5783+
5784+
return tuplestore;
5785+
}
5786+
5787+
/*
5788+
* Add the given heap tuple to the given tuplestore, applying the conversion
5789+
* map if necessary.
5790+
*/
5791+
static void
5792+
TransitionTableAddTuple(HeapTuple heaptup, Tuplestorestate *tuplestore,
5793+
TupleConversionMap *map)
5794+
{
5795+
/*
5796+
* Nothing needs to be done if we don't have a tuplestore.
5797+
*/
5798+
if (tuplestore == NULL)
5799+
return;
5800+
5801+
if (map != NULL)
5802+
{
5803+
HeapTuple converted = do_convert_tuple(heaptup, map);
5804+
5805+
tuplestore_puttuple(tuplestore, converted);
5806+
pfree(converted);
5807+
}
5808+
else
5809+
tuplestore_puttuple(tuplestore, heaptup);
5810+
}
57195811

57205812
/* ----------
57215813
* AfterTriggerSaveEvent()
@@ -5777,95 +5869,37 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
57775869
{
57785870
HeapTuple original_insert_tuple = transition_capture->tcs_original_insert_tuple;
57795871
TupleConversionMap *map = transition_capture->tcs_map;
5780-
bool delete_old_table = transition_capture->tcs_delete_old_table;
5781-
bool update_old_table = transition_capture->tcs_update_old_table;
5782-
bool update_new_table = transition_capture->tcs_update_new_table;
5783-
bool insert_new_table = transition_capture->tcs_insert_new_table;;
57845872

57855873
/*
5786-
* For INSERT events newtup should be non-NULL, for DELETE events
5787-
* oldtup should be non-NULL, whereas for UPDATE events normally both
5788-
* oldtup and newtup are non-NULL. But for UPDATE events fired for
5789-
* capturing transition tuples during UPDATE partition-key row
5790-
* movement, oldtup is NULL when the event is for a row being inserted,
5791-
* whereas newtup is NULL when the event is for a row being deleted.
5874+
* Capture the old tuple in the appropriate transition table based on
5875+
* the event.
57925876
*/
5793-
Assert(!(event == TRIGGER_EVENT_DELETE && delete_old_table &&
5794-
oldtup == NULL));
5795-
Assert(!(event == TRIGGER_EVENT_INSERT && insert_new_table &&
5796-
newtup == NULL));
5797-
5798-
if (oldtup != NULL &&
5799-
(event == TRIGGER_EVENT_DELETE && delete_old_table))
5877+
if (oldtup != NULL)
58005878
{
5801-
Tuplestorestate *old_tuplestore;
5802-
5803-
old_tuplestore = transition_capture->tcs_private->old_del_tuplestore;
5804-
5805-
if (map != NULL)
5806-
{
5807-
HeapTuple converted = do_convert_tuple(oldtup, map);
5808-
5809-
tuplestore_puttuple(old_tuplestore, converted);
5810-
pfree(converted);
5811-
}
5812-
else
5813-
tuplestore_puttuple(old_tuplestore, oldtup);
5879+
Tuplestorestate *tuplestore =
5880+
AfterTriggerGetTransitionTable(event,
5881+
oldtup,
5882+
NULL,
5883+
transition_capture);
5884+
TransitionTableAddTuple(oldtup, tuplestore, map);
58145885
}
5815-
if (oldtup != NULL &&
5816-
(event == TRIGGER_EVENT_UPDATE && update_old_table))
5817-
{
5818-
Tuplestorestate *old_tuplestore;
5819-
5820-
old_tuplestore = transition_capture->tcs_private->old_upd_tuplestore;
5821-
5822-
if (map != NULL)
5823-
{
5824-
HeapTuple converted = do_convert_tuple(oldtup, map);
58255886

5826-
tuplestore_puttuple(old_tuplestore, converted);
5827-
pfree(converted);
5828-
}
5829-
else
5830-
tuplestore_puttuple(old_tuplestore, oldtup);
5831-
}
5832-
if (newtup != NULL &&
5833-
(event == TRIGGER_EVENT_INSERT && insert_new_table))
5834-
{
5835-
Tuplestorestate *new_tuplestore;
5836-
5837-
new_tuplestore = transition_capture->tcs_private->new_ins_tuplestore;
5838-
5839-
if (original_insert_tuple != NULL)
5840-
tuplestore_puttuple(new_tuplestore, original_insert_tuple);
5841-
else if (map != NULL)
5842-
{
5843-
HeapTuple converted = do_convert_tuple(newtup, map);
5844-
5845-
tuplestore_puttuple(new_tuplestore, converted);
5846-
pfree(converted);
5847-
}
5848-
else
5849-
tuplestore_puttuple(new_tuplestore, newtup);
5850-
}
5851-
if (newtup != NULL &&
5852-
(event == TRIGGER_EVENT_UPDATE && update_new_table))
5887+
/*
5888+
* Capture the new tuple in the appropriate transition table based on
5889+
* the event.
5890+
*/
5891+
if (newtup != NULL)
58535892
{
5854-
Tuplestorestate *new_tuplestore;
5855-
5856-
new_tuplestore = transition_capture->tcs_private->new_upd_tuplestore;
5893+
Tuplestorestate *tuplestore =
5894+
AfterTriggerGetTransitionTable(event,
5895+
NULL,
5896+
newtup,
5897+
transition_capture);
58575898

58585899
if (original_insert_tuple != NULL)
5859-
tuplestore_puttuple(new_tuplestore, original_insert_tuple);
5860-
else if (map != NULL)
5861-
{
5862-
HeapTuple converted = do_convert_tuple(newtup, map);
5863-
5864-
tuplestore_puttuple(new_tuplestore, converted);
5865-
pfree(converted);
5866-
}
5900+
tuplestore_puttuple(tuplestore, original_insert_tuple);
58675901
else
5868-
tuplestore_puttuple(new_tuplestore, newtup);
5902+
TransitionTableAddTuple(newtup, tuplestore, map);
58695903
}
58705904

58715905
/*

src/backend/executor/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ include $(top_builddir)/src/Makefile.global
1414

1515
OBJS = execAmi.o execCurrent.o execExpr.o execExprInterp.o \
1616
execGrouping.o execIndexing.o execJunk.o \
17-
execMain.o execParallel.o execPartition.o execProcnode.o \
17+
execMain.o execMerge.o execParallel.o execPartition.o execProcnode.o \
1818
execReplication.o execScan.o execSRF.o execTuples.o \
1919
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \
2020
nodeBitmapAnd.o nodeBitmapOr.o \
2121
nodeBitmapHeapscan.o nodeBitmapIndexscan.o \
2222
nodeCustom.o nodeFunctionscan.o nodeGather.o \
2323
nodeHash.o nodeHashjoin.o nodeIndexscan.o nodeIndexonlyscan.o \
2424
nodeLimit.o nodeLockRows.o nodeGatherMerge.o \
25-
nodeMaterial.o nodeMergeAppend.o nodeMergejoin.o nodeMerge.o nodeModifyTable.o \
25+
nodeMaterial.o nodeMergeAppend.o nodeMergejoin.o nodeModifyTable.o \
2626
nodeNestloop.o nodeProjectSet.o nodeRecursiveunion.o nodeResult.o \
2727
nodeSamplescan.o nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \
2828
nodeValuesscan.o \

src/backend/executor/README

+6-5
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ ModifyTable node visits each of those rows and marks the row deleted.
3939

4040
MERGE runs one generic plan that returns candidate target rows. Each row
4141
consists of a super-row that contains all the columns needed by any of the
42-
individual actions, plus a CTID and a TABLEOID junk columns. The CTID column is
42+
individual actions, plus CTID and TABLEOID junk columns. The CTID column is
4343
required to know if a matching target row was found or not and the TABLEOID
4444
column is needed to find the underlying target partition, in case when the
45-
target table is a partition table. If the CTID column is set we attempt to
46-
activate WHEN MATCHED actions, or if it is NULL then we will attempt to
47-
activate WHEN NOT MATCHED actions. Once we know which action is activated we
48-
form the final result row and apply only those changes.
45+
target table is a partition table. When a matching target tuple is found, the
46+
CTID column identifies the matching target tuple and we attempt to activate
47+
WHEN MATCHED actions. If a matching tuple is not found, then CTID column is
48+
NULL and we attempt to activate WHEN NOT MATCHED actions. Once we know which
49+
action is activated we form the final result row and apply only those changes.
4950

5051
XXX a great deal more documentation needs to be written here...
5152

0 commit comments

Comments
 (0)