aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/copy.c24
-rw-r--r--src/backend/commands/explain.c17
-rw-r--r--src/backend/commands/tablecmds.c9
-rw-r--r--src/backend/commands/trigger.c2
-rw-r--r--src/backend/executor/execMain.c256
-rw-r--r--src/backend/executor/execParallel.c1
-rw-r--r--src/backend/executor/execUtils.c57
-rw-r--r--src/backend/executor/nodeModifyTable.c24
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/outfuncs.c4
-rw-r--r--src/backend/nodes/readfuncs.c3
-rw-r--r--src/backend/optimizer/plan/createplan.c2
-rw-r--r--src/backend/optimizer/plan/planner.c3
-rw-r--r--src/backend/optimizer/plan/setrefs.c17
-rw-r--r--src/backend/replication/logical/worker.c32
-rw-r--r--src/include/executor/executor.h5
-rw-r--r--src/include/nodes/execnodes.h18
-rw-r--r--src/include/nodes/pathnodes.h2
-rw-r--r--src/include/nodes/plannodes.h8
19 files changed, 184 insertions, 303 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3c7dbad27a2..71d48d45743 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2727,6 +2727,7 @@ CopyFrom(CopyState cstate)
bool leafpart_use_multi_insert = false;
Assert(cstate->rel);
+ Assert(list_length(cstate->range_table) == 1);
/*
* The target must be a plain, foreign, or partitioned relation, or have
@@ -2829,25 +2830,17 @@ CopyFrom(CopyState cstate)
* index-entry-making machinery. (There used to be a huge amount of code
* here that basically duplicated execUtils.c ...)
*/
- resultRelInfo = makeNode(ResultRelInfo);
- InitResultRelInfo(resultRelInfo,
- cstate->rel,
- 1, /* must match rel's position in range_table */
- NULL,
- 0);
- target_resultRelInfo = resultRelInfo;
+ ExecInitRangeTable(estate, cstate->range_table);
+ resultRelInfo = target_resultRelInfo = makeNode(ResultRelInfo);
+ ExecInitResultRelation(estate, resultRelInfo, 1);
/* Verify the named relation is a valid target for INSERT */
CheckValidResultRel(resultRelInfo, CMD_INSERT);
ExecOpenIndices(resultRelInfo, false);
- estate->es_result_relations = resultRelInfo;
- estate->es_num_result_relations = 1;
estate->es_result_relation_info = resultRelInfo;
- ExecInitRangeTable(estate, cstate->range_table);
-
/*
* Set up a ModifyTableState so we can let FDW(s) init themselves for
* foreign-table result relation(s).
@@ -2856,7 +2849,7 @@ CopyFrom(CopyState cstate)
mtstate->ps.plan = NULL;
mtstate->ps.state = estate;
mtstate->operation = CMD_INSERT;
- mtstate->resultRelInfo = estate->es_result_relations;
+ mtstate->resultRelInfo = resultRelInfo;
if (resultRelInfo->ri_FdwRoutine != NULL &&
resultRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
@@ -3359,14 +3352,13 @@ CopyFrom(CopyState cstate)
if (insertMethod != CIM_SINGLE)
CopyMultiInsertInfoCleanup(&multiInsertInfo);
- ExecCloseIndices(target_resultRelInfo);
-
/* Close all the partitioned tables, leaf partitions, and their indices */
if (proute)
ExecCleanupTupleRouting(mtstate, proute);
- /* Close any trigger target relations */
- ExecCleanUpTriggerState(estate);
+ /* Close the result relations, including any trigger target relations */
+ ExecCloseResultRelations(estate);
+ ExecCloseRangeTableRelations(estate);
FreeExecutorState(estate);
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index c98c9b5547c..c8e292adfa6 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -769,27 +769,24 @@ ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
{
ResultRelInfo *rInfo;
bool show_relname;
- int numrels = queryDesc->estate->es_num_result_relations;
- int numrootrels = queryDesc->estate->es_num_root_result_relations;
+ List *resultrels;
List *routerels;
List *targrels;
- int nr;
ListCell *l;
+ resultrels = queryDesc->estate->es_opened_result_relations;
routerels = queryDesc->estate->es_tuple_routing_result_relations;
targrels = queryDesc->estate->es_trig_target_relations;
ExplainOpenGroup("Triggers", "Triggers", false, es);
- show_relname = (numrels > 1 || numrootrels > 0 ||
+ show_relname = (list_length(resultrels) > 1 ||
routerels != NIL || targrels != NIL);
- rInfo = queryDesc->estate->es_result_relations;
- for (nr = 0; nr < numrels; rInfo++, nr++)
- report_triggers(rInfo, show_relname, es);
-
- rInfo = queryDesc->estate->es_root_result_relations;
- for (nr = 0; nr < numrootrels; rInfo++, nr++)
+ foreach(l, resultrels)
+ {
+ rInfo = (ResultRelInfo *) lfirst(l);
report_triggers(rInfo, show_relname, es);
+ }
foreach(l, routerels)
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e0ac4e05e5f..80fedad5e04 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1787,6 +1787,11 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
/*
* To fire triggers, we'll need an EState as well as a ResultRelInfo for
* each relation. We don't need to call ExecOpenIndices, though.
+ *
+ * We put the ResultRelInfos in the es_opened_result_relations list, even
+ * though we don't have a range table and don't populate the
+ * es_result_relations array. That's a big bogus, but it's enough to make
+ * ExecGetTriggerResultRel() find them.
*/
estate = CreateExecutorState();
resultRelInfos = (ResultRelInfo *)
@@ -1801,10 +1806,10 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
0, /* dummy rangetable index */
NULL,
0);
+ estate->es_opened_result_relations =
+ lappend(estate->es_opened_result_relations, resultRelInfo);
resultRelInfo++;
}
- estate->es_result_relations = resultRelInfos;
- estate->es_num_result_relations = list_length(rels);
/*
* Process all BEFORE STATEMENT TRUNCATE triggers before we begin
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 672fccff5bd..3b4fbdadf4f 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -4227,7 +4227,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
if (local_estate)
{
- ExecCleanUpTriggerState(estate);
+ ExecCloseResultRelations(estate);
ExecResetTupleTable(estate->es_tupleTable, false);
FreeExecutorState(estate);
}
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 2e27e26ba44..783eecbc133 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -827,86 +827,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate->es_plannedstmt = plannedstmt;
- /*
- * Initialize ResultRelInfo data structures, and open the result rels.
- */
- if (plannedstmt->resultRelations)
- {
- List *resultRelations = plannedstmt->resultRelations;
- int numResultRelations = list_length(resultRelations);
- ResultRelInfo *resultRelInfos;
- ResultRelInfo *resultRelInfo;
-
- resultRelInfos = (ResultRelInfo *)
- palloc(numResultRelations * sizeof(ResultRelInfo));
- resultRelInfo = resultRelInfos;
- foreach(l, resultRelations)
- {
- Index resultRelationIndex = lfirst_int(l);
- Relation resultRelation;
-
- resultRelation = ExecGetRangeTableRelation(estate,
- resultRelationIndex);
- InitResultRelInfo(resultRelInfo,
- resultRelation,
- resultRelationIndex,
- NULL,
- estate->es_instrument);
- resultRelInfo++;
- }
- estate->es_result_relations = resultRelInfos;
- estate->es_num_result_relations = numResultRelations;
-
- /* es_result_relation_info is NULL except when within ModifyTable */
- estate->es_result_relation_info = NULL;
-
- /*
- * In the partitioned result relation case, also build ResultRelInfos
- * for all the partitioned table roots, because we will need them to
- * fire statement-level triggers, if any.
- */
- if (plannedstmt->rootResultRelations)
- {
- int num_roots = list_length(plannedstmt->rootResultRelations);
-
- resultRelInfos = (ResultRelInfo *)
- palloc(num_roots * sizeof(ResultRelInfo));
- resultRelInfo = resultRelInfos;
- foreach(l, plannedstmt->rootResultRelations)
- {
- Index resultRelIndex = lfirst_int(l);
- Relation resultRelDesc;
-
- resultRelDesc = ExecGetRangeTableRelation(estate,
- resultRelIndex);
- InitResultRelInfo(resultRelInfo,
- resultRelDesc,
- resultRelIndex,
- NULL,
- estate->es_instrument);
- resultRelInfo++;
- }
-
- estate->es_root_result_relations = resultRelInfos;
- estate->es_num_root_result_relations = num_roots;
- }
- else
- {
- estate->es_root_result_relations = NULL;
- estate->es_num_root_result_relations = 0;
- }
- }
- else
- {
- /*
- * if no result relation, then set state appropriately
- */
- estate->es_result_relations = NULL;
- estate->es_num_result_relations = 0;
- estate->es_result_relation_info = NULL;
- estate->es_root_result_relations = NULL;
- estate->es_num_root_result_relations = 0;
- }
+ /* es_result_relation_info is NULL except when within ModifyTable */
+ estate->es_result_relation_info = NULL;
/*
* Next, build the ExecRowMark array from the PlanRowMark(s), if any.
@@ -1334,8 +1256,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
*
* Most of the time, triggers are fired on one of the result relations of the
* query, and so we can just return a member of the es_result_relations array,
- * or the es_root_result_relations array (if any), or the
- * es_tuple_routing_result_relations list (if any). (Note: in self-join
+ * or the es_tuple_routing_result_relations list (if any). (Note: in self-join
* situations there might be multiple members with the same OID; if so it
* doesn't matter which one we pick.)
*
@@ -1352,30 +1273,16 @@ ResultRelInfo *
ExecGetTriggerResultRel(EState *estate, Oid relid)
{
ResultRelInfo *rInfo;
- int nr;
ListCell *l;
Relation rel;
MemoryContext oldcontext;
/* First, search through the query result relations */
- rInfo = estate->es_result_relations;
- nr = estate->es_num_result_relations;
- while (nr > 0)
+ foreach(l, estate->es_opened_result_relations)
{
+ rInfo = lfirst(l);
if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
return rInfo;
- rInfo++;
- nr--;
- }
- /* Second, search through the root result relations, if any */
- rInfo = estate->es_root_result_relations;
- nr = estate->es_num_root_result_relations;
- while (nr > 0)
- {
- if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
- return rInfo;
- rInfo++;
- nr--;
}
/*
@@ -1428,35 +1335,6 @@ ExecGetTriggerResultRel(EState *estate, Oid relid)
return rInfo;
}
-/*
- * Close any relations that have been opened by ExecGetTriggerResultRel().
- */
-void
-ExecCleanUpTriggerState(EState *estate)
-{
- ListCell *l;
-
- foreach(l, estate->es_trig_target_relations)
- {
- ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
-
- /*
- * Assert this is a "dummy" ResultRelInfo, see above. Otherwise we
- * might be issuing a duplicate close against a Relation opened by
- * ExecGetRangeTableRelation.
- */
- Assert(resultRelInfo->ri_RangeTableIndex == 0);
-
- /*
- * Since ExecGetTriggerResultRel doesn't call ExecOpenIndices for
- * these rels, we needn't call ExecCloseIndices either.
- */
- Assert(resultRelInfo->ri_NumIndices == 0);
-
- table_close(resultRelInfo->ri_RelationDesc, NoLock);
- }
-}
-
/* ----------------------------------------------------------------
* ExecPostprocessPlan
*
@@ -1512,9 +1390,6 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
- ResultRelInfo *resultRelInfo;
- Index num_relations;
- Index i;
ListCell *l;
/*
@@ -1541,29 +1416,69 @@ ExecEndPlan(PlanState *planstate, EState *estate)
ExecResetTupleTable(estate->es_tupleTable, false);
/*
- * close indexes of result relation(s) if any. (Rels themselves get
- * closed next.)
+ * Close any Relations that have been opened for range table entries or
+ * result relations.
*/
- resultRelInfo = estate->es_result_relations;
- for (i = estate->es_num_result_relations; i > 0; i--)
+ ExecCloseResultRelations(estate);
+ ExecCloseRangeTableRelations(estate);
+}
+
+/*
+ * Close any relations that have been opened for ResultRelInfos.
+ */
+void
+ExecCloseResultRelations(EState *estate)
+{
+ ListCell *l;
+
+ /*
+ * close indexes of result relation(s) if any. (Rels themselves are
+ * closed in ExecCloseRangeTableRelations())
+ */
+ foreach(l, estate->es_opened_result_relations)
{
+ ResultRelInfo *resultRelInfo = lfirst(l);
+
ExecCloseIndices(resultRelInfo);
- resultRelInfo++;
}
- /*
- * close whatever rangetable Relations have been opened. We do not
- * release any locks we might hold on those rels.
- */
- num_relations = estate->es_range_table_size;
- for (i = 0; i < num_relations; i++)
+ /* Close any relations that have been opened by ExecGetTriggerResultRel(). */
+ foreach(l, estate->es_trig_target_relations)
+ {
+ ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
+
+ /*
+ * Assert this is a "dummy" ResultRelInfo, see above. Otherwise we
+ * might be issuing a duplicate close against a Relation opened by
+ * ExecGetRangeTableRelation.
+ */
+ Assert(resultRelInfo->ri_RangeTableIndex == 0);
+
+ /*
+ * Since ExecGetTriggerResultRel doesn't call ExecOpenIndices for
+ * these rels, we needn't call ExecCloseIndices either.
+ */
+ Assert(resultRelInfo->ri_NumIndices == 0);
+
+ table_close(resultRelInfo->ri_RelationDesc, NoLock);
+ }
+}
+
+/*
+ * Close all relations opened by ExecGetRangeTableRelation().
+ *
+ * We do not release any locks we might hold on those rels.
+ */
+void
+ExecCloseRangeTableRelations(EState *estate)
+{
+ int i;
+
+ for (i = 0; i < estate->es_range_table_size; i++)
{
if (estate->es_relations[i])
table_close(estate->es_relations[i], NoLock);
}
-
- /* likewise close any trigger target relations */
- ExecCleanUpTriggerState(estate);
}
/* ----------------------------------------------------------------
@@ -2758,17 +2673,9 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
/*
* Child EPQ EStates share the parent's copy of unchanging state such as
- * the snapshot, rangetable, result-rel info, and external Param info.
- * They need their own copies of local state, including a tuple table,
- * es_param_exec_vals, etc.
- *
- * The ResultRelInfo array management is trickier than it looks. We
- * create fresh arrays for the child but copy all the content from the
- * parent. This is because it's okay for the child to share any
- * per-relation state the parent has already created --- but if the child
- * sets up any ResultRelInfo fields, such as its own junkfilter, that
- * state must *not* propagate back to the parent. (For one thing, the
- * pointed-to data is in a memory context that won't last long enough.)
+ * the snapshot, rangetable, and external Param info. They need their own
+ * copies of local state, including a tuple table, es_param_exec_vals,
+ * result-rel info, etc.
*/
rcestate->es_direction = ForwardScanDirection;
rcestate->es_snapshot = parentestate->es_snapshot;
@@ -2781,30 +2688,12 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
rcestate->es_plannedstmt = parentestate->es_plannedstmt;
rcestate->es_junkFilter = parentestate->es_junkFilter;
rcestate->es_output_cid = parentestate->es_output_cid;
- if (parentestate->es_num_result_relations > 0)
- {
- int numResultRelations = parentestate->es_num_result_relations;
- int numRootResultRels = parentestate->es_num_root_result_relations;
- ResultRelInfo *resultRelInfos;
-
- resultRelInfos = (ResultRelInfo *)
- palloc(numResultRelations * sizeof(ResultRelInfo));
- memcpy(resultRelInfos, parentestate->es_result_relations,
- numResultRelations * sizeof(ResultRelInfo));
- rcestate->es_result_relations = resultRelInfos;
- rcestate->es_num_result_relations = numResultRelations;
-
- /* Also transfer partitioned root result relations. */
- if (numRootResultRels > 0)
- {
- resultRelInfos = (ResultRelInfo *)
- palloc(numRootResultRels * sizeof(ResultRelInfo));
- memcpy(resultRelInfos, parentestate->es_root_result_relations,
- numRootResultRels * sizeof(ResultRelInfo));
- rcestate->es_root_result_relations = resultRelInfos;
- rcestate->es_num_root_result_relations = numRootResultRels;
- }
- }
+
+ /*
+ * ResultRelInfos needed by subplans are initialized from scratch when the
+ * subplans themselves are initialized.
+ */
+ parentestate->es_result_relations = NULL;
/* es_result_relation_info must NOT be copied */
/* es_trig_target_relations must NOT be copied */
rcestate->es_top_eflags = parentestate->es_top_eflags;
@@ -2914,8 +2803,9 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
* This is a cut-down version of ExecutorEnd(); basically we want to do most
* of the normal cleanup, but *not* close result relations (which we are
* just sharing from the outer query). We do, however, have to close any
- * trigger target relations that got opened, since those are not shared.
- * (There probably shouldn't be any of the latter, but just in case...)
+ * result and trigger target relations that got opened, since those are not
+ * shared. (There probably shouldn't be any of the latter, but just in
+ * case...)
*/
void
EvalPlanQualEnd(EPQState *epqstate)
@@ -2957,8 +2847,8 @@ EvalPlanQualEnd(EPQState *epqstate)
/* throw away the per-estate tuple table, some node may have used it */
ExecResetTupleTable(estate->es_tupleTable, false);
- /* close any trigger target relations attached to this EState */
- ExecCleanUpTriggerState(estate);
+ /* Close any result and trigger target relations attached to this EState */
+ ExecCloseResultRelations(estate);
MemoryContextSwitchTo(oldcontext);
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 382e78fb7fe..befde526910 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -184,7 +184,6 @@ ExecSerializePlan(Plan *plan, EState *estate)
pstmt->planTree = plan;
pstmt->rtable = estate->es_range_table;
pstmt->resultRelations = NIL;
- pstmt->rootResultRelations = NIL;
pstmt->appendRelations = NIL;
/*
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d0e65b86473..6d8c112e2fe 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -124,14 +124,9 @@ CreateExecutorState(void)
estate->es_output_cid = (CommandId) 0;
estate->es_result_relations = NULL;
- estate->es_num_result_relations = 0;
+ estate->es_opened_result_relations = NIL;
estate->es_result_relation_info = NULL;
-
- estate->es_root_result_relations = NULL;
- estate->es_num_root_result_relations = 0;
-
estate->es_tuple_routing_result_relations = NIL;
-
estate->es_trig_target_relations = NIL;
estate->es_param_list_info = NULL;
@@ -711,16 +706,7 @@ ExecCreateScanSlotFromOuterPlan(EState *estate,
bool
ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
{
- ResultRelInfo *resultRelInfos;
- int i;
-
- resultRelInfos = estate->es_result_relations;
- for (i = 0; i < estate->es_num_result_relations; i++)
- {
- if (resultRelInfos[i].ri_RangeTableIndex == scanrelid)
- return true;
- }
- return false;
+ return list_member_int(estate->es_plannedstmt->resultRelations, scanrelid);
}
/* ----------------------------------------------------------------
@@ -779,9 +765,10 @@ ExecInitRangeTable(EState *estate, List *rangeTable)
palloc0(estate->es_range_table_size * sizeof(Relation));
/*
- * es_rowmarks is also parallel to the es_range_table, but it's allocated
- * only if needed.
+ * es_result_relations and es_rowmarks are also parallel to
+ * es_range_table, but are allocated only if needed.
*/
+ estate->es_result_relations = NULL;
estate->es_rowmarks = NULL;
}
@@ -836,6 +823,40 @@ ExecGetRangeTableRelation(EState *estate, Index rti)
}
/*
+ * ExecInitResultRelation
+ * Open relation given by the passed-in RT index and fill its
+ * ResultRelInfo node
+ *
+ * Here, we also save the ResultRelInfo in estate->es_result_relations array
+ * such that it can be accessed later using the RT index.
+ */
+void
+ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
+ Index rti)
+{
+ Relation resultRelationDesc;
+
+ resultRelationDesc = ExecGetRangeTableRelation(estate, rti);
+ InitResultRelInfo(resultRelInfo,
+ resultRelationDesc,
+ rti,
+ NULL,
+ estate->es_instrument);
+
+ if (estate->es_result_relations == NULL)
+ estate->es_result_relations = (ResultRelInfo **)
+ palloc0(estate->es_range_table_size * sizeof(ResultRelInfo *));
+ estate->es_result_relations[rti - 1] = resultRelInfo;
+
+ /*
+ * Saving in the list allows to avoid needlessly traversing the whole
+ * array when only a few of its entries are possibly non-NULL.
+ */
+ estate->es_opened_result_relations =
+ lappend(estate->es_opened_result_relations, resultRelInfo);
+}
+
+/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
*/
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 98120891619..b3f7012e386 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2301,7 +2301,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
ResultRelInfo *saved_resultRelInfo;
ResultRelInfo *resultRelInfo;
Plan *subplan;
- ListCell *l;
+ ListCell *l,
+ *l1;
int i;
Relation rel;
bool update_tuple_routing_needed = node->partColsUpdated;
@@ -2322,13 +2323,17 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_done = false;
mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
- mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
+ mtstate->resultRelInfo = (ResultRelInfo *)
+ palloc(nplans * sizeof(ResultRelInfo));
mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
/* If modifying a partitioned table, initialize the root table info */
- if (node->rootResultRelIndex >= 0)
- mtstate->rootResultRelInfo = estate->es_root_result_relations +
- node->rootResultRelIndex;
+ if (node->rootRelation > 0)
+ {
+ mtstate->rootResultRelInfo = makeNode(ResultRelInfo);
+ ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
+ node->rootRelation);
+ }
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
mtstate->mt_nplans = nplans;
@@ -2351,9 +2356,14 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
resultRelInfo = mtstate->resultRelInfo;
i = 0;
- foreach(l, node->plans)
+ forboth(l, node->resultRelations, l1, node->plans)
{
- subplan = (Plan *) lfirst(l);
+ Index resultRelation = lfirst_int(l);
+
+ subplan = (Plan *) lfirst(l1);
+
+ /* This opens the relation and fills ResultRelInfo. */
+ ExecInitResultRelation(estate, resultRelInfo, resultRelation);
/* Initialize the usesFdwDirectModify flag */
resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 0409a40b82a..4d79f70950b 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -91,7 +91,6 @@ _copyPlannedStmt(const PlannedStmt *from)
COPY_NODE_FIELD(planTree);
COPY_NODE_FIELD(rtable);
COPY_NODE_FIELD(resultRelations);
- COPY_NODE_FIELD(rootResultRelations);
COPY_NODE_FIELD(appendRelations);
COPY_NODE_FIELD(subplans);
COPY_BITMAPSET_FIELD(rewindPlanIDs);
@@ -207,8 +206,6 @@ _copyModifyTable(const ModifyTable *from)
COPY_SCALAR_FIELD(rootRelation);
COPY_SCALAR_FIELD(partColsUpdated);
COPY_NODE_FIELD(resultRelations);
- COPY_SCALAR_FIELD(resultRelIndex);
- COPY_SCALAR_FIELD(rootResultRelIndex);
COPY_NODE_FIELD(plans);
COPY_NODE_FIELD(withCheckOptionLists);
COPY_NODE_FIELD(returningLists);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index f0386480ab8..f441ae3c519 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -309,7 +309,6 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_NODE_FIELD(planTree);
WRITE_NODE_FIELD(rtable);
WRITE_NODE_FIELD(resultRelations);
- WRITE_NODE_FIELD(rootResultRelations);
WRITE_NODE_FIELD(appendRelations);
WRITE_NODE_FIELD(subplans);
WRITE_BITMAPSET_FIELD(rewindPlanIDs);
@@ -408,8 +407,6 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
WRITE_UINT_FIELD(rootRelation);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
- WRITE_INT_FIELD(resultRelIndex);
- WRITE_INT_FIELD(rootResultRelIndex);
WRITE_NODE_FIELD(plans);
WRITE_NODE_FIELD(withCheckOptionLists);
WRITE_NODE_FIELD(returningLists);
@@ -2194,7 +2191,6 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
WRITE_NODE_FIELD(finalrtable);
WRITE_NODE_FIELD(finalrowmarks);
WRITE_NODE_FIELD(resultRelations);
- WRITE_NODE_FIELD(rootResultRelations);
WRITE_NODE_FIELD(appendRelations);
WRITE_NODE_FIELD(relationOids);
WRITE_NODE_FIELD(invalItems);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 42050ab7195..3a54765f5ca 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1542,7 +1542,6 @@ _readPlannedStmt(void)
READ_NODE_FIELD(planTree);
READ_NODE_FIELD(rtable);
READ_NODE_FIELD(resultRelations);
- READ_NODE_FIELD(rootResultRelations);
READ_NODE_FIELD(appendRelations);
READ_NODE_FIELD(subplans);
READ_BITMAPSET_FIELD(rewindPlanIDs);
@@ -1639,8 +1638,6 @@ _readModifyTable(void)
READ_UINT_FIELD(rootRelation);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
- READ_INT_FIELD(resultRelIndex);
- READ_INT_FIELD(rootResultRelIndex);
READ_NODE_FIELD(plans);
READ_NODE_FIELD(withCheckOptionLists);
READ_NODE_FIELD(returningLists);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 3d7a4e373fb..881eaf48133 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -6808,8 +6808,6 @@ make_modifytable(PlannerInfo *root,
node->rootRelation = rootRelation;
node->partColsUpdated = partColsUpdated;
node->resultRelations = resultRelations;
- node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
- node->rootResultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;
if (!onconflict)
{
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index f331f82a6c2..986d7a52e32 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -305,7 +305,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
glob->finalrtable = NIL;
glob->finalrowmarks = NIL;
glob->resultRelations = NIL;
- glob->rootResultRelations = NIL;
glob->appendRelations = NIL;
glob->relationOids = NIL;
glob->invalItems = NIL;
@@ -493,7 +492,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
Assert(glob->finalrtable == NIL);
Assert(glob->finalrowmarks == NIL);
Assert(glob->resultRelations == NIL);
- Assert(glob->rootResultRelations == NIL);
Assert(glob->appendRelations == NIL);
top_plan = set_plan_references(root, top_plan);
/* ... and the subplans (both regular subplans and initplans) */
@@ -520,7 +518,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
result->planTree = top_plan;
result->rtable = glob->finalrtable;
result->resultRelations = glob->resultRelations;
- result->rootResultRelations = glob->rootResultRelations;
result->appendRelations = glob->appendRelations;
result->subplans = glob->subplans;
result->rewindPlanIDs = glob->rewindPlanIDs;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index dd8e2e966dd..6847ff6f447 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -975,26 +975,15 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
/*
* Append this ModifyTable node's final result relation RT
- * index(es) to the global list for the plan, and set its
- * resultRelIndex to reflect their starting position in the
- * global list.
+ * index(es) to the global list for the plan.
*/
- splan->resultRelIndex = list_length(root->glob->resultRelations);
root->glob->resultRelations =
list_concat(root->glob->resultRelations,
splan->resultRelations);
-
- /*
- * If the main target relation is a partitioned table, also
- * add the partition root's RT index to rootResultRelations,
- * and remember its index in that list in rootResultRelIndex.
- */
if (splan->rootRelation)
{
- splan->rootResultRelIndex =
- list_length(root->glob->rootResultRelations);
- root->glob->rootResultRelations =
- lappend_int(root->glob->rootResultRelations,
+ root->glob->resultRelations =
+ lappend_int(root->glob->resultRelations,
splan->rootRelation);
}
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 9c6fdeeb56c..8d5d9e05b3c 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -344,7 +344,6 @@ static EState *
create_estate_for_relation(LogicalRepRelMapEntry *rel)
{
EState *estate;
- ResultRelInfo *resultRelInfo;
RangeTblEntry *rte;
estate = CreateExecutorState();
@@ -356,13 +355,6 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
rte->rellockmode = AccessShareLock;
ExecInitRangeTable(estate, list_make1(rte));
- resultRelInfo = makeNode(ResultRelInfo);
- InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
-
- estate->es_result_relations = resultRelInfo;
- estate->es_num_result_relations = 1;
- estate->es_result_relation_info = resultRelInfo;
-
estate->es_output_cid = GetCurrentCommandId(true);
/* Prepare to catch AFTER triggers. */
@@ -1150,6 +1142,7 @@ GetRelationIdentityOrPK(Relation rel)
static void
apply_handle_insert(StringInfo s)
{
+ ResultRelInfo *resultRelInfo;
LogicalRepRelMapEntry *rel;
LogicalRepTupleData newtup;
LogicalRepRelId relid;
@@ -1179,6 +1172,9 @@ apply_handle_insert(StringInfo s)
remoteslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel),
&TTSOpsVirtual);
+ resultRelInfo = makeNode(ResultRelInfo);
+ InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
+ estate->es_result_relation_info = resultRelInfo;
/* Input functions may need an active snapshot, so get one */
PushActiveSnapshot(GetTransactionSnapshot());
@@ -1191,10 +1187,10 @@ apply_handle_insert(StringInfo s)
/* For a partitioned table, insert the tuple into a partition. */
if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+ apply_handle_tuple_routing(resultRelInfo, estate,
remoteslot, NULL, rel, CMD_INSERT);
else
- apply_handle_insert_internal(estate->es_result_relation_info, estate,
+ apply_handle_insert_internal(resultRelInfo, estate,
remoteslot);
PopActiveSnapshot();
@@ -1265,6 +1261,7 @@ check_relation_updatable(LogicalRepRelMapEntry *rel)
static void
apply_handle_update(StringInfo s)
{
+ ResultRelInfo *resultRelInfo;
LogicalRepRelMapEntry *rel;
LogicalRepRelId relid;
EState *estate;
@@ -1301,6 +1298,9 @@ apply_handle_update(StringInfo s)
remoteslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel),
&TTSOpsVirtual);
+ resultRelInfo = makeNode(ResultRelInfo);
+ InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
+ estate->es_result_relation_info = resultRelInfo;
/*
* Populate updatedCols so that per-column triggers can fire. This could
@@ -1337,10 +1337,10 @@ apply_handle_update(StringInfo s)
/* For a partitioned table, apply update to correct partition. */
if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+ apply_handle_tuple_routing(resultRelInfo, estate,
remoteslot, &newtup, rel, CMD_UPDATE);
else
- apply_handle_update_internal(estate->es_result_relation_info, estate,
+ apply_handle_update_internal(resultRelInfo, estate,
remoteslot, &newtup, rel);
PopActiveSnapshot();
@@ -1420,6 +1420,7 @@ apply_handle_update_internal(ResultRelInfo *relinfo,
static void
apply_handle_delete(StringInfo s)
{
+ ResultRelInfo *resultRelInfo;
LogicalRepRelMapEntry *rel;
LogicalRepTupleData oldtup;
LogicalRepRelId relid;
@@ -1452,6 +1453,9 @@ apply_handle_delete(StringInfo s)
remoteslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel),
&TTSOpsVirtual);
+ resultRelInfo = makeNode(ResultRelInfo);
+ InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
+ estate->es_result_relation_info = resultRelInfo;
PushActiveSnapshot(GetTransactionSnapshot());
@@ -1462,10 +1466,10 @@ apply_handle_delete(StringInfo s)
/* For a partitioned table, apply delete to correct partition. */
if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+ apply_handle_tuple_routing(resultRelInfo, estate,
remoteslot, NULL, rel, CMD_DELETE);
else
- apply_handle_delete_internal(estate->es_result_relation_info, estate,
+ apply_handle_delete_internal(resultRelInfo, estate,
remoteslot, &rel->remoterel);
PopActiveSnapshot();
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 415e117407c..c283bf14541 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -191,7 +191,6 @@ extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
Relation partition_root,
int instrument_options);
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
-extern void ExecCleanUpTriggerState(EState *estate);
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern bool ExecPartitionCheck(ResultRelInfo *resultRelInfo,
@@ -538,6 +537,8 @@ extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
extern void ExecInitRangeTable(EState *estate, List *rangeTable);
+extern void ExecCloseRangeTableRelations(EState *estate);
+extern void ExecCloseResultRelations(EState *estate);
static inline RangeTblEntry *
exec_rt_fetch(Index rti, EState *estate)
@@ -546,6 +547,8 @@ exec_rt_fetch(Index rti, EState *estate)
}
extern Relation ExecGetRangeTableRelation(EState *estate, Index rti);
+extern void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
+ Index rti);
extern int executor_errposition(EState *estate, int location);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index ef448d67c77..a926ff17118 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -519,23 +519,19 @@ typedef struct EState
CommandId es_output_cid;
/* Info about target table(s) for insert/update/delete queries: */
- ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
- int es_num_result_relations; /* length of array */
+ ResultRelInfo **es_result_relations; /* Array of per-range-table-entry
+ * ResultRelInfo pointers, or NULL
+ * if not a target table */
+ List *es_opened_result_relations; /* List of non-NULL entries in
+ * es_result_relations in no
+ * specific order */
ResultRelInfo *es_result_relation_info; /* currently active array elt */
- /*
- * Info about the partition root table(s) for insert/update/delete queries
- * targeting partitioned tables. Only leaf partitions are mentioned in
- * es_result_relations, but we need access to the roots for firing
- * triggers and for runtime tuple routing.
- */
- ResultRelInfo *es_root_result_relations; /* array of ResultRelInfos */
- int es_num_root_result_relations; /* length of the array */
PartitionDirectory es_partition_directory; /* for PartitionDesc lookup */
/*
* The following list contains ResultRelInfos created by the tuple routing
- * code for partitions that don't already have one.
+ * code for partitions that aren't found in the es_result_relations array.
*/
List *es_tuple_routing_result_relations;
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index dbe86e7af65..3dd16b9ad53 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -120,8 +120,6 @@ typedef struct PlannerGlobal
List *resultRelations; /* "flat" list of integer RT indexes */
- List *rootResultRelations; /* "flat" list of integer RT indexes */
-
List *appendRelations; /* "flat" list of AppendRelInfos */
List *relationOids; /* OIDs of relations the plan depends on */
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 83e01074ed1..a7bdf3497e1 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -68,12 +68,6 @@ typedef struct PlannedStmt
/* rtable indexes of target relations for INSERT/UPDATE/DELETE */
List *resultRelations; /* integer list of RT indexes, or NIL */
- /*
- * rtable indexes of partitioned table roots that are UPDATE/DELETE
- * targets; needed for trigger firing.
- */
- List *rootResultRelations;
-
List *appendRelations; /* list of AppendRelInfo nodes */
List *subplans; /* Plan trees for SubPlan expressions; note
@@ -224,8 +218,6 @@ typedef struct ModifyTable
Index rootRelation; /* Root RT index, if target is partitioned */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
- int resultRelIndex; /* index of first resultRel in plan's list */
- int rootResultRelIndex; /* index of the partitioned table root */
List *plans; /* plan(s) producing source data */
List *withCheckOptionLists; /* per-target-table WCO lists */
List *returningLists; /* per-target-table RETURNING tlists */