On 2018/08/16 17:22, Amit Langote wrote:
> 0004-Revise-executor-range-table-relation-opening-closing.patch
> 
> This adds two arrays to EState indexed by RT indexes, one for
> RangeTblEntry's and another for Relation pointers.  The former reduces the
> cost of fetching RangeTblEntry by RT index.  The latter is used by a newly
> introduced function ExecRangeTableRelation(), which replaces heap_open for
> relations that are contained in the range table.  If a given RTE's
> relation is opened by multiple times, only the first call of
> ExecRangeTableRelation will go to relcache.

David Rowely recently, independently [1], proposed one of the ideas
mentioned above (store RangeTblEntry's in an array in EState).  As I
mentioned in reply to his email, I think his implementation of the idea is
better than mine, so I've merged his patch in the above patch, except one
part: instead of removing the es_range_table list altogether, I decided to
keep it around so that ExecSerializePlan doesn't have to build one all
over again from the array like his patch did.

Updated patches attached; 0001-0003 are same as v1.

Thanks,
Amit

[1] Make executor's Range Table an array instead of a List
https://postgr.es/m/CAKJS1f9EypD_=xG6ACFdF=1cbjz+z9hihhsd-rqljor+qya...@mail.gmail.com
From e46911bd7bb621b66c8d693132d4aeb3202d73df Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v2 1/4] Don't lock range table relations in the executor

As noted in https://postgre.es/m/4114.1531674142%40sss.pgh.pa.us,
taking relation locks inside the executor proper is redundant, because
appropriate locks should've been taken by the upstream code, that is,
during the parse/rewrite/plan pipeline when adding the relations to
range table or by the AcquireExecutorLocks if using a cached plan.

Also, InitPlan would do certain initiaization steps, such as creating
result rels, ExecRowMarks, etc. only because of the concerns about
locking order, which it needs not to do anymore, because we've
eliminated executor locking at all.  Instead create result rels and
ExecRowMarks, etc. in the ExecInit* routines of the respective nodes.

To indicate which lock was taken on a relation before creating a
RTE_RELATION range table entry for it, add a 'lockmode' field to
RangeTblEntry.  It's set when the relation is opened for the first
time in the parse/rewrite/plan pipeline and its range table entry
created.
---
 src/backend/commands/view.c            |   2 +
 src/backend/executor/execMain.c        | 269 ++++++++++++---------------------
 src/backend/executor/execPartition.c   |   4 +-
 src/backend/executor/execUtils.c       |  24 +--
 src/backend/executor/nodeLockRows.c    |   2 +-
 src/backend/executor/nodeModifyTable.c |  39 ++++-
 src/backend/nodes/copyfuncs.c          |   1 +
 src/backend/nodes/equalfuncs.c         |   1 +
 src/backend/nodes/outfuncs.c           |   1 +
 src/backend/nodes/readfuncs.c          |   1 +
 src/backend/parser/analyze.c           |   1 +
 src/backend/parser/parse_clause.c      |   1 +
 src/backend/parser/parse_relation.c    |   1 +
 src/backend/parser/parse_utilcmd.c     |   4 +
 src/backend/rewrite/rewriteHandler.c   |  18 +--
 src/backend/storage/lmgr/lmgr.c        |   7 +-
 src/backend/utils/cache/plancache.c    |  26 +---
 src/include/executor/executor.h        |   2 +-
 src/include/nodes/parsenodes.h         |   1 +
 src/include/storage/lmgr.h             |   2 +-
 20 files changed, 166 insertions(+), 241 deletions(-)

diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..818557d796 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -388,9 +388,11 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
        rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
                                                                                
          makeAlias("old", NIL),
                                                                                
          false, false);
+       rt_entry1->lockmode = AccessShareLock;
        rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
                                                                                
          makeAlias("new", NIL),
                                                                                
          false, false);
+       rt_entry2->lockmode = AccessShareLock;
        /* Must override addRangeTableEntry's default access-check flags */
        rt_entry1->requiredPerms = 0;
        rt_entry2->requiredPerms = 0;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index c583e020a0..298bf43fce 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -50,10 +50,12 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
+#include "optimizer/prep.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
+#include "storage/lockdefs.h"
 #include "tcop/utility.h"
 #include "utils/acl.h"
 #include "utils/lsyscache.h"
@@ -818,6 +820,26 @@ InitPlan(QueryDesc *queryDesc, int eflags)
         */
        ExecCheckRTPerms(rangeTable, true);
 
+#ifdef USE_ASSERT_CHECKING
+       foreach(l, rangeTable)
+       {
+               RangeTblEntry *rte = lfirst(l);
+
+               if (rte->rtekind == RTE_RELATION && OidIsValid(rte->relid))
+               {
+                       /*
+                        * The following asserts that no new lock needed to be 
taken,
+                        * meaning the upstream code already acquired the 
needed locks.
+                        */
+                       Assert(rte->lockmode != NoLock);
+                       if (LockRelationOid(rte->relid, rte->lockmode) &&
+                               !IsParallelWorker())
+                               elog(NOTICE, "InitPlan: lock on \"%s\" not 
already taken",
+                                        get_rel_name(rte->relid));
+               }
+       }
+#endif
+
        /*
         * initialize the node's execution state
         */
@@ -832,85 +854,19 @@ InitPlan(QueryDesc *queryDesc, int eflags)
         */
        if (plannedstmt->resultRelations)
        {
-               List       *resultRelations = plannedstmt->resultRelations;
-               int                     numResultRelations = 
list_length(resultRelations);
-               ResultRelInfo *resultRelInfos;
-               ResultRelInfo *resultRelInfo;
+               int             numResultRelations = 
list_length(plannedstmt->resultRelations);
+               int             num_roots = 
list_length(plannedstmt->rootResultRelations);
 
-               resultRelInfos = (ResultRelInfo *)
-                       palloc(numResultRelations * sizeof(ResultRelInfo));
-               resultRelInfo = resultRelInfos;
-               foreach(l, resultRelations)
-               {
-                       Index           resultRelationIndex = lfirst_int(l);
-                       Oid                     resultRelationOid;
-                       Relation        resultRelation;
-
-                       resultRelationOid = getrelid(resultRelationIndex, 
rangeTable);
-                       resultRelation = heap_open(resultRelationOid, 
RowExclusiveLock);
-
-                       InitResultRelInfo(resultRelInfo,
-                                                         resultRelation,
-                                                         resultRelationIndex,
-                                                         NULL,
-                                                         
estate->es_instrument);
-                       resultRelInfo++;
-               }
-               estate->es_result_relations = resultRelInfos;
+               estate->es_result_relations = (ResultRelInfo *)
+                               palloc(numResultRelations * 
sizeof(ResultRelInfo));
                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, lock the non-leaf 
result
-                * relations too.  A subset of these are the roots of respective
-                * partitioned tables, for which we also allocate 
ResultRelInfos.
-                */
-               estate->es_root_result_relations = NULL;
-               estate->es_num_root_result_relations = 0;
-               if (plannedstmt->nonleafResultRelations)
-               {
-                       int                     num_roots = 
list_length(plannedstmt->rootResultRelations);
-
-                       /*
-                        * Firstly, build ResultRelInfos for all the 
partitioned table
-                        * roots, because we will need them to fire the 
statement-level
-                        * triggers, if any.
-                        */
-                       resultRelInfos = (ResultRelInfo *)
+               /* For partitioned tables that are roots of their partition 
trees. */
+               estate->es_root_result_relations = (ResultRelInfo *)
                                palloc(num_roots * sizeof(ResultRelInfo));
-                       resultRelInfo = resultRelInfos;
-                       foreach(l, plannedstmt->rootResultRelations)
-                       {
-                               Index           resultRelIndex = lfirst_int(l);
-                               Oid                     resultRelOid;
-                               Relation        resultRelDesc;
-
-                               resultRelOid = getrelid(resultRelIndex, 
rangeTable);
-                               resultRelDesc = heap_open(resultRelOid, 
RowExclusiveLock);
-                               InitResultRelInfo(resultRelInfo,
-                                                                 resultRelDesc,
-                                                                 lfirst_int(l),
-                                                                 NULL,
-                                                                 
estate->es_instrument);
-                               resultRelInfo++;
-                       }
-
-                       estate->es_root_result_relations = resultRelInfos;
-                       estate->es_num_root_result_relations = num_roots;
-
-                       /* Simply lock the rest of them. */
-                       foreach(l, plannedstmt->nonleafResultRelations)
-                       {
-                               Index           resultRelIndex = lfirst_int(l);
-
-                               /* We locked the roots above. */
-                               if 
(!list_member_int(plannedstmt->rootResultRelations,
-                                                                        
resultRelIndex))
-                                       
LockRelationOid(getrelid(resultRelIndex, rangeTable),
-                                                                       
RowExclusiveLock);
-                       }
-               }
+               estate->es_num_root_result_relations = num_roots;
        }
        else
        {
@@ -924,73 +880,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
                estate->es_num_root_result_relations = 0;
        }
 
-       /*
-        * Similarly, we have to lock relations selected FOR [KEY] UPDATE/SHARE
-        * before we initialize the plan tree, else we'd be risking lock 
upgrades.
-        * While we are at it, build the ExecRowMark list.  Any partitioned 
child
-        * tables are ignored here (because isParent=true) and will be locked by
-        * the first Append or MergeAppend node that references them.  (Note 
that
-        * the RowMarks corresponding to partitioned child tables are present in
-        * the same list as the rest, i.e., plannedstmt->rowMarks.)
-        */
        estate->es_rowMarks = NIL;
-       foreach(l, plannedstmt->rowMarks)
-       {
-               PlanRowMark *rc = (PlanRowMark *) lfirst(l);
-               Oid                     relid;
-               Relation        relation;
-               ExecRowMark *erm;
-
-               /* ignore "parent" rowmarks; they are irrelevant at runtime */
-               if (rc->isParent)
-                       continue;
-
-               /* get relation's OID (will produce InvalidOid if subquery) */
-               relid = getrelid(rc->rti, rangeTable);
-
-               /*
-                * If you change the conditions under which rel locks are 
acquired
-                * here, be sure to adjust ExecOpenScanRelation to match.
-                */
-               switch (rc->markType)
-               {
-                       case ROW_MARK_EXCLUSIVE:
-                       case ROW_MARK_NOKEYEXCLUSIVE:
-                       case ROW_MARK_SHARE:
-                       case ROW_MARK_KEYSHARE:
-                               relation = heap_open(relid, RowShareLock);
-                               break;
-                       case ROW_MARK_REFERENCE:
-                               relation = heap_open(relid, AccessShareLock);
-                               break;
-                       case ROW_MARK_COPY:
-                               /* no physical table access is required */
-                               relation = NULL;
-                               break;
-                       default:
-                               elog(ERROR, "unrecognized markType: %d", 
rc->markType);
-                               relation = NULL;        /* keep compiler quiet 
*/
-                               break;
-               }
-
-               /* Check that relation is a legal target for marking */
-               if (relation)
-                       CheckValidRowMarkRel(relation, rc->markType);
-
-               erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
-               erm->relation = relation;
-               erm->relid = relid;
-               erm->rti = rc->rti;
-               erm->prti = rc->prti;
-               erm->rowmarkId = rc->rowmarkId;
-               erm->markType = rc->markType;
-               erm->strength = rc->strength;
-               erm->waitPolicy = rc->waitPolicy;
-               erm->ermActive = false;
-               ItemPointerSetInvalid(&(erm->curCtid));
-               erm->ermExtra = NULL;
-               estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
-       }
 
        /*
         * Initialize the executor's tuple table to empty.
@@ -1597,8 +1487,6 @@ ExecPostprocessPlan(EState *estate)
 static void
 ExecEndPlan(PlanState *planstate, EState *estate)
 {
-       ResultRelInfo *resultRelInfo;
-       int                     i;
        ListCell   *l;
 
        /*
@@ -1624,26 +1512,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
         */
        ExecResetTupleTable(estate->es_tupleTable, false);
 
-       /*
-        * close the result relation(s) if any, but hold locks until xact 
commit.
-        */
-       resultRelInfo = estate->es_result_relations;
-       for (i = estate->es_num_result_relations; i > 0; i--)
-       {
-               /* Close indices and then the relation itself */
-               ExecCloseIndices(resultRelInfo);
-               heap_close(resultRelInfo->ri_RelationDesc, NoLock);
-               resultRelInfo++;
-       }
-
-       /* Close the root target relation(s). */
-       resultRelInfo = estate->es_root_result_relations;
-       for (i = estate->es_num_root_result_relations; i > 0; i--)
-       {
-               heap_close(resultRelInfo->ri_RelationDesc, NoLock);
-               resultRelInfo++;
-       }
-
        /* likewise close any trigger target relations */
        ExecCleanUpTriggerState(estate);
 
@@ -2404,25 +2272,64 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo 
*relinfo)
 }
 
 /*
- * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
- *
- * If no such struct, either return NULL or throw error depending on missing_ok
+ * ExecBuildRowMark -- create ExecRowMark struct for given PlanRowMark
  */
 ExecRowMark *
-ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
+ExecBuildRowMark(EState *estate, PlanRowMark *rc)
 {
-       ListCell   *lc;
+       ExecRowMark *erm;
+       Oid                     relid;
+       Relation        relation;
 
-       foreach(lc, estate->es_rowMarks)
+       Assert(!rc->isParent);
+
+       /* get relation's OID (will produce InvalidOid if subquery) */
+       relid = getrelid(rc->rti, estate->es_range_table);
+
+       /*
+        * If you change the conditions under which rel locks are acquired
+        * here, be sure to adjust ExecOpenScanRelation to match.
+        */
+       switch (rc->markType)
        {
-               ExecRowMark *erm = (ExecRowMark *) lfirst(lc);
-
-               if (erm->rti == rti)
-                       return erm;
+               case ROW_MARK_EXCLUSIVE:
+               case ROW_MARK_NOKEYEXCLUSIVE:
+               case ROW_MARK_SHARE:
+               case ROW_MARK_KEYSHARE:
+                       relation = heap_open(relid, NoLock);
+                       break;
+               case ROW_MARK_REFERENCE:
+                       relation = heap_open(relid, NoLock);
+                       break;
+               case ROW_MARK_COPY:
+                       /* no physical table access is required */
+                       relation = NULL;
+                       break;
+               default:
+                       elog(ERROR, "unrecognized markType: %d", rc->markType);
+                       relation = NULL;        /* keep compiler quiet */
+                       break;
        }
-       if (!missing_ok)
-               elog(ERROR, "failed to find ExecRowMark for rangetable index 
%u", rti);
-       return NULL;
+
+       /* Check that relation is a legal target for marking */
+       if (relation)
+               CheckValidRowMarkRel(relation, rc->markType);
+
+       erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
+       erm->relation = relation;
+       erm->relid = relid;
+       erm->rti = rc->rti;
+       erm->prti = rc->prti;
+       erm->rowmarkId = rc->rowmarkId;
+       erm->markType = rc->markType;
+       erm->strength = rc->strength;
+       erm->waitPolicy = rc->waitPolicy;
+       erm->ermActive = false;
+       ItemPointerSetInvalid(&(erm->curCtid));
+       erm->ermExtra = NULL;
+       estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
+
+       return erm;
 }
 
 /*
@@ -3154,7 +3061,7 @@ EvalPlanQualStart(EPQState *epqstate, EState 
*parentestate, Plan *planTree)
        }
        /* es_result_relation_info must NOT be copied */
        /* es_trig_target_relations must NOT be copied */
-       estate->es_rowMarks = parentestate->es_rowMarks;
+       /* es_rowMarks must NOT be copied */
        estate->es_top_eflags = parentestate->es_top_eflags;
        estate->es_instrument = parentestate->es_instrument;
        /* es_auxmodifytables must NOT be copied */
@@ -3267,6 +3174,18 @@ EvalPlanQualEnd(EPQState *epqstate)
                ExecEndNode(subplanstate);
        }
 
+       /*
+        * close any relations selected FOR [KEY] UPDATE/SHARE, again keeping
+        * locks
+        */
+       foreach(l, estate->es_rowMarks)
+       {
+               ExecRowMark *erm = (ExecRowMark *) lfirst(l);
+
+               if (erm->relation)
+                       heap_close(erm->relation, NoLock);
+       }
+
        /* throw away the per-estate tuple table */
        ExecResetTupleTable(estate->es_tupleTable, false);
 
diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index 1a9943c3aa..81c2f5cedc 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1510,9 +1510,7 @@ ExecCreatePartitionPruneState(PlanState *planstate,
                        /*
                         * We need to hold a pin on the partitioned table's 
relcache entry
                         * so that we can rely on its copies of the table's 
partition key
-                        * and partition descriptor.  We need not get a lock 
though; one
-                        * should have been acquired already by InitPlan or
-                        * ExecLockNonLeafAppendTables.
+                        * and partition descriptor.
                         */
                        context->partrel = relation_open(pinfo->reloid, NoLock);
 
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 5b3eaec80b..09942b34fb 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -42,6 +42,7 @@
 
 #include "postgres.h"
 
+#include "access/parallel.h"
 #include "access/relscan.h"
 #include "access/transam.h"
 #include "executor/executor.h"
@@ -51,6 +52,7 @@
 #include "parser/parsetree.h"
 #include "storage/lmgr.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/typcache.h"
@@ -652,28 +654,10 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int 
eflags)
 {
        Relation        rel;
        Oid                     reloid;
-       LOCKMODE        lockmode;
 
-       /*
-        * Determine the lock type we need.  First, scan to see if target 
relation
-        * is a result relation.  If not, check if it's a FOR UPDATE/FOR SHARE
-        * relation.  In either of those cases, we got the lock already.
-        */
-       lockmode = AccessShareLock;
-       if (ExecRelationIsTargetRelation(estate, scanrelid))
-               lockmode = NoLock;
-       else
-       {
-               /* Keep this check in sync with InitPlan! */
-               ExecRowMark *erm = ExecFindRowMark(estate, scanrelid, true);
-
-               if (erm != NULL && erm->relation != NULL)
-                       lockmode = NoLock;
-       }
-
-       /* Open the relation and acquire lock as needed */
+       /* Open the relation. */
        reloid = getrelid(scanrelid, estate->es_range_table);
-       rel = heap_open(reloid, lockmode);
+       rel = heap_open(reloid, NoLock);
 
        /*
         * Complain if we're attempting a scan of an unscannable relation, 
except
diff --git a/src/backend/executor/nodeLockRows.c 
b/src/backend/executor/nodeLockRows.c
index 30de8a95ab..8c80291a53 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -425,7 +425,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
                Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
 
                /* find ExecRowMark and build ExecAuxRowMark */
-               erm = ExecFindRowMark(estate, rc->rti, false);
+               erm = ExecBuildRowMark(estate, rc);
                aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
 
                /*
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index d8d89c7983..93e5bf7af6 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -46,6 +46,7 @@
 #include "foreign/fdwapi.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
 #include "utils/builtins.h"
@@ -2238,12 +2239,36 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
 
        mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * 
nplans);
        mtstate->resultRelInfo = estate->es_result_relations + 
node->resultRelIndex;
+       resultRelInfo = mtstate->resultRelInfo;
+       foreach(l, node->resultRelations)
+       {
+               Index           resultRelationIndex = lfirst_int(l);
+               RangeTblEntry *rte = rt_fetch(resultRelationIndex,
+                                                                         
estate->es_range_table);
+               Relation        rel = heap_open(rte->relid, NoLock);
+
+               InitResultRelInfo(resultRelInfo, rel, resultRelationIndex, NULL,
+                                                 estate->es_instrument);
+               resultRelInfo++;
+       }
 
        /* If modifying a partitioned table, initialize the root table info */
        if (node->rootResultRelIndex >= 0)
+       {
+               Index                   root_rt_index = 
linitial_int(node->partitioned_rels);
+               RangeTblEntry  *rte;
+               Relation                rel;
+
                mtstate->rootResultRelInfo = estate->es_root_result_relations +
                        node->rootResultRelIndex;
 
+               Assert(root_rt_index > 0);
+               rte = rt_fetch(root_rt_index, estate->es_range_table);
+               rel = heap_open(rte->relid, NoLock);
+               InitResultRelInfo(mtstate->rootResultRelInfo, rel, 
root_rt_index,
+                                                 NULL, estate->es_instrument);
+       }
+
        mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
        mtstate->mt_nplans = nplans;
 
@@ -2530,7 +2555,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
                        continue;
 
                /* find ExecRowMark (same for all subplans) */
-               erm = ExecFindRowMark(estate, rc->rti, false);
+               erm = ExecBuildRowMark(estate, rc);
 
                /* build ExecAuxRowMark for each subplan */
                for (i = 0; i < nplans; i++)
@@ -2687,19 +2712,29 @@ ExecEndModifyTable(ModifyTableState *node)
        int                     i;
 
        /*
-        * Allow any FDWs to shut down
+        * close the result relation(s) if any, but hold locks until xact 
commit.
         */
        for (i = 0; i < node->mt_nplans; i++)
        {
                ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
 
+               /* Allow any FDWs to shut down. */
                if (!resultRelInfo->ri_usesFdwDirectModify &&
                        resultRelInfo->ri_FdwRoutine != NULL &&
                        resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
                        
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
                                                                                
                                   resultRelInfo);
+
+               /* Close indices and then the relation itself */
+               ExecCloseIndices(resultRelInfo);
+               heap_close(resultRelInfo->ri_RelationDesc, NoLock);
+               resultRelInfo++;
        }
 
+       /* Close the root partitioned table, if any. */
+       if (node->rootResultRelInfo)
+               heap_close(node->rootResultRelInfo->ri_RelationDesc, NoLock);
+
        /* Close all the partitioned tables, leaf partitions, and their indices 
*/
        if (node->mt_partition_tuple_routing)
                ExecCleanupTupleRouting(node, node->mt_partition_tuple_routing);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 7c8220cf65..6d685db0ea 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2356,6 +2356,7 @@ _copyRangeTblEntry(const RangeTblEntry *from)
        COPY_SCALAR_FIELD(rtekind);
        COPY_SCALAR_FIELD(relid);
        COPY_SCALAR_FIELD(relkind);
+       COPY_SCALAR_FIELD(lockmode);
        COPY_NODE_FIELD(tablesample);
        COPY_NODE_FIELD(subquery);
        COPY_SCALAR_FIELD(security_barrier);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 378f2facb8..488fddb255 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2630,6 +2630,7 @@ _equalRangeTblEntry(const RangeTblEntry *a, const 
RangeTblEntry *b)
        COMPARE_SCALAR_FIELD(rtekind);
        COMPARE_SCALAR_FIELD(relid);
        COMPARE_SCALAR_FIELD(relkind);
+       COMPARE_SCALAR_FIELD(lockmode);
        COMPARE_NODE_FIELD(tablesample);
        COMPARE_NODE_FIELD(subquery);
        COMPARE_SCALAR_FIELD(security_barrier);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b5af904c18..53f209e170 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3127,6 +3127,7 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry 
*node)
                case RTE_RELATION:
                        WRITE_OID_FIELD(relid);
                        WRITE_CHAR_FIELD(relkind);
+                       WRITE_INT_FIELD(lockmode);
                        WRITE_NODE_FIELD(tablesample);
                        break;
                case RTE_SUBQUERY:
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 3254524223..7a1e839ef4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1350,6 +1350,7 @@ _readRangeTblEntry(void)
                case RTE_RELATION:
                        READ_OID_FIELD(relid);
                        READ_CHAR_FIELD(relkind);
+                       READ_INT_FIELD(lockmode);
                        READ_NODE_FIELD(tablesample);
                        break;
                case RTE_SUBQUERY:
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index c601b6d40d..f70597cbd3 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1040,6 +1040,7 @@ transformOnConflictClause(ParseState *pstate,
                                                                                
                makeAlias("excluded", NIL),
                                                                                
                false, false);
                exclRte->relkind = RELKIND_COMPOSITE_TYPE;
+               exclRte->lockmode = RowExclusiveLock;
                exclRte->requiredPerms = 0;
                /* other permissions fields in exclRte are already empty */
 
diff --git a/src/backend/parser/parse_clause.c 
b/src/backend/parser/parse_clause.c
index cfd4b91897..b6a1b60d1e 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -218,6 +218,7 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
         */
        rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
                                                                                
relation->alias, inh, false);
+       rte->lockmode = RowExclusiveLock;
        pstate->p_target_rangetblentry = rte;
 
        /* assume new rte is at end */
diff --git a/src/backend/parser/parse_relation.c 
b/src/backend/parser/parse_relation.c
index bf5df26009..3fd91bdbb3 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1217,6 +1217,7 @@ addRangeTableEntry(ParseState *pstate,
        rel = parserOpenTable(pstate, relation, lockmode);
        rte->relid = RelationGetRelid(rel);
        rte->relkind = rel->rd_rel->relkind;
+       rte->lockmode = lockmode;
 
        /*
         * Build the list of effective column names using user-supplied aliases
diff --git a/src/backend/parser/parse_utilcmd.c 
b/src/backend/parser/parse_utilcmd.c
index 656b1b5f1b..54c6b1e082 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2636,9 +2636,11 @@ transformRuleStmt(RuleStmt *stmt, const char 
*queryString,
        oldrte = addRangeTableEntryForRelation(pstate, rel,
                                                                                
   makeAlias("old", NIL),
                                                                                
   false, false);
+       oldrte->lockmode = AccessShareLock;
        newrte = addRangeTableEntryForRelation(pstate, rel,
                                                                                
   makeAlias("new", NIL),
                                                                                
   false, false);
+       newrte->lockmode = AccessShareLock;
        /* Must override addRangeTableEntry's default access-check flags */
        oldrte->requiredPerms = 0;
        newrte->requiredPerms = 0;
@@ -2734,9 +2736,11 @@ transformRuleStmt(RuleStmt *stmt, const char 
*queryString,
                        oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
                                                                                
                   makeAlias("old", NIL),
                                                                                
                   false, false);
+                       oldrte->lockmode = AccessShareLock;
                        newrte = addRangeTableEntryForRelation(sub_pstate, rel,
                                                                                
                   makeAlias("new", NIL),
                                                                                
                   false, false);
+                       newrte->lockmode = AccessShareLock;
                        oldrte->requiredPerms = 0;
                        newrte->requiredPerms = 0;
                        addRTEtoQuery(sub_pstate, oldrte, false, true, false);
diff --git a/src/backend/rewrite/rewriteHandler.c 
b/src/backend/rewrite/rewriteHandler.c
index d830569641..f99c15bfcd 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -147,7 +147,6 @@ AcquireRewriteLocks(Query *parsetree,
        {
                RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
                Relation        rel;
-               LOCKMODE        lockmode;
                List       *newaliasvars;
                Index           curinputvarno;
                RangeTblEntry *curinputrte;
@@ -162,21 +161,8 @@ AcquireRewriteLocks(Query *parsetree,
                                 * Grab the appropriate lock type for the 
relation, and do not
                                 * release it until end of transaction. This 
protects the
                                 * rewriter and planner against schema changes 
mid-query.
-                                *
-                                * Assuming forExecute is true, this logic must 
match what the
-                                * executor will do, else we risk lock-upgrade 
deadlocks.
                                 */
-                               if (!forExecute)
-                                       lockmode = AccessShareLock;
-                               else if (rt_index == parsetree->resultRelation)
-                                       lockmode = RowExclusiveLock;
-                               else if (forUpdatePushedDown ||
-                                                get_parse_rowmark(parsetree, 
rt_index) != NULL)
-                                       lockmode = RowShareLock;
-                               else
-                                       lockmode = AccessShareLock;
-
-                               rel = heap_open(rte->relid, lockmode);
+                               rel = heap_open(rte->relid, rte->lockmode);
 
                                /*
                                 * While we have the relation open, update the 
RTE's relkind,
@@ -2895,6 +2881,7 @@ rewriteTargetView(Query *parsetree, Relation view)
         * it changed since this view was made (cf. AcquireRewriteLocks).
         */
        base_rte->relkind = base_rel->rd_rel->relkind;
+       base_rte->lockmode = RowExclusiveLock;
 
        /*
         * If the view query contains any sublink subqueries then we need to 
also
@@ -3102,6 +3089,7 @@ rewriteTargetView(Query *parsetree, Relation view)
                                                                                
                                          NIL),
                                                                                
                        false, false);
                new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
+               new_exclRte->lockmode = RowExclusiveLock;
                new_exclRte->requiredPerms = 0;
                /* other permissions fields in new_exclRte are already empty */
 
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 7b2dcb6c60..a1ebf647de 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -100,8 +100,9 @@ SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
  *
  * Lock a relation given only its OID.  This should generally be used
  * before attempting to open the relation's relcache entry.
+ * Return TRUE if we acquired a new lock, FALSE if already held.
  */
-void
+bool
 LockRelationOid(Oid relid, LOCKMODE lockmode)
 {
        LOCKTAG         tag;
@@ -122,7 +123,11 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
         * CommandCounterIncrement, not here.)
         */
        if (res != LOCKACQUIRE_ALREADY_HELD)
+       {
                AcceptInvalidationMessages();
+               return true;
+       }
+       return false;
 }
 
 /*
diff --git a/src/backend/utils/cache/plancache.c 
b/src/backend/utils/cache/plancache.c
index 7271b5880b..b57e4d81ad 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1516,8 +1516,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
                foreach(lc2, plannedstmt->rtable)
                {
                        RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
-                       LOCKMODE        lockmode;
-                       PlanRowMark *rc;
 
                        rt_index++;
 
@@ -1530,19 +1528,10 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
                         * fail if it's been dropped entirely --- we'll just 
transiently
                         * acquire a non-conflicting lock.
                         */
-                       if (list_member_int(plannedstmt->resultRelations, 
rt_index) ||
-                               
list_member_int(plannedstmt->nonleafResultRelations, rt_index))
-                               lockmode = RowExclusiveLock;
-                       else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, 
rt_index)) != NULL &&
-                                        
RowMarkRequiresRowShareLock(rc->markType))
-                               lockmode = RowShareLock;
-                       else
-                               lockmode = AccessShareLock;
-
                        if (acquire)
-                               LockRelationOid(rte->relid, lockmode);
+                               LockRelationOid(rte->relid, rte->lockmode);
                        else
-                               UnlockRelationOid(rte->relid, lockmode);
+                               UnlockRelationOid(rte->relid, rte->lockmode);
                }
        }
 }
@@ -1596,23 +1585,16 @@ ScanQueryForLocks(Query *parsetree, bool acquire)
        foreach(lc, parsetree->rtable)
        {
                RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
-               LOCKMODE        lockmode;
 
                rt_index++;
                switch (rte->rtekind)
                {
                        case RTE_RELATION:
                                /* Acquire or release the appropriate type of 
lock */
-                               if (rt_index == parsetree->resultRelation)
-                                       lockmode = RowExclusiveLock;
-                               else if (get_parse_rowmark(parsetree, rt_index) 
!= NULL)
-                                       lockmode = RowShareLock;
-                               else
-                                       lockmode = AccessShareLock;
                                if (acquire)
-                                       LockRelationOid(rte->relid, lockmode);
+                                       LockRelationOid(rte->relid, 
rte->lockmode);
                                else
-                                       UnlockRelationOid(rte->relid, lockmode);
+                                       UnlockRelationOid(rte->relid, 
rte->lockmode);
                                break;
 
                        case RTE_SUBQUERY:
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index f82b51667f..4425b978f9 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -188,7 +188,7 @@ extern void ExecPartitionCheckEmitError(ResultRelInfo 
*resultRelInfo,
 extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
                                         TupleTableSlot *slot, EState *estate);
 extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo 
*relinfo);
-extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti, bool 
missing_ok);
+extern ExecRowMark *ExecBuildRowMark(EState *estate, PlanRowMark *rc);
 extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist);
 extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate,
                         Relation relation, Index rti, int lockmode,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 07ab1a3dde..e8ac2459d1 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -977,6 +977,7 @@ typedef struct RangeTblEntry
         */
        Oid                     relid;                  /* OID of the relation 
*/
        char            relkind;                /* relation kind (see 
pg_class.relkind) */
+       int                     lockmode;               /* lock taken on the 
relation or 0 */
        struct TableSampleClause *tablesample;  /* sampling info, or NULL */
 
        /*
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index a217de9716..69e6f7ffd6 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -37,7 +37,7 @@ typedef enum XLTW_Oper
 extern void RelationInitLockInfo(Relation relation);
 
 /* Lock a relation */
-extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool LockRelationOid(Oid relid, LOCKMODE lockmode);
 extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
 extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
 extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
-- 
2.11.0

From 2c9a0f7d81f69bb5faafbe1d552aeb0cad6be8d5 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Mon, 13 Aug 2018 16:10:19 +0900
Subject: [PATCH v2 2/4] Remove useless fields from planner nodes

They were added so that executor could identify range table entries
entries to lock them or to impose order on locking during executor
initialization, but turns out that executor doesn't take any locks
of its own on the relations, so these fields are redundant.

Following fields are removed:

* 'partitioned_rels' from Append, MergeAppend, and ModifyTable.
Actually, in ModifyTable, it is replaced by a single Index field
called 'rootRelation', because we still need to refer to root
partitioned table for constructing a ResultRelInfo needed for
processing its statement triggers.

* 'nonleafResultRelations' from PlannedStmt and PlannerGlobal.

* 'rowMarks' from PlannedStmt and 'finalrowmarks' from PlannerGlobal.
In PlannedStmt, it is replaced by a bool hasRowMarks that stores if
query->rowMarks != NIL.
---
 src/backend/commands/portalcmds.c       |  2 +-
 src/backend/executor/execMain.c         |  2 +-
 src/backend/executor/execParallel.c     |  3 +-
 src/backend/executor/execUtils.c        | 55 ---------------------------------
 src/backend/executor/nodeAppend.c       |  6 ----
 src/backend/executor/nodeMergeAppend.c  |  6 ----
 src/backend/executor/nodeModifyTable.c  |  7 ++---
 src/backend/executor/spi.c              |  4 +--
 src/backend/nodes/copyfuncs.c           |  7 ++---
 src/backend/nodes/outfuncs.c            | 11 ++-----
 src/backend/nodes/readfuncs.c           |  7 ++---
 src/backend/optimizer/plan/createplan.c | 42 +++++--------------------
 src/backend/optimizer/plan/planner.c    | 39 +++--------------------
 src/backend/optimizer/plan/setrefs.c    | 49 ++++-------------------------
 src/backend/optimizer/util/pathnode.c   |  8 ++---
 src/backend/tcop/utility.c              | 15 +++++++--
 src/include/executor/executor.h         |  2 --
 src/include/nodes/plannodes.h           | 26 ++++------------
 src/include/nodes/relation.h            |  6 +---
 src/include/optimizer/pathnode.h        |  2 +-
 20 files changed, 56 insertions(+), 243 deletions(-)

diff --git a/src/backend/commands/portalcmds.c 
b/src/backend/commands/portalcmds.c
index 568499761f..4b213a8db7 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -133,7 +133,7 @@ PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo 
params,
        portal->cursorOptions = cstmt->options;
        if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | 
CURSOR_OPT_NO_SCROLL)))
        {
-               if (plan->rowMarks == NIL &&
+               if (!plan->hasRowMarks &&
                        ExecSupportsBackwardScan(plan->planTree))
                        portal->cursorOptions |= CURSOR_OPT_SCROLL;
                else
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 298bf43fce..5e0c2b8e67 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -217,7 +217,7 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
                         * SELECT FOR [KEY] UPDATE/SHARE and modifying CTEs 
need to mark
                         * tuples
                         */
-                       if (queryDesc->plannedstmt->rowMarks != NIL ||
+                       if (queryDesc->plannedstmt->hasRowMarks ||
                                queryDesc->plannedstmt->hasModifyingCTE)
                                estate->es_output_cid = 
GetCurrentCommandId(true);
 
diff --git a/src/backend/executor/execParallel.c 
b/src/backend/executor/execParallel.c
index ee0f07a81e..7afcd5b6c0 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -174,6 +174,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
        pstmt->queryId = UINT64CONST(0);
        pstmt->hasReturning = false;
        pstmt->hasModifyingCTE = false;
+       pstmt->hasRowMarks = false;
        pstmt->canSetTag = true;
        pstmt->transientPlan = false;
        pstmt->dependsOnRole = false;
@@ -181,7 +182,6 @@ ExecSerializePlan(Plan *plan, EState *estate)
        pstmt->planTree = plan;
        pstmt->rtable = estate->es_range_table;
        pstmt->resultRelations = NIL;
-       pstmt->nonleafResultRelations = NIL;
 
        /*
         * Transfer only parallel-safe subplans, leaving a NULL "hole" in the 
list
@@ -201,7 +201,6 @@ ExecSerializePlan(Plan *plan, EState *estate)
        }
 
        pstmt->rewindPlanIDs = NULL;
-       pstmt->rowMarks = NIL;
        pstmt->relationOids = NIL;
        pstmt->invalItems = NIL;        /* workers can't replan anyway... */
        pstmt->paramExecTypes = estate->es_plannedstmt->paramExecTypes;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 09942b34fb..d32796aac3 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -848,61 +848,6 @@ ShutdownExprContext(ExprContext *econtext, bool isCommit)
 }
 
 /*
- * ExecLockNonLeafAppendTables
- *
- * Locks, if necessary, the tables indicated by the RT indexes contained in
- * the partitioned_rels list.  These are the non-leaf tables in the partition
- * tree controlled by a given Append or MergeAppend node.
- */
-void
-ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate)
-{
-       PlannedStmt *stmt = estate->es_plannedstmt;
-       ListCell   *lc;
-
-       foreach(lc, partitioned_rels)
-       {
-               ListCell   *l;
-               Index           rti = lfirst_int(lc);
-               bool            is_result_rel = false;
-               Oid                     relid = getrelid(rti, 
estate->es_range_table);
-
-               /* If this is a result relation, already locked in InitPlan */
-               foreach(l, stmt->nonleafResultRelations)
-               {
-                       if (rti == lfirst_int(l))
-                       {
-                               is_result_rel = true;
-                               break;
-                       }
-               }
-
-               /*
-                * Not a result relation; check if there is a RowMark that 
requires
-                * taking a RowShareLock on this rel.
-                */
-               if (!is_result_rel)
-               {
-                       PlanRowMark *rc = NULL;
-
-                       foreach(l, stmt->rowMarks)
-                       {
-                               if (((PlanRowMark *) lfirst(l))->rti == rti)
-                               {
-                                       rc = lfirst(l);
-                                       break;
-                               }
-                       }
-
-                       if (rc && RowMarkRequiresRowShareLock(rc->markType))
-                               LockRelationOid(relid, RowShareLock);
-                       else
-                               LockRelationOid(relid, AccessShareLock);
-               }
-       }
-}
-
-/*
  *             GetAttributeByName
  *             GetAttributeByNum
  *
diff --git a/src/backend/executor/nodeAppend.c 
b/src/backend/executor/nodeAppend.c
index f08dfcbcf0..eb587be221 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -113,12 +113,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
        Assert(!(eflags & EXEC_FLAG_MARK));
 
        /*
-        * Lock the non-leaf tables in the partition tree controlled by this 
node.
-        * It's a no-op for non-partitioned parent tables.
-        */
-       ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
-
-       /*
         * create new AppendState for our append node
         */
        appendstate->ps.plan = (Plan *) node;
diff --git a/src/backend/executor/nodeMergeAppend.c 
b/src/backend/executor/nodeMergeAppend.c
index 9a72d3a0ac..d8e0978966 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -76,12 +76,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int 
eflags)
        Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
 
        /*
-        * Lock the non-leaf tables in the partition tree controlled by this 
node.
-        * It's a no-op for non-partitioned parent tables.
-        */
-       ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
-
-       /*
         * create new MergeAppendState for our node
         */
        mergestate->ps.plan = (Plan *) node;
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index 93e5bf7af6..fd3966d489 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,17 +2255,16 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
        /* If modifying a partitioned table, initialize the root table info */
        if (node->rootResultRelIndex >= 0)
        {
-               Index                   root_rt_index = 
linitial_int(node->partitioned_rels);
                RangeTblEntry  *rte;
                Relation                rel;
 
                mtstate->rootResultRelInfo = estate->es_root_result_relations +
                        node->rootResultRelIndex;
 
-               Assert(root_rt_index > 0);
-               rte = rt_fetch(root_rt_index, estate->es_range_table);
+               Assert(node->rootRelation > 0);
+               rte = rt_fetch(node->rootRelation, estate->es_range_table);
                rel = heap_open(rte->relid, NoLock);
-               InitResultRelInfo(mtstate->rootResultRelInfo, rel, 
root_rt_index,
+               InitResultRelInfo(mtstate->rootResultRelInfo, rel, 
node->rootRelation,
                                                  NULL, estate->es_instrument);
        }
 
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 5756365c8f..b3664e2f3f 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1334,7 +1334,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr 
plan,
        {
                if (list_length(stmt_list) == 1 &&
                        linitial_node(PlannedStmt, stmt_list)->commandType != 
CMD_UTILITY &&
-                       linitial_node(PlannedStmt, stmt_list)->rowMarks == NIL 
&&
+                       !linitial_node(PlannedStmt, stmt_list)->hasRowMarks &&
                        ExecSupportsBackwardScan(linitial_node(PlannedStmt, 
stmt_list)->planTree))
                        portal->cursorOptions |= CURSOR_OPT_SCROLL;
                else
@@ -1350,7 +1350,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr 
plan,
        {
                if (list_length(stmt_list) == 1 &&
                        linitial_node(PlannedStmt, stmt_list)->commandType != 
CMD_UTILITY &&
-                       linitial_node(PlannedStmt, stmt_list)->rowMarks != NIL)
+                       linitial_node(PlannedStmt, stmt_list)->hasRowMarks)
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("DECLARE SCROLL CURSOR ... FOR 
UPDATE/SHARE is not supported"),
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 6d685db0ea..29abe56b70 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -83,6 +83,7 @@ _copyPlannedStmt(const PlannedStmt *from)
        COPY_SCALAR_FIELD(queryId);
        COPY_SCALAR_FIELD(hasReturning);
        COPY_SCALAR_FIELD(hasModifyingCTE);
+       COPY_SCALAR_FIELD(hasRowMarks);
        COPY_SCALAR_FIELD(canSetTag);
        COPY_SCALAR_FIELD(transientPlan);
        COPY_SCALAR_FIELD(dependsOnRole);
@@ -91,11 +92,9 @@ _copyPlannedStmt(const PlannedStmt *from)
        COPY_NODE_FIELD(planTree);
        COPY_NODE_FIELD(rtable);
        COPY_NODE_FIELD(resultRelations);
-       COPY_NODE_FIELD(nonleafResultRelations);
        COPY_NODE_FIELD(rootResultRelations);
        COPY_NODE_FIELD(subplans);
        COPY_BITMAPSET_FIELD(rewindPlanIDs);
-       COPY_NODE_FIELD(rowMarks);
        COPY_NODE_FIELD(relationOids);
        COPY_NODE_FIELD(invalItems);
        COPY_NODE_FIELD(paramExecTypes);
@@ -204,7 +203,7 @@ _copyModifyTable(const ModifyTable *from)
        COPY_SCALAR_FIELD(operation);
        COPY_SCALAR_FIELD(canSetTag);
        COPY_SCALAR_FIELD(nominalRelation);
-       COPY_NODE_FIELD(partitioned_rels);
+       COPY_SCALAR_FIELD(rootRelation);
        COPY_SCALAR_FIELD(partColsUpdated);
        COPY_NODE_FIELD(resultRelations);
        COPY_SCALAR_FIELD(resultRelIndex);
@@ -244,7 +243,6 @@ _copyAppend(const Append *from)
         */
        COPY_NODE_FIELD(appendplans);
        COPY_SCALAR_FIELD(first_partial_plan);
-       COPY_NODE_FIELD(partitioned_rels);
        COPY_NODE_FIELD(part_prune_info);
 
        return newnode;
@@ -266,7 +264,6 @@ _copyMergeAppend(const MergeAppend *from)
        /*
         * copy remainder of node
         */
-       COPY_NODE_FIELD(partitioned_rels);
        COPY_NODE_FIELD(mergeplans);
        COPY_SCALAR_FIELD(numCols);
        COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 53f209e170..ac1e434ce5 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -268,6 +268,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
        WRITE_UINT64_FIELD(queryId);
        WRITE_BOOL_FIELD(hasReturning);
        WRITE_BOOL_FIELD(hasModifyingCTE);
+       WRITE_BOOL_FIELD(hasRowMarks);
        WRITE_BOOL_FIELD(canSetTag);
        WRITE_BOOL_FIELD(transientPlan);
        WRITE_BOOL_FIELD(dependsOnRole);
@@ -276,11 +277,9 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
        WRITE_NODE_FIELD(planTree);
        WRITE_NODE_FIELD(rtable);
        WRITE_NODE_FIELD(resultRelations);
-       WRITE_NODE_FIELD(nonleafResultRelations);
        WRITE_NODE_FIELD(rootResultRelations);
        WRITE_NODE_FIELD(subplans);
        WRITE_BITMAPSET_FIELD(rewindPlanIDs);
-       WRITE_NODE_FIELD(rowMarks);
        WRITE_NODE_FIELD(relationOids);
        WRITE_NODE_FIELD(invalItems);
        WRITE_NODE_FIELD(paramExecTypes);
@@ -372,7 +371,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
        WRITE_ENUM_FIELD(operation, CmdType);
        WRITE_BOOL_FIELD(canSetTag);
        WRITE_UINT_FIELD(nominalRelation);
-       WRITE_NODE_FIELD(partitioned_rels);
+       WRITE_UINT_FIELD(rootRelation);
        WRITE_BOOL_FIELD(partColsUpdated);
        WRITE_NODE_FIELD(resultRelations);
        WRITE_INT_FIELD(resultRelIndex);
@@ -401,7 +400,6 @@ _outAppend(StringInfo str, const Append *node)
 
        WRITE_NODE_FIELD(appendplans);
        WRITE_INT_FIELD(first_partial_plan);
-       WRITE_NODE_FIELD(partitioned_rels);
        WRITE_NODE_FIELD(part_prune_info);
 }
 
@@ -414,7 +412,6 @@ _outMergeAppend(StringInfo str, const MergeAppend *node)
 
        _outPlanInfo(str, (const Plan *) node);
 
-       WRITE_NODE_FIELD(partitioned_rels);
        WRITE_NODE_FIELD(mergeplans);
 
        WRITE_INT_FIELD(numCols);
@@ -2175,7 +2172,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath 
*node)
        WRITE_ENUM_FIELD(operation, CmdType);
        WRITE_BOOL_FIELD(canSetTag);
        WRITE_UINT_FIELD(nominalRelation);
-       WRITE_NODE_FIELD(partitioned_rels);
+       WRITE_UINT_FIELD(rootRelation);
        WRITE_BOOL_FIELD(partColsUpdated);
        WRITE_NODE_FIELD(resultRelations);
        WRITE_NODE_FIELD(subpaths);
@@ -2253,9 +2250,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal 
*node)
        WRITE_NODE_FIELD(subplans);
        WRITE_BITMAPSET_FIELD(rewindPlanIDs);
        WRITE_NODE_FIELD(finalrtable);
-       WRITE_NODE_FIELD(finalrowmarks);
        WRITE_NODE_FIELD(resultRelations);
-       WRITE_NODE_FIELD(nonleafResultRelations);
        WRITE_NODE_FIELD(rootResultRelations);
        WRITE_NODE_FIELD(relationOids);
        WRITE_NODE_FIELD(invalItems);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 7a1e839ef4..780d261edf 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1476,6 +1476,7 @@ _readPlannedStmt(void)
        READ_UINT64_FIELD(queryId);
        READ_BOOL_FIELD(hasReturning);
        READ_BOOL_FIELD(hasModifyingCTE);
+       READ_BOOL_FIELD(hasRowMarks);
        READ_BOOL_FIELD(canSetTag);
        READ_BOOL_FIELD(transientPlan);
        READ_BOOL_FIELD(dependsOnRole);
@@ -1484,11 +1485,9 @@ _readPlannedStmt(void)
        READ_NODE_FIELD(planTree);
        READ_NODE_FIELD(rtable);
        READ_NODE_FIELD(resultRelations);
-       READ_NODE_FIELD(nonleafResultRelations);
        READ_NODE_FIELD(rootResultRelations);
        READ_NODE_FIELD(subplans);
        READ_BITMAPSET_FIELD(rewindPlanIDs);
-       READ_NODE_FIELD(rowMarks);
        READ_NODE_FIELD(relationOids);
        READ_NODE_FIELD(invalItems);
        READ_NODE_FIELD(paramExecTypes);
@@ -1578,7 +1577,7 @@ _readModifyTable(void)
        READ_ENUM_FIELD(operation, CmdType);
        READ_BOOL_FIELD(canSetTag);
        READ_UINT_FIELD(nominalRelation);
-       READ_NODE_FIELD(partitioned_rels);
+       READ_UINT_FIELD(rootRelation);
        READ_BOOL_FIELD(partColsUpdated);
        READ_NODE_FIELD(resultRelations);
        READ_INT_FIELD(resultRelIndex);
@@ -1612,7 +1611,6 @@ _readAppend(void)
 
        READ_NODE_FIELD(appendplans);
        READ_INT_FIELD(first_partial_plan);
-       READ_NODE_FIELD(partitioned_rels);
        READ_NODE_FIELD(part_prune_info);
 
        READ_DONE();
@@ -1628,7 +1626,6 @@ _readMergeAppend(void)
 
        ReadCommonPlan(&local_node->plan);
 
-       READ_NODE_FIELD(partitioned_rels);
        READ_NODE_FIELD(mergeplans);
        READ_INT_FIELD(numCols);
        READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols);
diff --git a/src/backend/optimizer/plan/createplan.c 
b/src/backend/optimizer/plan/createplan.c
index ae41c9efa0..ae46b0140e 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -124,7 +124,6 @@ static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo 
*root,
 static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
                                          List **qual, List **indexqual, List 
**indexECs);
 static void bitmap_subplan_mark_shared(Plan *plan);
-static List *flatten_partitioned_rels(List *partitioned_rels);
 static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
                                        List *tlist, List *scan_clauses);
 static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root,
@@ -203,8 +202,7 @@ static NamedTuplestoreScan *make_namedtuplestorescan(List 
*qptlist, List *qpqual
 static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
                                   Index scanrelid, int wtParam);
 static Append *make_append(List *appendplans, int first_partial_plan,
-                       List *tlist, List *partitioned_rels,
-                       PartitionPruneInfo *partpruneinfo);
+                       List *tlist, PartitionPruneInfo *partpruneinfo);
 static RecursiveUnion *make_recursive_union(List *tlist,
                                         Plan *lefttree,
                                         Plan *righttree,
@@ -280,7 +278,7 @@ static Result *make_result(List *tlist, Node 
*resconstantqual, Plan *subplan);
 static ProjectSet *make_project_set(List *tlist, Plan *subplan);
 static ModifyTable *make_modifytable(PlannerInfo *root,
                                 CmdType operation, bool canSetTag,
-                                Index nominalRelation, List *partitioned_rels,
+                                Index nominalRelation, Index rootRelation,
                                 bool partColsUpdated,
                                 List *resultRelations, List *subplans, List 
*subroots,
                                 List *withCheckOptionLists, List 
*returningLists,
@@ -1110,8 +1108,7 @@ create_append_plan(PlannerInfo *root, AppendPath 
*best_path)
         */
 
        plan = make_append(subplans, best_path->first_partial_path,
-                                          tlist, best_path->partitioned_rels,
-                                          partpruneinfo);
+                                          tlist, partpruneinfo);
 
        copy_generic_path_info(&plan->plan, (Path *) best_path);
 
@@ -1253,8 +1250,6 @@ create_merge_append_plan(PlannerInfo *root, 
MergeAppendPath *best_path)
                                                                                
                         prunequal);
        }
 
-       node->partitioned_rels =
-               flatten_partitioned_rels(best_path->partitioned_rels);
        node->mergeplans = subplans;
        node->part_prune_info = partpruneinfo;
 
@@ -2411,7 +2406,7 @@ create_modifytable_plan(PlannerInfo *root, 
ModifyTablePath *best_path)
                                                        best_path->operation,
                                                        best_path->canSetTag,
                                                        
best_path->nominalRelation,
-                                                       
best_path->partitioned_rels,
+                                                       best_path->rootRelation,
                                                        
best_path->partColsUpdated,
                                                        
best_path->resultRelations,
                                                        subplans,
@@ -5005,27 +5000,6 @@ bitmap_subplan_mark_shared(Plan *plan)
                elog(ERROR, "unrecognized node type: %d", nodeTag(plan));
 }
 
-/*
- * flatten_partitioned_rels
- *             Convert List of Lists into a single List with all elements from 
the
- *             sub-lists.
- */
-static List *
-flatten_partitioned_rels(List *partitioned_rels)
-{
-       List       *newlist = NIL;
-       ListCell   *lc;
-
-       foreach(lc, partitioned_rels)
-       {
-               List       *sublist = lfirst(lc);
-
-               newlist = list_concat(newlist, list_copy(sublist));
-       }
-
-       return newlist;
-}
-
 /*****************************************************************************
  *
  *     PLAN NODE BUILDING ROUTINES
@@ -5368,8 +5342,7 @@ make_foreignscan(List *qptlist,
 
 static Append *
 make_append(List *appendplans, int first_partial_plan,
-                       List *tlist, List *partitioned_rels,
-                       PartitionPruneInfo *partpruneinfo)
+                       List *tlist, PartitionPruneInfo *partpruneinfo)
 {
        Append     *node = makeNode(Append);
        Plan       *plan = &node->plan;
@@ -5380,7 +5353,6 @@ make_append(List *appendplans, int first_partial_plan,
        plan->righttree = NULL;
        node->appendplans = appendplans;
        node->first_partial_plan = first_partial_plan;
-       node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
        node->part_prune_info = partpruneinfo;
        return node;
 }
@@ -6509,7 +6481,7 @@ make_project_set(List *tlist,
 static ModifyTable *
 make_modifytable(PlannerInfo *root,
                                 CmdType operation, bool canSetTag,
-                                Index nominalRelation, List *partitioned_rels,
+                                Index nominalRelation, Index rootRelation,
                                 bool partColsUpdated,
                                 List *resultRelations, List *subplans, List 
*subroots,
                                 List *withCheckOptionLists, List 
*returningLists,
@@ -6538,7 +6510,7 @@ make_modifytable(PlannerInfo *root,
        node->operation = operation;
        node->canSetTag = canSetTag;
        node->nominalRelation = nominalRelation;
-       node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+       node->rootRelation = rootRelation;
        node->partColsUpdated = partColsUpdated;
        node->resultRelations = resultRelations;
        node->resultRelIndex = -1;      /* will be set correctly in setrefs.c */
diff --git a/src/backend/optimizer/plan/planner.c 
b/src/backend/optimizer/plan/planner.c
index 96bf0601a8..34fbc37702 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -290,9 +290,7 @@ standard_planner(Query *parse, int cursorOptions, 
ParamListInfo boundParams)
        glob->subroots = NIL;
        glob->rewindPlanIDs = NULL;
        glob->finalrtable = NIL;
-       glob->finalrowmarks = NIL;
        glob->resultRelations = NIL;
-       glob->nonleafResultRelations = NIL;
        glob->rootResultRelations = NIL;
        glob->relationOids = NIL;
        glob->invalItems = NIL;
@@ -490,9 +488,7 @@ standard_planner(Query *parse, int cursorOptions, 
ParamListInfo boundParams)
 
        /* final cleanup of the plan */
        Assert(glob->finalrtable == NIL);
-       Assert(glob->finalrowmarks == NIL);
        Assert(glob->resultRelations == NIL);
-       Assert(glob->nonleafResultRelations == NIL);
        Assert(glob->rootResultRelations == NIL);
        top_plan = set_plan_references(root, top_plan);
        /* ... and the subplans (both regular subplans and initplans) */
@@ -512,6 +508,7 @@ standard_planner(Query *parse, int cursorOptions, 
ParamListInfo boundParams)
        result->queryId = parse->queryId;
        result->hasReturning = (parse->returningList != NIL);
        result->hasModifyingCTE = parse->hasModifyingCTE;
+       result->hasRowMarks = (parse->rowMarks != NIL);
        result->canSetTag = parse->canSetTag;
        result->transientPlan = glob->transientPlan;
        result->dependsOnRole = glob->dependsOnRole;
@@ -519,11 +516,9 @@ standard_planner(Query *parse, int cursorOptions, 
ParamListInfo boundParams)
        result->planTree = top_plan;
        result->rtable = glob->finalrtable;
        result->resultRelations = glob->resultRelations;
-       result->nonleafResultRelations = glob->nonleafResultRelations;
        result->rootResultRelations = glob->rootResultRelations;
        result->subplans = glob->subplans;
        result->rewindPlanIDs = glob->rewindPlanIDs;
-       result->rowMarks = glob->finalrowmarks;
        result->relationOids = glob->relationOids;
        result->invalItems = glob->invalItems;
        result->paramExecTypes = glob->paramExecTypes;
@@ -1174,7 +1169,7 @@ inheritance_planner(PlannerInfo *root)
        Index           rti;
        RangeTblEntry *parent_rte;
        Relids          partitioned_relids = NULL;
-       List       *partitioned_rels = NIL;
+       Index           rootRelation = 0;
        PlannerInfo *parent_root;
        Query      *parent_parse;
        Bitmapset  *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1248,15 +1243,7 @@ inheritance_planner(PlannerInfo *root)
         */
        parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
        if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
-       {
-               nominalRelation = top_parentRTindex;
-
-               /*
-                * Root parent's RT index is always present in the 
partitioned_rels of
-                * the ModifyTable node, if one is needed at all.
-                */
-               partitioned_relids = bms_make_singleton(top_parentRTindex);
-       }
+               nominalRelation = rootRelation = top_parentRTindex;
 
        /*
         * The PlannerInfo for each child is obtained by translating the 
relevant
@@ -1609,29 +1596,13 @@ inheritance_planner(PlannerInfo *root)
        else
                rowMarks = root->rowMarks;
 
-       if (partitioned_relids)
-       {
-               int                     i;
-
-               i = -1;
-               while ((i = bms_next_member(partitioned_relids, i)) >= 0)
-                       partitioned_rels = lappend_int(partitioned_rels, i);
-
-               /*
-                * If we're going to create ModifyTable at all, the list should
-                * contain at least one member, that is, the root parent's 
index.
-                */
-               Assert(list_length(partitioned_rels) >= 1);
-               partitioned_rels = list_make1(partitioned_rels);
-       }
-
        /* Create Path representing a ModifyTable to do the UPDATE/DELETE work 
*/
        add_path(final_rel, (Path *)
                         create_modifytable_path(root, final_rel,
                                                                         
parse->commandType,
                                                                         
parse->canSetTag,
                                                                         
nominalRelation,
-                                                                        
partitioned_rels,
+                                                                        
rootRelation,
                                                                         
root->partColsUpdated,
                                                                         
resultRelations,
                                                                         
subpaths,
@@ -2208,7 +2179,7 @@ grouping_planner(PlannerInfo *root, bool 
inheritance_update,
                                                                                
parse->commandType,
                                                                                
parse->canSetTag,
                                                                                
parse->resultRelation,
-                                                                               
NIL,
+                                                                               
0,
                                                                                
false,
                                                                                
list_make1_int(parse->resultRelation),
                                                                                
list_make1(path),
diff --git a/src/backend/optimizer/plan/setrefs.c 
b/src/backend/optimizer/plan/setrefs.c
index f66f39d8c6..f516b3a85c 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -211,7 +211,6 @@ set_plan_references(PlannerInfo *root, Plan *plan)
 {
        PlannerGlobal *glob = root->glob;
        int                     rtoffset = list_length(glob->finalrtable);
-       ListCell   *lc;
 
        /*
         * Add all the query's RTEs to the flattened rangetable.  The live ones
@@ -220,25 +219,6 @@ set_plan_references(PlannerInfo *root, Plan *plan)
         */
        add_rtes_to_flat_rtable(root, false);
 
-       /*
-        * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
-        */
-       foreach(lc, root->rowMarks)
-       {
-               PlanRowMark *rc = lfirst_node(PlanRowMark, lc);
-               PlanRowMark *newrc;
-
-               /* flat copy is enough since all fields are scalars */
-               newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
-               memcpy(newrc, rc, sizeof(PlanRowMark));
-
-               /* adjust indexes ... but *not* the rowmarkId */
-               newrc->rti += rtoffset;
-               newrc->prti += rtoffset;
-
-               glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
-       }
-
        /* Now fix the Plan tree */
        return set_plan_refs(root, plan, rtoffset);
 }
@@ -848,12 +828,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                                }
 
                                splan->nominalRelation += rtoffset;
+                               if (splan->rootRelation > 0)
+                                       splan->rootRelation += rtoffset;
                                splan->exclRelRTI += rtoffset;
 
-                               foreach(l, splan->partitioned_rels)
-                               {
-                                       lfirst_int(l) += rtoffset;
-                               }
                                foreach(l, splan->resultRelations)
                                {
                                        lfirst_int(l) += rtoffset;
@@ -884,24 +862,17 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                                                                
list_copy(splan->resultRelations));
 
                                /*
-                                * If the main target relation is a partitioned 
table, the
-                                * following list contains the RT indexes of 
partitioned child
-                                * relations including the root, which are not 
included in the
-                                * above list.  We also keep RT indexes of the 
roots
-                                * separately to be identified as such during 
the executor
-                                * initialization.
+                                * If the main target relation is a partitioned 
table, remember
+                                * the root table's RT index.
                                 */
-                               if (splan->partitioned_rels != NIL)
+                               if (splan->rootRelation > 0)
                                {
-                                       root->glob->nonleafResultRelations =
-                                               
list_concat(root->glob->nonleafResultRelations,
-                                                                       
list_copy(splan->partitioned_rels));
                                        /* Remember where this root will be in 
the global list. */
                                        splan->rootResultRelIndex =
                                                
list_length(root->glob->rootResultRelations);
                                        root->glob->rootResultRelations =
                                                
lappend_int(root->glob->rootResultRelations,
-                                                                       
linitial_int(splan->partitioned_rels));
+                                                                       
splan->rootRelation);
                                }
                        }
                        break;
@@ -915,10 +886,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                                 */
                                set_dummy_tlist_references(plan, rtoffset);
                                Assert(splan->plan.qual == NIL);
-                               foreach(l, splan->partitioned_rels)
-                               {
-                                       lfirst_int(l) += rtoffset;
-                               }
                                foreach(l, splan->appendplans)
                                {
                                        lfirst(l) = set_plan_refs(root,
@@ -937,10 +904,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                                 */
                                set_dummy_tlist_references(plan, rtoffset);
                                Assert(splan->plan.qual == NIL);
-                               foreach(l, splan->partitioned_rels)
-                               {
-                                       lfirst_int(l) += rtoffset;
-                               }
                                foreach(l, splan->mergeplans)
                                {
                                        lfirst(l) = set_plan_refs(root,
diff --git a/src/backend/optimizer/util/pathnode.c 
b/src/backend/optimizer/util/pathnode.c
index c5aaaf5c22..4983e500ac 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3292,9 +3292,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
  * 'operation' is the operation type
  * 'canSetTag' is true if we set the command tag/es_processed
  * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * 'partitioned_rels' is an integer list of RT indexes of non-leaf tables in
- *             the partition tree, if this is an UPDATE/DELETE to a 
partitioned table.
- *             Otherwise NIL.
+ * 'rootRelation' is the RT index of the root partitioned table
  * 'partColsUpdated' is true if any partitioning columns are being updated,
  *             either from the target relation or a descendent partitioned 
table.
  * 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -3309,7 +3307,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
 ModifyTablePath *
 create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
                                                CmdType operation, bool 
canSetTag,
-                                               Index nominalRelation, List 
*partitioned_rels,
+                                               Index nominalRelation, Index 
rootRelation,
                                                bool partColsUpdated,
                                                List *resultRelations, List 
*subpaths,
                                                List *subroots,
@@ -3377,7 +3375,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo 
*rel,
        pathnode->operation = operation;
        pathnode->canSetTag = canSetTag;
        pathnode->nominalRelation = nominalRelation;
-       pathnode->partitioned_rels = list_copy(partitioned_rels);
+       pathnode->rootRelation = rootRelation;
        pathnode->partColsUpdated = partColsUpdated;
        pathnode->resultRelations = resultRelations;
        pathnode->subpaths = subpaths;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index b5804f64ad..72cf99c79e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -103,7 +103,7 @@ CommandIsReadOnly(PlannedStmt *pstmt)
        switch (pstmt->commandType)
        {
                case CMD_SELECT:
-                       if (pstmt->rowMarks != NIL)
+                       if (pstmt->hasRowMarks)
                                return false;   /* SELECT FOR [KEY] 
UPDATE/SHARE */
                        else if (pstmt->hasModifyingCTE)
                                return false;   /* data-modifying CTE */
@@ -2809,10 +2809,19 @@ CreateCommandTag(Node *parsetree)
                                                 * will be useful for 
complaints about read-only
                                                 * statements
                                                 */
-                                               if (stmt->rowMarks != NIL)
+                                               if (stmt->hasRowMarks)
                                                {
+                                                       List *rowMarks;
+
+                                                       /* Top-level Plan must 
be LockRows or ModifyTable */
+                                                       
Assert(IsA(stmt->planTree, LockRows) ||
+                                                                  
IsA(stmt->planTree, ModifyTable));
+                                                       if (IsA(stmt->planTree, 
LockRows))
+                                                               rowMarks = 
((LockRows *) stmt->planTree)->rowMarks;
+                                                       else if 
(IsA(stmt->planTree, ModifyTable))
+                                                               rowMarks = 
((ModifyTable *) stmt->planTree)->rowMarks;
                                                        /* not 100% but 
probably close enough */
-                                                       switch (((PlanRowMark 
*) linitial(stmt->rowMarks))->strength)
+                                                       switch (((PlanRowMark 
*) linitial(rowMarks))->strength)
                                                        {
                                                                case 
LCS_FORKEYSHARE:
                                                                        tag = 
"SELECT FOR KEY SHARE";
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 4425b978f9..1d2b48fe09 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -524,8 +524,6 @@ extern void UnregisterExprContextCallback(ExprContext 
*econtext,
                                                          
ExprContextCallbackFunction function,
                                                          Datum arg);
 
-extern void ExecLockNonLeafAppendTables(List *partitioned_rels, EState 
*estate);
-
 extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname,
                                   bool *isNull);
 extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno,
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 7c2abbd03a..a342edf49c 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -51,6 +51,8 @@ typedef struct PlannedStmt
 
        bool            hasModifyingCTE;        /* has insert|update|delete in 
WITH? */
 
+       bool            hasRowMarks;            /* has FOR UPDATE/SHARE? */
+
        bool            canSetTag;              /* do I set the command result 
tag? */
 
        bool            transientPlan;  /* redo plan when TransactionXmin 
changes? */
@@ -69,15 +71,8 @@ typedef struct PlannedStmt
        List       *resultRelations;    /* integer list of RT indexes, or NIL */
 
        /*
-        * rtable indexes of non-leaf target relations for UPDATE/DELETE on all
-        * the partitioned tables mentioned in the query.
-        */
-       List       *nonleafResultRelations;
-
-       /*
-        * rtable indexes of root target relations for UPDATE/DELETE; this list
-        * maintains a subset of the RT indexes in nonleafResultRelations,
-        * indicating the roots of the respective partition hierarchies.
+        * rtable indexes of root partitioned tables that are  UPDATE/DELETE
+        * targets
         */
        List       *rootResultRelations;
 
@@ -86,8 +81,6 @@ typedef struct PlannedStmt
 
        Bitmapset  *rewindPlanIDs;      /* indices of subplans that require 
REWIND */
 
-       List       *rowMarks;           /* a list of PlanRowMark's */
-
        List       *relationOids;       /* OIDs of relations the plan depends 
on */
 
        List       *invalItems;         /* other dependencies, as 
PlanInvalItems */
@@ -220,8 +213,7 @@ typedef struct ModifyTable
        CmdType         operation;              /* INSERT, UPDATE, or DELETE */
        bool            canSetTag;              /* do we set the command 
tag/es_processed? */
        Index           nominalRelation;        /* Parent RT index for use of 
EXPLAIN */
-       /* RT indexes of non-leaf tables in a partition tree */
-       List       *partitioned_rels;
+       Index           rootRelation;           /* RT index of root partitioned 
table */
        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 */
@@ -259,9 +251,6 @@ typedef struct Append
         */
        int                     first_partial_plan;
 
-       /* RT indexes of non-leaf tables in a partition tree */
-       List       *partitioned_rels;
-
        /* Info for run-time subplan pruning; NULL if we're not doing that */
        struct PartitionPruneInfo *part_prune_info;
 } Append;
@@ -274,8 +263,6 @@ typedef struct Append
 typedef struct MergeAppend
 {
        Plan            plan;
-       /* RT indexes of non-leaf tables in a partition tree */
-       List       *partitioned_rels;
        List       *mergeplans;
        /* remaining fields are just like the sort-key info in struct Sort */
        int                     numCols;                /* number of sort-key 
columns */
@@ -927,8 +914,7 @@ typedef struct SetOp
 /* ----------------
  *             lock-rows node
  *
- * rowMarks identifies the rels to be locked by this node; it should be
- * a subset of the rowMarks listed in the top-level PlannedStmt.
+ * rowMarks identifies the rels to be locked by this node.
  * epqParam is a Param that all scan nodes below this one must depend on.
  * It is used to force re-evaluation of the plan during EvalPlanQual.
  * ----------------
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index adb4265047..f9d23305fb 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -117,11 +117,8 @@ typedef struct PlannerGlobal
 
        List       *finalrtable;        /* "flat" rangetable for executor */
 
-       List       *finalrowmarks;      /* "flat" list of PlanRowMarks */
-
        List       *resultRelations;    /* "flat" list of integer RT indexes */
 
-       List       *nonleafResultRelations; /* "flat" list of integer RT 
indexes */
        List       *rootResultRelations;        /* "flat" list of integer RT 
indexes */
 
        List       *relationOids;       /* OIDs of relations the plan depends 
on */
@@ -1717,8 +1714,7 @@ typedef struct ModifyTablePath
        CmdType         operation;              /* INSERT, UPDATE, or DELETE */
        bool            canSetTag;              /* do we set the command 
tag/es_processed? */
        Index           nominalRelation;        /* Parent RT index for use of 
EXPLAIN */
-       /* RT indexes of non-leaf tables in a partition tree */
-       List       *partitioned_rels;
+       Index           rootRelation;           /* RT index of root partitioned 
table */
        bool            partColsUpdated;        /* some part key in hierarchy 
updated */
        List       *resultRelations;    /* integer list of RT indexes */
        List       *subpaths;           /* Path(s) producing source data */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7c5ff22650..81abcf53a8 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo 
*root, RelOptInfo *rel,
 extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
                                                RelOptInfo *rel,
                                                CmdType operation, bool 
canSetTag,
-                                               Index nominalRelation, List 
*partitioned_rels,
+                                               Index nominalRelation, Index 
rootRelation,
                                                bool partColsUpdated,
                                                List *resultRelations, List 
*subpaths,
                                                List *subroots,
-- 
2.11.0

From a2aab818dd94db0d78c73ecfda4134a80dbed043 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Tue, 14 Aug 2018 10:35:47 +0900
Subject: [PATCH v2 3/4] Prune PlanRowMark of relations that are pruned from a
 plan

---
 src/backend/optimizer/plan/planner.c | 47 +++++++++++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/src/backend/optimizer/plan/planner.c 
b/src/backend/optimizer/plan/planner.c
index 34fbc37702..3cca02c4a2 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1594,7 +1594,19 @@ inheritance_planner(PlannerInfo *root)
        if (parse->rowMarks)
                rowMarks = NIL;
        else
-               rowMarks = root->rowMarks;
+       {
+               rowMarks = NIL;
+               foreach(lc, root->rowMarks)
+               {
+                       PlanRowMark *rc = lfirst(lc);
+
+                       if (root->simple_rel_array[rc->rti] != NULL &&
+                               IS_DUMMY_REL(root->simple_rel_array[rc->rti]))
+                               continue;
+
+                       rowMarks = lappend(rowMarks, rc);
+               }
+       }
 
        /* Create Path representing a ModifyTable to do the UPDATE/DELETE work 
*/
        add_path(final_rel, (Path *)
@@ -2124,8 +2136,23 @@ grouping_planner(PlannerInfo *root, bool 
inheritance_update,
                 */
                if (parse->rowMarks)
                {
+                       ListCell   *lc2;
+                       List       *rowMarks;
+
+                       rowMarks = NIL;
+                       foreach(lc2, root->rowMarks)
+                       {
+                               PlanRowMark *rc = lfirst(lc2);
+
+                               if (root->simple_rel_array[rc->rti] != NULL &&
+                                       
IS_DUMMY_REL(root->simple_rel_array[rc->rti]))
+                                       continue;
+
+                               rowMarks = lappend(rowMarks, rc);
+                       }
+
                        path = (Path *) create_lockrows_path(root, final_rel, 
path,
-                                                                               
                 root->rowMarks,
+                                                                               
                 rowMarks,
                                                                                
                 SS_assign_special_param(root));
                }
 
@@ -2172,7 +2199,21 @@ grouping_planner(PlannerInfo *root, bool 
inheritance_update,
                        if (parse->rowMarks)
                                rowMarks = NIL;
                        else
-                               rowMarks = root->rowMarks;
+                       {
+                               ListCell *lc2;
+
+                               rowMarks = NIL;
+                               foreach(lc2, root->rowMarks)
+                               {
+                                       PlanRowMark *rc = lfirst(lc2);
+
+                                       if (root->simple_rel_array[rc->rti] != 
NULL &&
+                                               
IS_DUMMY_REL(root->simple_rel_array[rc->rti]))
+                                               continue;
+
+                                       rowMarks = lappend(rowMarks, rc);
+                               }
+                       }
 
                        path = (Path *)
                                create_modifytable_path(root, final_rel,
-- 
2.11.0

From 36e2b0b58e0c7b1a1445a46be147881fe416a2dc Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Thu, 19 Jul 2018 13:01:43 +0900
Subject: [PATCH v2 4/4] Revise executor range table relation opening/closing

All requests to open range table relations in the executor now go
through ExecRangeTableRelation(), which consults an array of Relation
pointers indexed by RT index.

To speed up retrieving range table entries at arbitrary points within
the executor, this introduceds an array of RangeTblEntry pointers in
EState.  InitPlan builds it from the es_range_table list.

This also revises PartitionedRelPruneInfo node to contain the
partitioned table's RT index instead of OID.  With that change,
ExecCreatePartitionPruneState can use ExecRangeTableRelation described
above.

Authors: Amit Langote, David Rowley
---
 contrib/postgres_fdw/postgres_fdw.c      | 12 ++++++------
 src/backend/commands/copy.c              | 12 +++++++++++-
 src/backend/commands/trigger.c           |  3 ++-
 src/backend/executor/execExprInterp.c    |  7 ++++---
 src/backend/executor/execMain.c          | 33 ++++++++++++++++++++------------
 src/backend/executor/execPartition.c     | 12 ++++++------
 src/backend/executor/execUtils.c         |  4 +---
 src/backend/executor/nodeLockRows.c      |  2 +-
 src/backend/executor/nodeModifyTable.c   |  9 +++------
 src/backend/nodes/copyfuncs.c            |  2 +-
 src/backend/nodes/outfuncs.c             |  2 +-
 src/backend/nodes/readfuncs.c            |  2 +-
 src/backend/optimizer/plan/setrefs.c     | 30 +++++++++++++++++++++++++++++
 src/backend/partitioning/partprune.c     |  5 +----
 src/backend/replication/logical/worker.c |  3 ++-
 src/include/executor/executor.h          | 28 +++++++++++++++++++++++++++
 src/include/nodes/execnodes.h            | 22 ++++++++++++++++++++-
 src/include/nodes/plannodes.h            |  2 +-
 src/include/parser/parsetree.h           | 10 ----------
 19 files changed, 141 insertions(+), 59 deletions(-)

diff --git a/contrib/postgres_fdw/postgres_fdw.c 
b/contrib/postgres_fdw/postgres_fdw.c
index e4e330397e..604e480d93 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -1345,7 +1345,7 @@ postgresBeginForeignScan(ForeignScanState *node, int 
eflags)
                rtindex = fsplan->scan.scanrelid;
        else
                rtindex = bms_next_member(fsplan->fs_relids, -1);
-       rte = rt_fetch(rtindex, estate->es_range_table);
+       rte = exec_rt_fetch(rtindex, estate->es_range_table_array);
        userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
 
        /* Get info about foreign table. */
@@ -1732,8 +1732,8 @@ postgresBeginForeignModify(ModifyTableState *mtstate,
                                                                                
FdwModifyPrivateRetrievedAttrs);
 
        /* Find RTE. */
-       rte = rt_fetch(resultRelInfo->ri_RangeTableIndex,
-                                  mtstate->ps.state->es_range_table);
+       rte = exec_rt_fetch(resultRelInfo->ri_RangeTableIndex,
+                                               
mtstate->ps.state->es_range_table_array);
 
        /* Construct an execution state. */
        fmstate = create_foreign_modify(mtstate->ps.state,
@@ -2037,7 +2037,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
         * correspond to this partition if it is one of the UPDATE subplan 
target
         * rels; in that case, we can just use the existing RTE as-is.
         */
-       rte = list_nth(estate->es_range_table, resultRelation - 1);
+       rte = exec_rt_fetch(resultRelation, estate->es_range_table_array);
        if (rte->relid != RelationGetRelid(rel))
        {
                rte = copyObject(rte);
@@ -2397,7 +2397,7 @@ postgresBeginDirectModify(ForeignScanState *node, int 
eflags)
         * ExecCheckRTEPerms() does.
         */
        rtindex = estate->es_result_relation_info->ri_RangeTableIndex;
-       rte = rt_fetch(rtindex, estate->es_range_table);
+       rte = exec_rt_fetch(rtindex, estate->es_range_table_array);
        userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
 
        /* Get info about foreign table. */
@@ -5757,7 +5757,7 @@ conversion_error_callback(void *arg)
                        RangeTblEntry *rte;
                        Var                *var = (Var *) tle->expr;
 
-                       rte = rt_fetch(var->varno, estate->es_range_table);
+                       rte = exec_rt_fetch(var->varno, 
estate->es_range_table_array);
 
                        if (var->varattno == 0)
                                is_wholerow = true;
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9bc67ce60f..3dce6e7359 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2333,6 +2333,8 @@ CopyFrom(CopyState cstate)
        bool            has_before_insert_row_trig;
        bool            has_instead_insert_row_trig;
        bool            leafpart_use_multi_insert = false;
+       int                     i;
+       ListCell   *lc;
 
 #define MAX_BUFFERED_TUPLES 1000
 #define RECHECK_MULTI_INSERT_THRESHOLD 1000
@@ -2482,7 +2484,15 @@ CopyFrom(CopyState cstate)
        estate->es_result_relations = resultRelInfo;
        estate->es_num_result_relations = 1;
        estate->es_result_relation_info = resultRelInfo;
-       estate->es_range_table = cstate->range_table;
+
+       estate->es_range_table_size = list_length(cstate->range_table);
+       estate->es_range_table_array = (RangeTblEntry **)
+                                                                       
palloc(sizeof(RangeTblEntry *) *
+                                                                               
   estate->es_range_table_size);
+       /* Populate the range table array */
+       i = 0;
+       foreach(lc, cstate->range_table)
+               estate->es_range_table_array[i++] = lfirst_node(RangeTblEntry, 
lc);
 
        /* Set up a tuple slot too */
        myslot = ExecInitExtraTupleSlot(estate, tupDesc);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 2436692eb8..e60fd5f1d7 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -75,7 +75,8 @@ static int    MyTriggerDepth = 0;
  * to be changed, however.
  */
 #define GetUpdatedColumns(relinfo, estate) \
-       (rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table)->updatedCols)
+       (exec_rt_fetch((relinfo)->ri_RangeTableIndex,\
+                                  (estate)->es_range_table_array)->updatedCols)
 
 /* Local function prototypes */
 static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid);
diff --git a/src/backend/executor/execExprInterp.c 
b/src/backend/executor/execExprInterp.c
index 9d6e25aae5..5de1d01a94 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3961,10 +3961,11 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, 
ExprContext *econtext)
                 * perhaps other places.)
                 */
                if (econtext->ecxt_estate &&
-                       variable->varno <= 
list_length(econtext->ecxt_estate->es_range_table))
+                       variable->varno <= 
econtext->ecxt_estate->es_range_table_size)
                {
-                       RangeTblEntry *rte = rt_fetch(variable->varno,
-                                                                               
  econtext->ecxt_estate->es_range_table);
+                       RangeTblEntry *rte =
+                               exec_rt_fetch(variable->varno,
+                                                         
econtext->ecxt_estate->es_range_table_array);
 
                        if (rte->eref)
                                ExecTypeSetColNames(output_tupdesc, 
rte->eref->colnames);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 5e0c2b8e67..a219a87483 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -109,9 +109,9 @@ static void EvalPlanQualStart(EPQState *epqstate, EState 
*parentestate,
  * to be changed, however.
  */
 #define GetInsertedColumns(relinfo, estate) \
-       (rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table)->insertedCols)
+       (exec_rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table_array)->insertedCols)
 #define GetUpdatedColumns(relinfo, estate) \
-       (rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table)->updatedCols)
+       (exec_rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table_array)->updatedCols)
 
 /* end of local decls */
 
@@ -814,6 +814,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
        TupleDesc       tupType;
        ListCell   *l;
        int                     i;
+       int                     rti;
 
        /*
         * Do permissions checks
@@ -844,6 +845,17 @@ InitPlan(QueryDesc *queryDesc, int eflags)
         * initialize the node's execution state
         */
        estate->es_range_table = rangeTable;
+       estate->es_range_table_size = list_length(rangeTable);
+       estate->es_range_table_array = (RangeTblEntry **)
+                                                                               
palloc(estate->es_range_table_size *
+                                                                               
           sizeof(RangeTblEntry *));
+       estate->es_relations = (Relation *) palloc0(estate->es_range_table_size 
*
+                                                                               
                sizeof(Relation));
+       /* Fill the RTEs, Relations array will be filled later. */
+       rti = 0;
+       foreach(l, rangeTable)
+               estate->es_range_table_array[rti++] = 
lfirst_node(RangeTblEntry, l);
+
        estate->es_plannedstmt = plannedstmt;
 
        /*
@@ -2278,14 +2290,10 @@ ExecRowMark *
 ExecBuildRowMark(EState *estate, PlanRowMark *rc)
 {
        ExecRowMark *erm;
-       Oid                     relid;
        Relation        relation;
 
        Assert(!rc->isParent);
 
-       /* get relation's OID (will produce InvalidOid if subquery) */
-       relid = getrelid(rc->rti, estate->es_range_table);
-
        /*
         * If you change the conditions under which rel locks are acquired
         * here, be sure to adjust ExecOpenScanRelation to match.
@@ -2296,10 +2304,10 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc)
                case ROW_MARK_NOKEYEXCLUSIVE:
                case ROW_MARK_SHARE:
                case ROW_MARK_KEYSHARE:
-                       relation = heap_open(relid, NoLock);
+                       relation = ExecRangeTableRelation(estate, rc->rti);
                        break;
                case ROW_MARK_REFERENCE:
-                       relation = heap_open(relid, NoLock);
+                       relation = ExecRangeTableRelation(estate, rc->rti);
                        break;
                case ROW_MARK_COPY:
                        /* no physical table access is required */
@@ -2317,7 +2325,7 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc)
 
        erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
        erm->relation = relation;
-       erm->relid = relid;
+       erm->relid = exec_rt_fetch(rc->rti, 
estate->es_range_table_array)->relid;
        erm->rti = rc->rti;
        erm->prti = rc->prti;
        erm->rowmarkId = rc->rowmarkId;
@@ -2975,7 +2983,7 @@ EvalPlanQualBegin(EPQState *epqstate, EState 
*parentestate)
                /*
                 * We already have a suitable child EPQ tree, so just reset it.
                 */
-               int                     rtsize = 
list_length(parentestate->es_range_table);
+               int                     rtsize = 
parentestate->es_range_table_size;
                PlanState  *planstate = epqstate->planstate;
 
                MemSet(estate->es_epqScanDone, 0, rtsize * sizeof(bool));
@@ -3020,7 +3028,7 @@ EvalPlanQualStart(EPQState *epqstate, EState 
*parentestate, Plan *planTree)
        MemoryContext oldcontext;
        ListCell   *l;
 
-       rtsize = list_length(parentestate->es_range_table);
+       rtsize = parentestate->es_range_table_size;
 
        epqstate->estate = estate = CreateExecutorState();
 
@@ -3043,7 +3051,8 @@ EvalPlanQualStart(EPQState *epqstate, EState 
*parentestate, Plan *planTree)
        estate->es_direction = ForwardScanDirection;
        estate->es_snapshot = parentestate->es_snapshot;
        estate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
-       estate->es_range_table = parentestate->es_range_table;
+       estate->es_range_table_array = parentestate->es_range_table_array;
+       estate->es_relations = parentestate->es_relations;
        estate->es_plannedstmt = parentestate->es_plannedstmt;
        estate->es_junkFilter = parentestate->es_junkFilter;
        estate->es_output_cid = parentestate->es_output_cid;
diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index 81c2f5cedc..e56f090a2c 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -831,11 +831,10 @@ ExecCleanupTupleRouting(ModifyTableState *mtstate,
        int                     subplan_index = 0;
 
        /*
-        * Remember, proute->partition_dispatch_info[0] corresponds to the root
-        * partitioned table, which we must not try to close, because it is the
-        * main target table of the query that will be closed by callers such as
-        * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
-        * partitioned table.
+        * proute->partition_dispatch_info[0] corresponds to the root 
partitioned
+        * table, which is the main target table of the query, so it is closed 
by
+        * ExecEndModifyTable() or DoCopy(). Also, tupslot is NULL for the root
+        * partitioned table, so nothing to do here for the root table.
         */
        for (i = 1; i < proute->num_dispatch; i++)
        {
@@ -1432,6 +1431,7 @@ PartitionPruneState *
 ExecCreatePartitionPruneState(PlanState *planstate,
                                                          PartitionPruneInfo 
*partitionpruneinfo)
 {
+       EState     *estate = planstate->state;
        PartitionPruneState *prunestate;
        int                     n_part_hierarchies;
        ListCell   *lc;
@@ -1512,7 +1512,7 @@ ExecCreatePartitionPruneState(PlanState *planstate,
                         * so that we can rely on its copies of the table's 
partition key
                         * and partition descriptor.
                         */
-                       context->partrel = relation_open(pinfo->reloid, NoLock);
+                       context->partrel = ExecRangeTableRelation(estate, 
pinfo->rtindex);
 
                        partkey = RelationGetPartitionKey(context->partrel);
                        partdesc = RelationGetPartitionDesc(context->partrel);
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..94acea245a 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -653,11 +653,9 @@ Relation
 ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
 {
        Relation        rel;
-       Oid                     reloid;
 
        /* Open the relation. */
-       reloid = getrelid(scanrelid, estate->es_range_table);
-       rel = heap_open(reloid, NoLock);
+       rel = ExecRangeTableRelation(estate, scanrelid);
 
        /*
         * Complain if we're attempting a scan of an unscannable relation, 
except
diff --git a/src/backend/executor/nodeLockRows.c 
b/src/backend/executor/nodeLockRows.c
index 8c80291a53..9e7c5e94cf 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -400,7 +400,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
        /*
         * Create workspace in which we can remember per-RTE locked tuples
         */
-       lrstate->lr_ntables = list_length(estate->es_range_table);
+       lrstate->lr_ntables = estate->es_range_table_size;
        lrstate->lr_curtuples = (HeapTuple *)
                palloc0(lrstate->lr_ntables * sizeof(HeapTuple));
 
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index fd3966d489..8c6c26d7d6 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2243,10 +2243,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
        foreach(l, node->resultRelations)
        {
                Index           resultRelationIndex = lfirst_int(l);
-               RangeTblEntry *rte = rt_fetch(resultRelationIndex,
-                                                                         
estate->es_range_table);
-               Relation        rel = heap_open(rte->relid, NoLock);
+               Relation        rel;
 
+               rel = ExecRangeTableRelation(estate, resultRelationIndex);
                InitResultRelInfo(resultRelInfo, rel, resultRelationIndex, NULL,
                                                  estate->es_instrument);
                resultRelInfo++;
@@ -2255,15 +2254,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
        /* If modifying a partitioned table, initialize the root table info */
        if (node->rootResultRelIndex >= 0)
        {
-               RangeTblEntry  *rte;
                Relation                rel;
 
                mtstate->rootResultRelInfo = estate->es_root_result_relations +
                        node->rootResultRelIndex;
 
                Assert(node->rootRelation > 0);
-               rte = rt_fetch(node->rootRelation, estate->es_range_table);
-               rel = heap_open(rte->relid, NoLock);
+               rel = ExecRangeTableRelation(estate, node->rootRelation);
                InitResultRelInfo(mtstate->rootResultRelInfo, rel, 
node->rootRelation,
                                                  NULL, estate->es_instrument);
        }
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 29abe56b70..478cd711cf 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1190,7 +1190,7 @@ _copyPartitionedRelPruneInfo(const 
PartitionedRelPruneInfo *from)
 {
        PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo);
 
-       COPY_SCALAR_FIELD(reloid);
+       COPY_SCALAR_FIELD(rtindex);
        COPY_NODE_FIELD(pruning_steps);
        COPY_BITMAPSET_FIELD(present_parts);
        COPY_SCALAR_FIELD(nparts);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index ac1e434ce5..7589299c97 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1025,7 +1025,7 @@ _outPartitionedRelPruneInfo(StringInfo str, const 
PartitionedRelPruneInfo *node)
 
        WRITE_NODE_TYPE("PARTITIONEDRELPRUNEINFO");
 
-       WRITE_OID_FIELD(reloid);
+       WRITE_UINT_FIELD(rtindex);
        WRITE_NODE_FIELD(pruning_steps);
        WRITE_BITMAPSET_FIELD(present_parts);
        WRITE_INT_FIELD(nparts);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 780d261edf..df80a31cc1 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2338,7 +2338,7 @@ _readPartitionedRelPruneInfo(void)
 {
        READ_LOCALS(PartitionedRelPruneInfo);
 
-       READ_OID_FIELD(reloid);
+       READ_UINT_FIELD(rtindex);
        READ_NODE_FIELD(pruning_steps);
        READ_BITMAPSET_FIELD(present_parts);
        READ_INT_FIELD(nparts);
diff --git a/src/backend/optimizer/plan/setrefs.c 
b/src/backend/optimizer/plan/setrefs.c
index f516b3a85c..9990cc4155 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -892,6 +892,21 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                                                                                
          (Plan *) lfirst(l),
                                                                                
          rtoffset);
                                }
+                               if (splan->part_prune_info)
+                               {
+                                       foreach(l, 
splan->part_prune_info->prune_infos)
+                                       {
+                                               List *prune_infos = lfirst(l);
+                                               ListCell *l2;
+
+                                               foreach(l2, prune_infos)
+                                               {
+                                                       PartitionedRelPruneInfo 
*pinfo = lfirst(l2);
+
+                                                       pinfo->rtindex += 
rtoffset;
+                                               }
+                                       }
+                               }
                        }
                        break;
                case T_MergeAppend:
@@ -910,6 +925,21 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                                                                                
          (Plan *) lfirst(l),
                                                                                
          rtoffset);
                                }
+                               if (splan->part_prune_info)
+                               {
+                                       foreach(l, 
splan->part_prune_info->prune_infos)
+                                       {
+                                               List *prune_infos = lfirst(l);
+                                               ListCell *l2;
+
+                                               foreach(l2, prune_infos)
+                                               {
+                                                       PartitionedRelPruneInfo 
*pinfo = lfirst(l2);
+
+                                                       pinfo->rtindex += 
rtoffset;
+                                               }
+                                       }
+                               }
                        }
                        break;
                case T_RecursiveUnion:
diff --git a/src/backend/partitioning/partprune.c 
b/src/backend/partitioning/partprune.c
index b5c1c7d4dd..c46b8166a6 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -357,7 +357,6 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo 
*parentrel,
                Index           rti = lfirst_int(lc);
                RelOptInfo *subpart = find_base_rel(root, rti);
                PartitionedRelPruneInfo *pinfo;
-               RangeTblEntry *rte;
                Bitmapset  *present_parts;
                int                     nparts = subpart->nparts;
                int                     partnatts = 
subpart->part_scheme->partnatts;
@@ -459,10 +458,8 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, 
RelOptInfo *parentrel,
                                present_parts = bms_add_member(present_parts, 
i);
                }
 
-               rte = root->simple_rte_array[subpart->relid];
-
                pinfo = makeNode(PartitionedRelPruneInfo);
-               pinfo->reloid = rte->relid;
+               pinfo->rtindex = rti;
                pinfo->pruning_steps = pruning_steps;
                pinfo->present_parts = present_parts;
                pinfo->nparts = nparts;
diff --git a/src/backend/replication/logical/worker.c 
b/src/backend/replication/logical/worker.c
index 2054abe653..5e7aa7c6c5 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -199,7 +199,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
        rte->rtekind = RTE_RELATION;
        rte->relid = RelationGetRelid(rel->localrel);
        rte->relkind = rel->localrel->rd_rel->relkind;
-       estate->es_range_table = list_make1(rte);
+       estate->es_range_table_array = &rte;
+       estate->es_range_table_size = 1;
 
        resultRelInfo = makeNode(ResultRelInfo);
        InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..4752dcc9c7 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -17,6 +17,7 @@
 #include "executor/execdesc.h"
 #include "nodes/parsenodes.h"
 #include "utils/memutils.h"
+#include "utils/rel.h"
 
 
 /*
@@ -568,4 +569,31 @@ extern void CheckCmdReplicaIdentity(Relation rel, CmdType 
cmd);
 extern void CheckSubscriptionRelkind(char relkind, const char *nspname,
                                                 const char *relname);
 
+#ifndef FRONTEND
+static inline Relation
+ExecRangeTableRelation(EState *estate, Index rti)
+{
+       RangeTblEntry *rte;
+       Relation rel;
+
+       if (estate->es_relations[rti - 1] != NULL)
+       {
+               RelationIncrementReferenceCount(estate->es_relations[rti - 1]);
+               rel = estate->es_relations[rti - 1];
+       }
+       else
+       {
+               rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+               /*
+                * No need to lock the relation lock, because upstream code
+                * must hold the lock already.
+                */
+               rel = estate->es_relations[rti - 1] = heap_open(rte->relid, 
NoLock);
+       }
+
+       return rel;
+}
+#endif
+
 #endif                                                 /* EXECUTOR_H  */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index c830f141b1..966e2f3b62 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -20,6 +20,7 @@
 #include "executor/instrument.h"
 #include "lib/pairingheap.h"
 #include "nodes/params.h"
+#include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
 #include "utils/hsearch.h"
 #include "utils/queryenvironment.h"
@@ -478,7 +479,10 @@ typedef struct EState
        ScanDirection es_direction; /* current scan direction */
        Snapshot        es_snapshot;    /* time qual to use */
        Snapshot        es_crosscheck_snapshot; /* crosscheck time qual for RI 
*/
-       List       *es_range_table; /* List of RangeTblEntry */
+       List       *es_range_table;     /* List of RangeTblEntry */
+       struct RangeTblEntry **es_range_table_array;    /* 0-based range table 
*/
+       int                     es_range_table_size;    /* size of the range 
table array */
+       Relation   *es_relations;       /* 0-based array of Relation pointers */
        PlannedStmt *es_plannedstmt;    /* link to top of plan tree */
        const char *es_sourceText;      /* Source text from QueryDesc */
 
@@ -573,7 +577,23 @@ typedef struct EState
        int                     es_jit_flags;
        struct JitContext *es_jit;
 } EState;
+ 
+/*
+ *             exec_rt_fetch
+ *
+ * NB: this will crash and burn if handed an out-of-range RT index
+ */
+#define exec_rt_fetch(rangetblidx, rangetbl) rangetbl[(rangetblidx) - 1]
 
+/* XXX moved from parsetree.h. okay??
+ *             getrelid
+ *
+ *             Given the range index of a relation, return the corresponding
+ *             relation OID.  Note that InvalidOid will be returned if the
+ *             RTE is for a non-relation-type RTE.
+ */
+#define getrelid(rangeindex,rangetable) \
+       (exec_rt_fetch(rangeindex, rangetable)->relid)
 
 /*
  * ExecRowMark -
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index a342edf49c..34f7de1f9d 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1091,7 +1091,7 @@ typedef struct PartitionPruneInfo
 typedef struct PartitionedRelPruneInfo
 {
        NodeTag         type;
-       Oid                     reloid;                 /* OID of partition rel 
for this level */
+       Index           rtindex;                /* Table's RT index */
        List       *pruning_steps;      /* List of PartitionPruneStep, see 
below */
        Bitmapset  *present_parts;      /* Indexes of all partitions which 
subplans or
                                                                 * subparts are 
present for. */
diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h
index dd9ae658ac..fe16d7d1fa 100644
--- a/src/include/parser/parsetree.h
+++ b/src/include/parser/parsetree.h
@@ -32,16 +32,6 @@
        ((RangeTblEntry *) list_nth(rangetable, (rangetable_index)-1))
 
 /*
- *             getrelid
- *
- *             Given the range index of a relation, return the corresponding
- *             relation OID.  Note that InvalidOid will be returned if the
- *             RTE is for a non-relation-type RTE.
- */
-#define getrelid(rangeindex,rangetable) \
-       (rt_fetch(rangeindex, rangetable)->relid)
-
-/*
  * Given an RTE and an attribute number, return the appropriate
  * variable name or alias for that attribute of that RTE.
  */
-- 
2.11.0

Reply via email to