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

Lines changed: 113 additions & 79 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 6 additions & 5 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy