aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2020-10-13 12:57:02 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2020-10-13 12:57:02 +0300
commit1375422c7826a2bf387be29895e961614f69de4b (patch)
tree17299eebfa3734f796d84ad44f3e5ab9f5557259 /src/backend/executor/execMain.c
parent2050832d0d637358a376a99514071941aa93ed31 (diff)
downloadpostgresql-1375422c7826a2bf387be29895e961614f69de4b.tar.gz
postgresql-1375422c7826a2bf387be29895e961614f69de4b.zip
Create ResultRelInfos later in InitPlan, index them by RT index.
Instead of allocating all the ResultRelInfos upfront in one big array, allocate them in ExecInitModifyTable(). es_result_relations is now an array of ResultRelInfo pointers, rather than an array of structs, and it is indexed by the RT index. This simplifies things: we get rid of the separate concept of a "result rel index", and don't need to set it in setrefs.c anymore. This also allows follow-up optimizations (not included in this commit yet) to skip initializing ResultRelInfos for target relations that were not needed at runtime, and removal of the es_result_relation_info pointer. The EState arrays of regular result rels and root result rels are merged into one array. Similarly, the resultRelations and rootResultRelations lists in PlannedStmt are merged into one. It's not actually clear to me why they were kept separate in the first place, but now that the es_result_relations array is indexed by RT index, it certainly seems pointless. The PlannedStmt->resultRelations list is now only needed for ExecRelationIsTargetRelation(). One visible effect of this change is that ExecRelationIsTargetRelation() will now return 'true' also for the partition root, if a partitioned table is updated. That seems like a good thing, although the function isn't used in core code, and I don't see any reason for an FDW to call it on a partition root. Author: Amit Langote Discussion: https://www.postgresql.org/message-id/CA%2BHiwqGEmiib8FLiHMhKB%2BCH5dRgHSLc5N5wnvc4kym%2BZYpQEQ%40mail.gmail.com
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c256
1 files changed, 73 insertions, 183 deletions
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);