Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Create ResultRelInfos later in InitPlan, index them by RT index.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 13 Oct 2020 09:57:02 +0000 (12:57 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 13 Oct 2020 09:57:02 +0000 (12:57 +0300)
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

19 files changed:
src/backend/commands/copy.c
src/backend/commands/explain.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/executor/execMain.c
src/backend/executor/execParallel.c
src/backend/executor/execUtils.c
src/backend/executor/nodeModifyTable.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/backend/replication/logical/worker.c
src/include/executor/executor.h
src/include/nodes/execnodes.h
src/include/nodes/pathnodes.h
src/include/nodes/plannodes.h

index 3c7dbad27a21bba97c44beeee427df9bf8dad8bf..71d48d45743b6564b7bdbba06e260ac37ca06493 100644 (file)
@@ -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);
 
index c98c9b5547c5a5a08fa98040f239bb13a85a54ae..c8e292adfa63e797cd52fc6a4844665209751580 100644 (file)
@@ -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)
    {
index e0ac4e05e5f5a0e64aac45e6c6cb5fb8cde8c091..80fedad5e045bbab15e942ce4104a9048abf7f29 100644 (file)
@@ -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
index 672fccff5bd15ff5be50fcb7eb9f7dc8feea725e..3b4fbdadf4f3138db7e1b8979020d3249483b05c 100644 (file)
@@ -4227,7 +4227,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
 
    if (local_estate)
    {
-       ExecCleanUpTriggerState(estate);
+       ExecCloseResultRelations(estate);
        ExecResetTupleTable(estate->es_tupleTable, false);
        FreeExecutorState(estate);
    }
index 2e27e26ba44652b51fc2c9603f93730e945744ad..783eecbc13375da8baaf540e3b63a1691794821c 100644 (file)
@@ -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);
 
index 382e78fb7fed23b872cf1919b25b645dec9c03a6..befde526910aea022fe608ab91b39a9d59d8b2c4 100644 (file)
@@ -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;
 
    /*
index d0e65b86473d690752d45cab1018bc4d9bf1649b..6d8c112e2fe4acfcf8b0db4bf95b87e597bbabdb 100644 (file)
@@ -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;
 }
 
@@ -835,6 +822,40 @@ ExecGetRangeTableRelation(EState *estate, Index rti)
    return rel;
 }
 
+/*
+ * 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
index 98120891619b0ecb0f24d4f93af11bdc6347d368..b3f7012e38699448926f8272926f831f431a5ad7 100644 (file)
@@ -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,
index 0409a40b82a839b4245c256718c483d7e699c7fc..4d79f70950b7613cb8bae1b0c27dac1002588597 100644 (file)
@@ -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);
index f0386480ab890c6ed24dcd3b442a3cc50c9ca1f7..f441ae3c5192822118911d6b063f405686acace6 100644 (file)
@@ -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);
index 42050ab71955a134aa3d99b287fcdcd3b5cf78d2..3a54765f5ca16bcdebf74a86f846eefac9a28647 100644 (file)
@@ -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);
index 3d7a4e373fb5277ac4b477edecd9abda39959c3c..881eaf481339a4d857066a8c999b0146636dad2d 100644 (file)
@@ -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)
    {
index f331f82a6c200e56adc66f145f57ed8f080a3af1..986d7a52e32ca49841f0574b6565afab97c5ed0b 100644 (file)
@@ -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;
index dd8e2e966ddd4373671b304b8074bafe31231733..6847ff6f44738c2f1546b3866f8b1ec32ca9be73 100644 (file)
@@ -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);
                }
            }
index 9c6fdeeb56c46f1f97e42619dc87d1c3dafa86e2..8d5d9e05b3c0474a41d237efe74e8fcead41f2c8 100644 (file)
@@ -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();
index 415e117407c9688e9ca9422efff9aaae221255ca..c283bf14541cc8128c23ef263248b2477a5b14f5 100644 (file)
@@ -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);
 
index ef448d67c77d9ad6a681c984173efc455db34aea..a926ff17118bf12fe5e0cba8616e26f096f910fc 100644 (file)
@@ -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;
 
index dbe86e7af6571e91273cb0613d872b8e860a0dd3..3dd16b9ad534f35e95e22d1d34d4656c9ab21a79 100644 (file)
@@ -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 */
index 83e01074ed1d289103f69c04e534968f2eda5978..a7bdf3497e1385ee2189c5eca42bc54ecff43d4b 100644 (file)
@@ -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 */