Skip to content

Commit f49b85d

Browse files
committed
Clean up code to resolve the "root target relation" in nodeModifyTable.c
When executing DDL on a partitioned table or on a table with inheritance children, statement-level triggers must be fired against the table given in the original statement. The code to look that up was a bit messy and duplicative. Commit 501ed02 added a helper function, getASTriggerResultRelInfo() (later renamed to getTargetResultRelInfo()) for it, but for some reason it was only used when firing AFTER STATEMENT triggers and the code to fire BEFORE STATEMENT triggers duplicated the logic. Determine the target relation in ExecInitModifyTable(), and set it always in ModifyTableState. Code that used to call getTargetResultRelInfo() can now use ModifyTableState->rootResultRelInfo directly. Discussion: https://www.postgresql.org/message-id/CA%2BHiwqFViT47Zbr_ASBejiK7iDG8%3DQ1swQ-tjM6caRPQ67pT%3Dw%40mail.gmail.com
1 parent 26ec6b5 commit f49b85d

File tree

2 files changed

+31
-40
lines changed

2 files changed

+31
-40
lines changed

src/backend/executor/nodeModifyTable.c

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ static TupleTableSlot *ExecPrepareTupleRouting(ModifyTableState *mtstate,
7272
ResultRelInfo *targetRelInfo,
7373
TupleTableSlot *slot,
7474
ResultRelInfo **partRelInfo);
75-
static ResultRelInfo *getTargetResultRelInfo(ModifyTableState *node);
7675
static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate);
7776
static TupleConversionMap *tupconv_map_for_subplan(ModifyTableState *node,
7877
int whichplan);
@@ -1186,7 +1185,6 @@ ExecCrossPartitionUpdate(ModifyTableState *mtstate,
11861185
saved_tcs_map = mtstate->mt_transition_capture->tcs_map;
11871186

11881187
/* Tuple routing starts from the root table. */
1189-
Assert(mtstate->rootResultRelInfo != NULL);
11901188
*inserted_tuple = ExecInsert(mtstate, mtstate->rootResultRelInfo, slot,
11911189
planSlot, estate, canSetTag);
11921190

@@ -1796,15 +1794,7 @@ static void
17961794
fireBSTriggers(ModifyTableState *node)
17971795
{
17981796
ModifyTable *plan = (ModifyTable *) node->ps.plan;
1799-
ResultRelInfo *resultRelInfo = node->resultRelInfo;
1800-
1801-
/*
1802-
* If the node modifies a partitioned table, we must fire its triggers.
1803-
* Note that in that case, node->resultRelInfo points to the first leaf
1804-
* partition, not the root table.
1805-
*/
1806-
if (node->rootResultRelInfo != NULL)
1807-
resultRelInfo = node->rootResultRelInfo;
1797+
ResultRelInfo *resultRelInfo = node->rootResultRelInfo;
18081798

18091799
switch (node->operation)
18101800
{
@@ -1826,36 +1816,14 @@ fireBSTriggers(ModifyTableState *node)
18261816
}
18271817
}
18281818

1829-
/*
1830-
* Return the target rel ResultRelInfo.
1831-
*
1832-
* This relation is the same as :
1833-
* - the relation for which we will fire AFTER STATEMENT triggers.
1834-
* - the relation into whose tuple format all captured transition tuples must
1835-
* be converted.
1836-
* - the root partitioned table.
1837-
*/
1838-
static ResultRelInfo *
1839-
getTargetResultRelInfo(ModifyTableState *node)
1840-
{
1841-
/*
1842-
* Note that if the node modifies a partitioned table, node->resultRelInfo
1843-
* points to the first leaf partition, not the root table.
1844-
*/
1845-
if (node->rootResultRelInfo != NULL)
1846-
return node->rootResultRelInfo;
1847-
else
1848-
return node->resultRelInfo;
1849-
}
1850-
18511819
/*
18521820
* Process AFTER EACH STATEMENT triggers
18531821
*/
18541822
static void
18551823
fireASTriggers(ModifyTableState *node)
18561824
{
18571825
ModifyTable *plan = (ModifyTable *) node->ps.plan;
1858-
ResultRelInfo *resultRelInfo = getTargetResultRelInfo(node);
1826+
ResultRelInfo *resultRelInfo = node->rootResultRelInfo;
18591827

18601828
switch (node->operation)
18611829
{
@@ -1889,7 +1857,7 @@ static void
18891857
ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
18901858
{
18911859
ModifyTable *plan = (ModifyTable *) mtstate->ps.plan;
1892-
ResultRelInfo *targetRelInfo = getTargetResultRelInfo(mtstate);
1860+
ResultRelInfo *targetRelInfo = mtstate->rootResultRelInfo;
18931861

18941862
/* Check for transition tables on the directly targeted relation. */
18951863
mtstate->mt_transition_capture =
@@ -2019,7 +1987,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
20191987
static void
20201988
ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
20211989
{
2022-
ResultRelInfo *targetRelInfo = getTargetResultRelInfo(mtstate);
1990+
ResultRelInfo *targetRelInfo = mtstate->rootResultRelInfo;
20231991
ResultRelInfo *resultRelInfos = mtstate->resultRelInfo;
20241992
TupleDesc outdesc;
20251993
int numResultRelInfos = mtstate->mt_nplans;
@@ -2355,13 +2323,31 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
23552323
palloc(nplans * sizeof(ResultRelInfo));
23562324
mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
23572325

2358-
/* If modifying a partitioned table, initialize the root table info */
2326+
/*----------
2327+
* Resolve the target relation. This is the same as:
2328+
*
2329+
* - the relation for which we will fire FOR STATEMENT triggers,
2330+
* - the relation into whose tuple format all captured transition tuples
2331+
* must be converted, and
2332+
* - the root partitioned table used for tuple routing.
2333+
*
2334+
* If it's a partitioned table, the root partition doesn't appear
2335+
* elsewhere in the plan and its RT index is given explicitly in
2336+
* node->rootRelation. Otherwise (i.e. table inheritance) the target
2337+
* relation is the first relation in the node->resultRelations list, and
2338+
* we will initialize it in the loop below.
2339+
*----------
2340+
*/
23592341
if (node->rootRelation > 0)
23602342
{
23612343
mtstate->rootResultRelInfo = makeNode(ResultRelInfo);
23622344
ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
23632345
node->rootRelation);
23642346
}
2347+
else
2348+
{
2349+
mtstate->rootResultRelInfo = mtstate->resultRelInfo;
2350+
}
23652351

23662352
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
23672353
mtstate->mt_nplans = nplans;
@@ -2446,7 +2432,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
24462432
}
24472433

24482434
/* Get the target relation */
2449-
rel = (getTargetResultRelInfo(mtstate))->ri_RelationDesc;
2435+
rel = mtstate->rootResultRelInfo->ri_RelationDesc;
24502436

24512437
/*
24522438
* If it's not a partitioned table after all, UPDATE tuple routing should

src/include/nodes/execnodes.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,8 +1154,13 @@ typedef struct ModifyTableState
11541154
TupleTableSlot **mt_scans; /* input tuple corresponding to underlying
11551155
* plans */
11561156
ResultRelInfo *resultRelInfo; /* per-subplan target relations */
1157-
ResultRelInfo *rootResultRelInfo; /* root target relation (partitioned
1158-
* table root) */
1157+
1158+
/*
1159+
* Target relation mentioned in the original statement, used to fire
1160+
* statement-level triggers and as the root for tuple routing.
1161+
*/
1162+
ResultRelInfo *rootResultRelInfo;
1163+
11591164
List **mt_arowmarks; /* per-subplan ExecAuxRowMark lists */
11601165
EPQState mt_epqstate; /* for evaluating EvalPlanQual rechecks */
11611166
bool fireBSTriggers; /* do we need to fire stmt triggers? */

0 commit comments

Comments
 (0)