diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 0c055ed408..ae209bc774 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -72,7 +72,6 @@ static TupleTableSlot *ExecPrepareTupleRouting(ModifyTableState *mtstate, ResultRelInfo *targetRelInfo, TupleTableSlot *slot, ResultRelInfo **partRelInfo); -static ResultRelInfo *getTargetResultRelInfo(ModifyTableState *node); static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate); static TupleConversionMap *tupconv_map_for_subplan(ModifyTableState *node, int whichplan); @@ -1186,7 +1185,6 @@ ExecCrossPartitionUpdate(ModifyTableState *mtstate, saved_tcs_map = mtstate->mt_transition_capture->tcs_map; /* Tuple routing starts from the root table. */ - Assert(mtstate->rootResultRelInfo != NULL); *inserted_tuple = ExecInsert(mtstate, mtstate->rootResultRelInfo, slot, planSlot, estate, canSetTag); @@ -1796,15 +1794,7 @@ static void fireBSTriggers(ModifyTableState *node) { ModifyTable *plan = (ModifyTable *) node->ps.plan; - ResultRelInfo *resultRelInfo = node->resultRelInfo; - - /* - * If the node modifies a partitioned table, we must fire its triggers. - * Note that in that case, node->resultRelInfo points to the first leaf - * partition, not the root table. - */ - if (node->rootResultRelInfo != NULL) - resultRelInfo = node->rootResultRelInfo; + ResultRelInfo *resultRelInfo = node->rootResultRelInfo; switch (node->operation) { @@ -1826,28 +1816,6 @@ fireBSTriggers(ModifyTableState *node) } } -/* - * Return the target rel ResultRelInfo. - * - * This relation is the same as : - * - the relation for which we will fire AFTER STATEMENT triggers. - * - the relation into whose tuple format all captured transition tuples must - * be converted. - * - the root partitioned table. - */ -static ResultRelInfo * -getTargetResultRelInfo(ModifyTableState *node) -{ - /* - * Note that if the node modifies a partitioned table, node->resultRelInfo - * points to the first leaf partition, not the root table. - */ - if (node->rootResultRelInfo != NULL) - return node->rootResultRelInfo; - else - return node->resultRelInfo; -} - /* * Process AFTER EACH STATEMENT triggers */ @@ -1855,7 +1823,7 @@ static void fireASTriggers(ModifyTableState *node) { ModifyTable *plan = (ModifyTable *) node->ps.plan; - ResultRelInfo *resultRelInfo = getTargetResultRelInfo(node); + ResultRelInfo *resultRelInfo = node->rootResultRelInfo; switch (node->operation) { @@ -1889,7 +1857,7 @@ static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate) { ModifyTable *plan = (ModifyTable *) mtstate->ps.plan; - ResultRelInfo *targetRelInfo = getTargetResultRelInfo(mtstate); + ResultRelInfo *targetRelInfo = mtstate->rootResultRelInfo; /* Check for transition tables on the directly targeted relation. */ mtstate->mt_transition_capture = @@ -2019,7 +1987,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate, static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate) { - ResultRelInfo *targetRelInfo = getTargetResultRelInfo(mtstate); + ResultRelInfo *targetRelInfo = mtstate->rootResultRelInfo; ResultRelInfo *resultRelInfos = mtstate->resultRelInfo; TupleDesc outdesc; int numResultRelInfos = mtstate->mt_nplans; @@ -2355,13 +2323,31 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) palloc(nplans * sizeof(ResultRelInfo)); mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans); - /* If modifying a partitioned table, initialize the root table info */ + /*---------- + * Resolve the target relation. This is the same as: + * + * - the relation for which we will fire FOR STATEMENT triggers, + * - the relation into whose tuple format all captured transition tuples + * must be converted, and + * - the root partitioned table used for tuple routing. + * + * If it's a partitioned table, the root partition doesn't appear + * elsewhere in the plan and its RT index is given explicitly in + * node->rootRelation. Otherwise (i.e. table inheritance) the target + * relation is the first relation in the node->resultRelations list, and + * we will initialize it in the loop below. + *---------- + */ if (node->rootRelation > 0) { mtstate->rootResultRelInfo = makeNode(ResultRelInfo); ExecInitResultRelation(estate, mtstate->rootResultRelInfo, node->rootRelation); } + else + { + mtstate->rootResultRelInfo = mtstate->resultRelInfo; + } mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans); mtstate->mt_nplans = nplans; @@ -2446,7 +2432,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) } /* Get the target relation */ - rel = (getTargetResultRelInfo(mtstate))->ri_RelationDesc; + rel = mtstate->rootResultRelInfo->ri_RelationDesc; /* * If it's not a partitioned table after all, UPDATE tuple routing should diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index b7e9e5d539..dff34fbc14 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1154,8 +1154,13 @@ typedef struct ModifyTableState TupleTableSlot **mt_scans; /* input tuple corresponding to underlying * plans */ ResultRelInfo *resultRelInfo; /* per-subplan target relations */ - ResultRelInfo *rootResultRelInfo; /* root target relation (partitioned - * table root) */ + + /* + * Target relation mentioned in the original statement, used to fire + * statement-level triggers and as the root for tuple routing. + */ + ResultRelInfo *rootResultRelInfo; + List **mt_arowmarks; /* per-subplan ExecAuxRowMark lists */ EPQState mt_epqstate; /* for evaluating EvalPlanQual rechecks */ bool fireBSTriggers; /* do we need to fire stmt triggers? */