This is the continuation of the discussion at:

https://www.postgresql.org/message-id/7500.1531920772%40sss.pgh.pa.us

Actually, for more background on what I've written below, reading this
email in the same discussion would help:

https://www.postgresql.org/message-id/4114.1531674...@sss.pgh.pa.us


Attached find a series of patches, the first of which tries to implement
the main topic discussed in the above email, which is to eliminate
execution-time locking of relations in PlannedStmt.rtable.  One of the
other patches removes the plan node fields that are obsoleted by
eliminating execution-time locking of relations.  Those fields served no
purpose beside telling the executor which relations to lock, or more
precisely which relations to lock before initializing the plan tree so
that we don't end up upgrading lock strength due to same relation being
both a source relation and target relation.

When working on that, I noticed that planner fails to remove PlanRowMarks
of relations that won't be scanned by a given plan, which results in
executor redundantly locking relations that the planner already deemed
unnecessary to scan.  The locking would be gone with one of the proposed
patches, but there are still a couple of overheads during executor
initialization of having all those PlanRowMarks.  For example,
ExecInitLockRows or ExecInitModifyTable calling ExecFindRowMark would end
up going over PlanRowMarks that won't ever be used, which especially grows
worse with many partitions.

Short description of each patch follows:

0001-Don-t-lock-range-table-relations-in-the-executor.patch

This removes all instances of heap_open(relid, <not-NoLock>) in the
executor code with heap_open(relid, NoLock).  To verify that an
appropriate lock is already taken on a relation by the time we get into
executor, this also installs an assert-build-only check that confirms that
lmgr indeed holds the lock.  To remember which lock was taken when
creating a given RTE_RELATION range table entry, this adds a lockmode
field to RangeTblEntry.  Finally, because we don't lock in the executor
and hence there are no concerns about lock strength upgrade hazard,
InitPlan doesn't need toinitialize ResultRelInfos and ExecRowMarks, in
favor of doing that in the ExecInit* routines of respective nodes which
need those ResultRelInfos and ExecLockRows.

(This doesn't touch index relations though, as they don't have a range
table entry.)   

0002-Remove-useless-fields-from-planner-nodes.patch

This removes some fields from PlannedStmt whose only purpose currently is
to help InitPlan do certain things that it no longer does, as mentioned
above.  Also, some fields in Append, MergeAppend, ModifyTable, whose only
purpose currently is to propagate partitioned table RT indexes so that
executor could lock them, are removed.  Removing them also means that the
planner doesn't have to spend cycles initializing them.

0003-Prune-PlanRowMark-of-relations-that-are-pruned-from-.patch

This prevents PlanRowMarks corresponding to relations that won't be
scanned by a given plan from appearing in the rowMarks field of LockRows
or ModifyTable nodes.  This results in removing significant overhead from
the executor initialization of those nodes, especially for partitioned
tables with many partitions.

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.



Although improving executor's performance is not the main goal of these
patches, the fact that we're getting rid of redundant processing means
there would be at least some speedup, especially with large number of
relations in the range table, such as with partitioned tables with many
partitions.

* Benchmark script used:

$ cat /tmp/select-lt.sql
select * from lt where b = 999;

'lt' above is a list-partitioned table with 1000 partitions, with one
partition for each value in the range 1..1000.


$ for i in 1 2;
> do
> pgbench -n -Mprepared -T 60 -f /tmp/select-lt.sql
> done

master

tps = 768.172129 (excluding connections establishing)
tps = 764.180834 (excluding connections establishing)

patch 0001 (no locking in the executor)

tps = 775.060323 (excluding connections establishing)
tps = 778.772917 (excluding connections establishing)

patch 0002 (remove useless planner node fields)

tps = 782.165436 (excluding connections establishing)
tps = 759.417411 (excluding connections establishing

patch 0003 (prune PlanRowMarks)

tps = 783.558539 (excluding connections establishing)
tps = 776.106055 (excluding connections establishing)

patch 0004 (executor range table Relation open)

tps = 778.924649 (excluding connections establishing)
tps = 769.093431 (excluding connections establishing)


Speedup is more pronounced with a benchmark that needs RowMarks, because
one of the patches (0003) removes overhead around handling them.

$ cat /tmp/select-lt-for-share.sql
select * from lt where b = 999 for share;

master

tps = 94.095985 (excluding connections establishing)
tps = 93.955702 (excluding connections establishing)

patch 0001 (no locking in the executor)

tps = 199.030555 (excluding connections establishing)
tps = 197.630424 (excluding connections establishing)

patch 0002 (remove useless planner node fields)

tps = 194.384994 (excluding connections establishing)
tps = 195.821362 (excluding connections establishing)

patch 0003 (prune PlanRowMarks)

tps = 712.544029 (excluding connections establishing)
tps = 717.540052 (excluding connections establishing)

patch 0004 (executor range table Relation open)

tps = 725.189715 (excluding connections establishing)
tps = 727.344683 (excluding connections establishing)


Will add this to next CF.

Thanks,
Amit
From 14f9d6e7d443e7f9c0601210aab59d5cf3c6b249 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v1 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 7d4511c585..2a021a028b 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 d13be4145f..3db0b99aa6 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 6269f474d2..b4d2a4aa4c 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3126,6 +3126,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 3123ee274d..5b12e3c80c 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,
@@ -2886,6 +2872,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
@@ -3093,6 +3080,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 6b934cf39c05fc0f3720bb8817e0489cf7e0c339 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Mon, 13 Aug 2018 16:10:19 +0900
Subject: [PATCH v1 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 b4d2a4aa4c..f5fd9e6345 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 69dd327f0c..7db9d0f1d4 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -215,7 +215,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
@@ -224,25 +223,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);
 }
@@ -852,12 +832,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;
@@ -888,24 +866,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;
@@ -919,10 +890,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,
@@ -941,10 +908,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 41caf873fb..10d9327b8b 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 */
@@ -1713,8 +1710,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 8ca856147b53d806d597101a73b4cdeff429c7ff Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Tue, 14 Aug 2018 10:35:47 +0900
Subject: [PATCH v1 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 e519b5c78ce6c21df524a609eb9acf582f49cb79 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Thu, 19 Jul 2018 13:01:43 +0900
Subject: [PATCH v1 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.
---
 src/backend/executor/execExprInterp.c  |  6 ++++--
 src/backend/executor/execMain.c        | 34 +++++++++++++++++++++++++---------
 src/backend/executor/execPartition.c   | 12 ++++++------
 src/backend/executor/execUtils.c       |  4 +---
 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/include/executor/executor.h        | 30 ++++++++++++++++++++++++++++++
 src/include/nodes/execnodes.h          |  7 +++++++
 src/include/nodes/plannodes.h          |  2 +-
 13 files changed, 111 insertions(+), 34 deletions(-)

diff --git a/src/backend/executor/execExprInterp.c 
b/src/backend/executor/execExprInterp.c
index 9d6e25aae5..af8c636d94 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3963,8 +3963,10 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, 
ExprContext *econtext)
                if (econtext->ecxt_estate &&
                        variable->varno <= 
list_length(econtext->ecxt_estate->es_range_table))
                {
-                       RangeTblEntry *rte = rt_fetch(variable->varno,
-                                                                               
  econtext->ecxt_estate->es_range_table);
+                       RangeTblEntry *rte = 
econtext->ecxt_estate->es_rtable_array ?
+                                       
econtext->ecxt_estate->es_rtable_array[variable->varno] :
+                                       rt_fetch(variable->varno,
+                                                        
econtext->ecxt_estate->es_range_table);
 
                        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..c3899d9068 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -109,9 +109,13 @@ 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)
+       ((estate)->es_rtable_array != NULL ?\
+        (estate)->es_rtable_array[(relinfo)->ri_RangeTableIndex]->insertedCols 
:\
+        rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table)->insertedCols)
 #define GetUpdatedColumns(relinfo, estate) \
-       (rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table)->updatedCols)
+       ((estate)->es_rtable_array != NULL ?\
+        (estate)->es_rtable_array[(relinfo)->ri_RangeTableIndex]->updatedCols 
:\
+        rt_fetch((relinfo)->ri_RangeTableIndex, 
(estate)->es_range_table)->updatedCols)
 
 /* end of local decls */
 
@@ -814,6 +818,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
        TupleDesc       tupType;
        ListCell   *l;
        int                     i;
+       int                     rti;
 
        /*
         * Do permissions checks
@@ -844,6 +849,17 @@ InitPlan(QueryDesc *queryDesc, int eflags)
         * initialize the node's execution state
         */
        estate->es_range_table = rangeTable;
+
+       /* allocate space for Relation pointer and initialize with 0s. */
+       estate->es_relations = (Relation *)
+                                       palloc0((list_length(rangeTable) + 1) * 
sizeof(Relation));
+       estate->es_rtable_array = (RangeTblEntry **)
+                                       palloc((list_length(rangeTable) + 1) *
+                                                  sizeof(RangeTblEntry *));
+       rti = 1;
+       foreach(l, rangeTable)
+               estate->es_rtable_array[rti++] = lfirst(l);
+
        estate->es_plannedstmt = plannedstmt;
 
        /*
@@ -2278,14 +2294,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 +2308,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 +2329,7 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc)
 
        erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
        erm->relation = relation;
-       erm->relid = relid;
+       erm->relid = estate->es_rtable_array[rc->rti]->relid;
        erm->rti = rc->rti;
        erm->prti = rc->prti;
        erm->rowmarkId = rc->rowmarkId;
@@ -3114,6 +3126,10 @@ EvalPlanQualStart(EPQState *epqstate, EState 
*parentestate, Plan *planTree)
         */
        estate->es_tupleTable = NIL;
 
+       /* OK to use these as is from the parent. */
+       estate->es_rtable_array = parentestate->es_rtable_array;
+       estate->es_relations = parentestate->es_relations;
+
        /*
         * Initialize private state information for each SubPlan.  We must do 
this
         * before running ExecInitNode on the main query tree, since
diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index 3db0b99aa6..cf4b569d5c 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/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 f5fd9e6345..dd53ef3115 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 7db9d0f1d4..0e53981834 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -896,6 +896,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:
@@ -914,6 +929,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 0dd55ac1ba..58d8ad6f24 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/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..97d86788ba 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,33 @@ 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] != NULL)
+       {
+               RelationIncrementReferenceCount(estate->es_relations[rti]);
+               rel = estate->es_relations[rti];
+       }
+       else
+       {
+               Assert(estate->es_rtable_array != NULL &&
+                          estate->es_rtable_array[rti] != NULL);
+               rte = estate->es_rtable_array[rti];
+
+               /*
+                * No need to lock the relation lock, because upstream code
+                * must hold the lock already.
+                */
+               rel = estate->es_relations[rti] = 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 41fa2052a2..127153b3be 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"
@@ -486,6 +487,12 @@ typedef struct EState
        /* If query can insert/delete tuples, the command ID to mark them with 
*/
        CommandId       es_output_cid;
 
+       /* Array of RT entries indexed by their RT indexes. */
+       RangeTblEntry **es_rtable_array;
+
+       /* Relation pointers for all relations in es_range_table. */
+       Relation   *es_relations;
+
        /* Info about target table(s) for insert/update/delete queries: */
        ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
        int                     es_num_result_relations;        /* length of 
array */
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. */
-- 
2.11.0

Reply via email to