Imai-san,

Thanks for testing and sorry it took me a while to reply.

On 2019/02/25 15:24, Imai, Yoshikazu wrote:
> [update_pt_with_joining_another_pt.sql]
> update rt set c = jrt.c + 100 from jrt where rt.b = jrt.b;
> 
> [pgbench]
> pgbench -n -f update_pt_with_joining_another_pt_for_ptkey.sql -T 60 postgres
> 
> [results]
> (part_num_rt, part_num_jrt)  master  patched(0001)
> ---------------------------  ------  -------------
>                   (3, 1024)    8.06           5.89
>                   (3, 2048)    1.52           0.87
>                   (6, 1024)    4.11           1.77
> 
> 
> 
> With HEAD, we add target inheritance and source inheritance to parse->rtable 
> in inheritance_planner and copy and adjust it for child tables at beginning 
> of each planning of child tables.
> 
> With the 0001 patch, we add target inheritance to parse->rtable in 
> inheritance_planner and add source inheritance to parse->rtable in 
> make_one_rel(under grouping_planner()) during each planning of child tables.
> Adding source inheritance to parse->rtable may be the same process between 
> each planning of child tables and it might be useless. OTOH, from the POV of 
> making inheritance-expansion-at-bottom better, expanding source inheritance 
> in make_one_rel seems correct design to me.
> 
> How should we do that...?

To solve this problem, I ended up teaching inheritance_planner to reuse
the objects for *source* inheritance child relations (RTEs,
AppendRelInfos, and PlanRowMarks) created during the planning of the 1st
child query for the planning of subsequent child queries.  Set of source
child relations don't change between different planning runs, so it's okay
to do so.  Of course, I had to make sure that query_planner (which is not
in the charge of adding source inheritance child objects) can notice that.

Please find attached updated patches.  Will update source code comments,
commit message and perform other fine-tuning over the weekend if possible.

Thanks,
Amit
From 2f4c085145c3991c8d7160eab0c90d5d3f9d713e Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Fri, 26 Oct 2018 16:45:59 +0900
Subject: [PATCH v25 1/2] Lazy creation of RTEs for inheritance children

Rewrite inherit.c so that source inheritance could be expanded
during query_planner().  That's better because for partitioned
tables, we can add only the partitions left after performing
partition pruning.

Since it's not known what RowMark identities are necessary for
individual inheritance children until they're added to the query,
preprocess_targetlist must delay adding junk columns if there are
any parent PlanRowMarks.

For partitioning, although we don't create a RangeTblEntry and
RelOptInfo for pruned partitions at make_one_rel time, partitionwise
join code relies on the fact that even though partitions may have
been pruned, they'd still own a RelOptInfo to handle the outer join
case where the pruned partition appears on the nullable side of join.
Partitionwise join code deals with that by allocating dummy
RelOptInfos for pruned partitions that are based mostly on their
parent's properties.

There are a few regression test diffs:

 1. Caused by the fact that we no longer allocate a duplicate RT
    entry for a partitioned table in its role as child, as seen in
    the partition_aggregate.out test output.

 2. Those in postgres_fdw.out are caused by the fact that junk columns
    required for row marking are added to reltarget->exprs later than
    user columns, because the row marking junk columns aren't added
    until the inheritance is expanded which as of this commit is
    later than it used to be as noted above.
---
 contrib/postgres_fdw/expected/postgres_fdw.out    |  24 +-
 src/backend/optimizer/path/allpaths.c             | 202 +------
 src/backend/optimizer/path/joinrels.c             |  92 +++-
 src/backend/optimizer/plan/initsplan.c            |  53 +-
 src/backend/optimizer/plan/planmain.c             |  15 +-
 src/backend/optimizer/plan/planner.c              | 271 +++++++---
 src/backend/optimizer/plan/setrefs.c              |   6 +
 src/backend/optimizer/prep/preptlist.c            | 130 +++--
 src/backend/optimizer/util/inherit.c              | 620 +++++++++++++---------
 src/backend/optimizer/util/plancat.c              |  18 +-
 src/backend/optimizer/util/relnode.c              | 359 +++++++++++--
 src/backend/partitioning/partprune.c              |  44 +-
 src/include/nodes/pathnodes.h                     |   7 +
 src/include/optimizer/inherit.h                   |   5 +-
 src/include/optimizer/pathnode.h                  |   3 +
 src/include/optimizer/plancat.h                   |   4 +-
 src/include/optimizer/planmain.h                  |   1 +
 src/include/optimizer/prep.h                      |   2 +
 src/test/regress/expected/partition_aggregate.out |   4 +-
 19 files changed, 1185 insertions(+), 675 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out 
b/contrib/postgres_fdw/expected/postgres_fdw.out
index 42108bd3d4..4d31cfed5d 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -7128,15 +7128,15 @@ select * from bar where f1 in (select f1 from foo) for 
update;
                      Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid
                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR 
UPDATE
          ->  Hash
-               Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+               Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                ->  HashAggregate
-                     Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+                     Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                      Group Key: foo.f1
                      ->  Append
                            ->  Seq Scan on public.foo
-                                 Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+                                 Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                            ->  Foreign Scan on public.foo2
-                                 Output: foo2.ctid, foo2.*, foo2.tableoid, 
foo2.f1
+                                 Output: foo2.f1, foo2.ctid, foo2.*, 
foo2.tableoid
                                  Remote SQL: SELECT f1, f2, f3, ctid FROM 
public.loct1
 (23 rows)
 
@@ -7166,15 +7166,15 @@ select * from bar where f1 in (select f1 from foo) for 
share;
                      Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid
                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR 
SHARE
          ->  Hash
-               Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+               Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                ->  HashAggregate
-                     Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+                     Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                      Group Key: foo.f1
                      ->  Append
                            ->  Seq Scan on public.foo
-                                 Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+                                 Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                            ->  Foreign Scan on public.foo2
-                                 Output: foo2.ctid, foo2.*, foo2.tableoid, 
foo2.f1
+                                 Output: foo2.f1, foo2.ctid, foo2.*, 
foo2.tableoid
                                  Remote SQL: SELECT f1, f2, f3, ctid FROM 
public.loct1
 (23 rows)
 
@@ -7203,15 +7203,15 @@ update bar set f2 = f2 + 100 where f1 in (select f1 
from foo);
          ->  Seq Scan on public.bar
                Output: bar.f1, bar.f2, bar.ctid
          ->  Hash
-               Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+               Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                ->  HashAggregate
-                     Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+                     Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                      Group Key: foo.f1
                      ->  Append
                            ->  Seq Scan on public.foo
-                                 Output: foo.ctid, foo.*, foo.tableoid, foo.f1
+                                 Output: foo.f1, foo.ctid, foo.*, foo.tableoid
                            ->  Foreign Scan on public.foo2
-                                 Output: foo2.ctid, foo2.*, foo2.tableoid, 
foo2.f1
+                                 Output: foo2.f1, foo2.ctid, foo2.*, 
foo2.tableoid
                                  Remote SQL: SELECT f1, f2, f3, ctid FROM 
public.loct1
    ->  Hash Join
          Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, foo.ctid, 
foo.*, foo.tableoid
diff --git a/src/backend/optimizer/path/allpaths.c 
b/src/backend/optimizer/path/allpaths.c
index 0debac75c6..29ac5d8b0e 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -44,7 +44,6 @@
 #include "optimizer/tlist.h"
 #include "parser/parse_clause.h"
 #include "parser/parsetree.h"
-#include "partitioning/partprune.h"
 #include "rewrite/rewriteManip.h"
 #include "utils/lsyscache.h"
 
@@ -138,9 +137,6 @@ static void subquery_push_qual(Query *subquery,
 static void recurse_push_qual(Node *setOp, Query *topquery,
                                  RangeTblEntry *rte, Index rti, Node *qual);
 static void remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel);
-static bool apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
-                                         RelOptInfo *childrel,
-                                         RangeTblEntry *childRTE, 
AppendRelInfo *appinfo);
 
 
 /*
@@ -945,8 +941,6 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
        double     *parent_attrsizes;
        int                     nattrs;
        ListCell   *l;
-       Relids          live_children = NULL;
-       bool            did_pruning = false;
 
        /* Guard against stack overflow due to overly deep inheritance tree. */
        check_stack_depth();
@@ -954,32 +948,6 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
        Assert(IS_SIMPLE_REL(rel));
 
        /*
-        * Initialize partitioned_child_rels to contain this RT index.
-        *
-        * Note that during the set_append_rel_pathlist() phase, we will bubble 
up
-        * the indexes of partitioned relations that appear down in the tree, so
-        * that when we've created Paths for all the children, the root
-        * partitioned table's list will contain all such indexes.
-        */
-       if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-               rel->partitioned_child_rels = list_make1_int(rti);
-
-       /*
-        * If the partitioned relation has any baserestrictinfo quals then we
-        * attempt to use these quals to prune away partitions that cannot
-        * possibly contain any tuples matching these quals.  In this case we'll
-        * store the relids of all partitions which could possibly contain a
-        * matching tuple, and skip anything else in the loop below.
-        */
-       if (enable_partition_pruning &&
-               rte->relkind == RELKIND_PARTITIONED_TABLE &&
-               rel->baserestrictinfo != NIL)
-       {
-               live_children = prune_append_rel_partitions(rel);
-               did_pruning = true;
-       }
-
-       /*
         * If this is a partitioned baserel, set the consider_partitionwise_join
         * flag; currently, we only consider partitionwise joins with the 
baserel
         * if its targetlist doesn't contain a whole-row Var.
@@ -1025,50 +993,26 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 
                childRTindex = appinfo->child_relid;
                childRTE = root->simple_rte_array[childRTindex];
+               Assert(childRTE != NULL);
 
                /*
-                * The child rel's RelOptInfo was already created during
-                * add_base_rels_to_query.
+                * The child rel's RelOptInfo was created during
+                * add_other_rels_to_query().
                 */
                childrel = find_base_rel(root, childRTindex);
+               Assert(childrel != NULL);
                Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
 
-               if (did_pruning && !bms_is_member(appinfo->child_relid, 
live_children))
-               {
-                       /* This partition was pruned; skip it. */
-                       set_dummy_rel_pathlist(childrel);
-                       continue;
-               }
-
                /*
-                * We have to copy the parent's targetlist and quals to the 
child,
-                * with appropriate substitution of variables.  If any constant 
false
-                * or NULL clauses turn up, we can disregard the child right 
away.
-                * If not, we can apply constraint exclusion with just the
-                * baserestrictinfo quals.
+                * Child relation may have been marked dummy if 
build_append_child_rel
+                * found self-contradictory quals or quals that contradict its
+                * constraints.
                 */
-               if (!apply_child_basequals(root, rel, childrel, childRTE, 
appinfo))
-               {
-                       /*
-                        * Some restriction clause reduced to constant FALSE or 
NULL after
-                        * substitution, so this child need not be scanned.
-                        */
-                       set_dummy_rel_pathlist(childrel);
+               if (IS_DUMMY_REL(childrel))
                        continue;
-               }
-
-               if (relation_excluded_by_constraints(root, childrel, childRTE))
-               {
-                       /*
-                        * This child need not be scanned, so we can omit it 
from the
-                        * appendrel.
-                        */
-                       set_dummy_rel_pathlist(childrel);
-                       continue;
-               }
 
                /*
-                * CE failed, so finish copying/modifying targetlist and join 
quals.
+                * Copy/Modify targetlist.
                 *
                 * NB: the resulting childrel->reltarget->exprs may contain 
arbitrary
                 * expressions, which otherwise would not occur in a rel's 
targetlist.
@@ -3557,134 +3501,6 @@ generate_partitionwise_join_paths(PlannerInfo *root, 
RelOptInfo *rel)
        list_free(live_children);
 }
 
-/*
- * apply_child_basequals
- *             Populate childrel's quals based on rel's quals, translating 
them using
- *             appinfo.
- *
- * If any of the resulting clauses evaluate to false or NULL, we return false
- * and don't apply any quals.  Caller can mark the relation as a dummy rel in
- * this case, since it needn't be scanned.
- *
- * If any resulting clauses evaluate to true, they're unnecessary and we don't
- * apply then.
- */
-static bool
-apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
-                                         RelOptInfo *childrel, RangeTblEntry 
*childRTE,
-                                         AppendRelInfo *appinfo)
-{
-       List       *childquals;
-       Index           cq_min_security;
-       ListCell   *lc;
-
-       /*
-        * The child rel's targetlist might contain non-Var expressions, which
-        * means that substitution into the quals could produce opportunities 
for
-        * const-simplification, and perhaps even pseudoconstant quals. 
Therefore,
-        * transform each RestrictInfo separately to see if it reduces to a
-        * constant or pseudoconstant.  (We must process them separately to keep
-        * track of the security level of each qual.)
-        */
-       childquals = NIL;
-       cq_min_security = UINT_MAX;
-       foreach(lc, rel->baserestrictinfo)
-       {
-               RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
-               Node       *childqual;
-               ListCell   *lc2;
-
-               Assert(IsA(rinfo, RestrictInfo));
-               childqual = adjust_appendrel_attrs(root,
-                                                                               
   (Node *) rinfo->clause,
-                                                                               
   1, &appinfo);
-               childqual = eval_const_expressions(root, childqual);
-               /* check for flat-out constant */
-               if (childqual && IsA(childqual, Const))
-               {
-                       if (((Const *) childqual)->constisnull ||
-                               !DatumGetBool(((Const *) 
childqual)->constvalue))
-                       {
-                               /* Restriction reduces to constant FALSE or 
NULL */
-                               return false;
-                       }
-                       /* Restriction reduces to constant TRUE, so drop it */
-                       continue;
-               }
-               /* might have gotten an AND clause, if so flatten it */
-               foreach(lc2, make_ands_implicit((Expr *) childqual))
-               {
-                       Node       *onecq = (Node *) lfirst(lc2);
-                       bool            pseudoconstant;
-
-                       /* check for pseudoconstant (no Vars or volatile 
functions) */
-                       pseudoconstant =
-                               !contain_vars_of_level(onecq, 0) &&
-                               !contain_volatile_functions(onecq);
-                       if (pseudoconstant)
-                       {
-                               /* tell createplan.c to check for gating quals 
*/
-                               root->hasPseudoConstantQuals = true;
-                       }
-                       /* reconstitute RestrictInfo with appropriate 
properties */
-                       childquals = lappend(childquals,
-                                                                
make_restrictinfo((Expr *) onecq,
-                                                                               
                   rinfo->is_pushed_down,
-                                                                               
                   rinfo->outerjoin_delayed,
-                                                                               
                   pseudoconstant,
-                                                                               
                   rinfo->security_level,
-                                                                               
                   NULL, NULL, NULL));
-                       /* track minimum security level among child quals */
-                       cq_min_security = Min(cq_min_security, 
rinfo->security_level);
-               }
-       }
-
-       /*
-        * In addition to the quals inherited from the parent, we might have
-        * securityQuals associated with this particular child node. (Currently
-        * this can only happen in appendrels originating from UNION ALL;
-        * inheritance child tables don't have their own securityQuals, see
-        * expand_inherited_rtentry().) Pull any such securityQuals up into the
-        * baserestrictinfo for the child.  This is similar to
-        * process_security_barrier_quals() for the parent rel, except that we
-        * can't make any general deductions from such quals, since they don't
-        * hold for the whole appendrel.
-        */
-       if (childRTE->securityQuals)
-       {
-               Index           security_level = 0;
-
-               foreach(lc, childRTE->securityQuals)
-               {
-                       List       *qualset = (List *) lfirst(lc);
-                       ListCell   *lc2;
-
-                       foreach(lc2, qualset)
-                       {
-                               Expr       *qual = (Expr *) lfirst(lc2);
-
-                               /* not likely that we'd see constants here, so 
no check */
-                               childquals = lappend(childquals,
-                                                                        
make_restrictinfo(qual,
-                                                                               
                           true, false, false,
-                                                                               
                           security_level,
-                                                                               
                           NULL, NULL, NULL));
-                               cq_min_security = Min(cq_min_security, 
security_level);
-                       }
-                       security_level++;
-               }
-               Assert(security_level <= root->qual_security_level);
-       }
-
-       /*
-        * OK, we've got all the baserestrictinfo quals for this child.
-        */
-       childrel->baserestrictinfo = childquals;
-       childrel->baserestrict_min_security = cq_min_security;
-
-       return true;
-}
-
 /*****************************************************************************
  *                     DEBUG SUPPORT
  *****************************************************************************/
diff --git a/src/backend/optimizer/path/joinrels.c 
b/src/backend/optimizer/path/joinrels.c
index dfbbfdac6d..66a5cf3334 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -14,6 +14,7 @@
  */
 #include "postgres.h"
 
+#include "access/table.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/appendinfo.h"
@@ -21,6 +22,8 @@
 #include "optimizer/joininfo.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
+#include "optimizer/tlist.h"
+#include "parser/parsetree.h"
 #include "partitioning/partbounds.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
@@ -52,6 +55,9 @@ static SpecialJoinInfo *build_child_join_sjinfo(PlannerInfo 
*root,
                                                Relids left_relids, Relids 
right_relids);
 static int match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel,
                                                         bool strict_op);
+static RelOptInfo *build_dummy_partition_rel(PlannerInfo *root,
+                                                                       
RelOptInfo *parent, Relation parentrel,
+                                                                       int 
partidx);
 
 
 /*
@@ -1318,6 +1324,8 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo 
*rel1, RelOptInfo *rel2,
                                           RelOptInfo *joinrel, SpecialJoinInfo 
*parent_sjinfo,
                                           List *parent_restrictlist)
 {
+       Relation        baserel1 = NULL,
+                               baserel2 = NULL;
        bool            rel1_is_simple = IS_SIMPLE_REL(rel1);
        bool            rel2_is_simple = IS_SIMPLE_REL(rel2);
        int                     nparts;
@@ -1368,6 +1376,18 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo 
*rel1, RelOptInfo *rel2,
 
        nparts = joinrel->nparts;
 
+       if (rel1_is_simple)
+       {
+               RangeTblEntry *rte = planner_rt_fetch(rel1->relid, root);
+
+               baserel1 = table_open(rte->relid, NoLock);
+       }
+       if (rel2_is_simple)
+       {
+               RangeTblEntry *rte = planner_rt_fetch(rel2->relid, root);
+
+               baserel2 = table_open(rte->relid, NoLock);
+       }
        /*
         * Create child-join relations for this partitioned join, if those don't
         * exist. Add paths to child-joins for a pair of child relations
@@ -1384,6 +1404,13 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo 
*rel1, RelOptInfo *rel2,
                AppendRelInfo **appinfos;
                int                     nappinfos;
 
+               if (rel1_is_simple && child_rel1 == NULL)
+                       child_rel1 = build_dummy_partition_rel(root, rel1, 
baserel1,
+                                                                               
                   cnt_parts);
+               if (rel2_is_simple && child_rel2 == NULL)
+                       child_rel2 = build_dummy_partition_rel(root, rel2, 
baserel2,
+                                                                               
                   cnt_parts);
+
                /*
                 * If a child table has consider_partitionwise_join=false, it 
means
                 * that it's a dummy relation for which we skipped setting up 
tlist
@@ -1444,6 +1471,11 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo 
*rel1, RelOptInfo *rel2,
                                                                        
child_joinrel, child_sjinfo,
                                                                        
child_restrictlist);
        }
+
+       if (baserel1)
+               table_close(baserel1, NoLock);
+       if (baserel2)
+               table_close(baserel2, NoLock);
 }
 
 /*
@@ -1462,8 +1494,14 @@ update_child_rel_info(PlannerInfo *root,
                                                           (Node *) 
rel->reltarget->exprs,
                                                           1, &appinfo);
 
-       /* Make child entries in the EquivalenceClass as well */
-       if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
+       /*
+        * Make child entries in the EquivalenceClass as well.  If the childrel
+        * appears to be a dummy one (one built by build_dummy_partition_rel()),
+        * no need to make any new entries, because anything that'd need those
+        * can instead use the parent's (rel).
+        */
+       if (childrel->relid != rel->relid &&
+               (rel->has_eclass_joins || has_useful_pathkeys(root, rel)))
                add_child_rel_equivalences(root, appinfo, rel, childrel);
        childrel->has_eclass_joins = rel->has_eclass_joins;
 }
@@ -1674,3 +1712,53 @@ match_expr_to_partition_keys(Expr *expr, RelOptInfo 
*rel, bool strict_op)
 
        return -1;
 }
+
+/*
+ * build_dummy_partition_rel
+ *             Build a RelOptInfo and AppendRelInfo for a pruned partition
+ *
+ * This does not result in opening the relation or a range table entry being
+ * created.  Also, the RelOptInfo thus created is not stored anywhere else
+ * beside the parent's part_rels array.
+ *
+ * The only reason this exists is because partition-wise join, in some cases,
+ * needs a RelOptInfo to represent an empty relation that's on the nullable
+ * side of an outer join, so that a Path representing the outer join can be
+ * created.
+ */
+static RelOptInfo *
+build_dummy_partition_rel(PlannerInfo *root, RelOptInfo *parent,
+                                                 Relation parentrel, int 
partidx)
+{
+       RelOptInfo *rel;
+
+       Assert(parent->part_rels[partidx] == NULL);
+
+       /* Create minimally valid-looking RelOptInfo with parent's relid. */
+       rel = makeNode(RelOptInfo);
+       rel->reloptkind = RELOPT_OTHER_MEMBER_REL;
+       rel->relid = parent->relid;
+       rel->relids = bms_copy(parent->relids);
+       if (parent->top_parent_relids)
+               rel->top_parent_relids = parent->top_parent_relids;
+       else
+               rel->top_parent_relids = bms_copy(parent->relids);
+       rel->reltarget = copy_pathtarget(parent->reltarget);
+       parent->part_rels[partidx] = rel;
+       mark_dummy_rel(rel);
+
+       /*
+        * Now we'll need a (no-op) AppendRelInfo for parent, because we're
+        * setting the dummy partition's relid to be same as the parent's.
+        */
+       if (root->append_rel_array[parent->relid] == NULL)
+       {
+               AppendRelInfo *appinfo = make_append_rel_info(parentrel, 
parentrel,
+                                                                               
                          parent->relid,
+                                                                               
                          parent->relid);
+
+               root->append_rel_array[parent->relid] = appinfo;
+       }
+
+       return rel;
+}
diff --git a/src/backend/optimizer/plan/initsplan.c 
b/src/backend/optimizer/plan/initsplan.c
index 2afc3f1dfe..54fc4dda97 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -20,6 +20,7 @@
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
+#include "optimizer/inherit.h"
 #include "optimizer/joininfo.h"
 #include "optimizer/optimizer.h"
 #include "optimizer/pathnode.h"
@@ -30,6 +31,7 @@
 #include "optimizer/prep.h"
 #include "optimizer/restrictinfo.h"
 #include "parser/analyze.h"
+#include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 #include "utils/lsyscache.h"
 
@@ -97,10 +99,11 @@ static void check_hashjoinable(RestrictInfo *restrictinfo);
  * jtnode.  Internally, the function recurses through the jointree.
  *
  * At the end of this process, there should be one baserel RelOptInfo for
- * every non-join RTE that is used in the query.  Therefore, this routine
- * is the only place that should call build_simple_rel with reloptkind
- * RELOPT_BASEREL.  (Note: build_simple_rel recurses internally to build
- * "other rel" RelOptInfos for the members of any appendrels we find here.)
+ * every non-join RTE that is specified in the query.  Therefore, this
+ * routine is the only place that should call build_simple_rel with
+ * reloptkind RELOPT_BASEREL.  (Note:  "other rel" RelOptInfos for the
+ * members of any appendrels we find here are added built later when
+ * query_planner calls add_other_rels_to_query().)
  */
 void
 add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
@@ -133,6 +136,48 @@ add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
                         (int) nodeTag(jtnode));
 }
 
+/*
+ * add_other_rels_to_query
+ *
+ *       Scan the query's jointree and for each base rels that is an appendrel,
+ *       create otherrel RelOptInfos of its children
+ *
+ * At the end of this process, there should be RelOptInfos for all relations
+ * that will be scanned by the query.
+ */
+void
+add_other_rels_to_query(PlannerInfo *root, Node *jtnode)
+{
+       if (jtnode == NULL)
+               return;
+       if (IsA(jtnode, RangeTblRef))
+       {
+               int                     varno = ((RangeTblRef *) 
jtnode)->rtindex;
+               RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
+
+               if (rte->inh)
+                       (void) add_appendrel_other_rels(root, rte, varno);
+       }
+       else if (IsA(jtnode, FromExpr))
+       {
+               FromExpr   *f = (FromExpr *) jtnode;
+               ListCell   *l;
+
+               foreach(l, f->fromlist)
+                       add_other_rels_to_query(root, lfirst(l));
+       }
+       else if (IsA(jtnode, JoinExpr))
+       {
+               JoinExpr   *j = (JoinExpr *) jtnode;
+
+               add_other_rels_to_query(root, j->larg);
+               add_other_rels_to_query(root, j->rarg);
+       }
+       else
+               elog(ERROR, "unrecognized node type: %d",
+                        (int) nodeTag(jtnode));
+}
+
 
 /*****************************************************************************
  *
diff --git a/src/backend/optimizer/plan/planmain.c 
b/src/backend/optimizer/plan/planmain.c
index 3cedd01c98..03c81772a3 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -159,10 +159,8 @@ query_planner(PlannerInfo *root, List *tlist,
        setup_append_rel_array(root);
 
        /*
-        * Construct RelOptInfo nodes for all base relations in query, and
-        * indirectly for all appendrel member relations ("other rels").  This
-        * will give us a RelOptInfo for every "simple" (non-join) rel involved 
in
-        * the query.
+        * Construct RelOptInfo nodes for all base relations directly mentioned
+        * in query, but not any appendrel member relations ("other rels") yet.
         *
         * Note: the reason we find the rels by searching the jointree and
         * appendrel list, rather than just scanning the rangetable, is that the
@@ -204,6 +202,15 @@ query_planner(PlannerInfo *root, List *tlist,
        generate_base_implied_equalities(root);
 
        /*
+        * Now that we have restrict clauses figured out and assigned to proper
+        * base rels, we can proceed to add otherrels, that is, UNION ALL child
+        * tables, inheritance child tables.  Having restrict clauses ready 
helps
+        * to exclude any children that wouldn't be necessary to scan, based on
+        * constraint exclusion and partition pruning.
+        */
+       add_other_rels_to_query(root, (Node *) root->parse->jointree);
+
+       /*
         * We have completed merging equivalence sets, so it's now possible to
         * generate pathkeys in canonical form; so compute query_pathkeys and
         * other pathkeys fields in PlannerInfo.
diff --git a/src/backend/optimizer/plan/planner.c 
b/src/backend/optimizer/plan/planner.c
index bc81535905..ddc4d27f67 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -25,6 +25,7 @@
 #include "access/table.h"
 #include "access/xact.h"
 #include "catalog/pg_constraint.h"
+#include "catalog/pg_inherits.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "executor/executor.h"
@@ -641,6 +642,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                root->wt_param_id = -1;
        root->non_recursive_path = NULL;
        root->partColsUpdated = false;
+       root->contains_inherit_children = false;
 
        /*
         * If there is a WITH list, process each WITH query and either convert 
it
@@ -714,27 +716,24 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                }
                if (rte->lateral)
                        root->hasLateralRTEs = true;
+
+               /*
+                * While at it, also update the inh status.  If the relation 
doesn't
+                * or can't have any children, there is no point in letting inh 
be set
+                * to true.  Note that we do this before processing rowmarks, 
so that
+                * the correct information for setting isParent field of 
PlanRowMarks.
+                */
+               if (rte->rtekind == RTE_RELATION)
+                       rte->inh = rte->inh && has_subclass(rte->relid);
        }
 
        /*
         * Preprocess RowMark information.  We need to do this after subquery
-        * pullup (so that all non-inherited RTEs are present) and before
-        * inheritance expansion (so that the info is available for
-        * expand_inherited_tables to examine and modify).
+        * pullup (so that all non-inherited RTEs are present).
         */
        preprocess_rowmarks(root);
 
        /*
-        * Expand any rangetable entries that are inheritance sets into "append
-        * relations".  This can add entries to the rangetable, but they must be
-        * plain RTE_RELATION entries, so it's OK (and marginally more 
efficient)
-        * to do it after checking for joins and other special RTEs.  We must do
-        * this after pulling up subqueries, else we'd fail to handle inherited
-        * tables in subqueries.
-        */
-       expand_inherited_tables(root);
-
-       /*
         * Set hasHavingQual to remember if HAVING clause is present.  Needed
         * because preprocess_expression will reduce a constant-true condition 
to
         * an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
@@ -1207,13 +1206,44 @@ inheritance_planner(PlannerInfo *root)
        Index           rti;
        RangeTblEntry *parent_rte;
        PlannerInfo *parent_root;
-       Query      *parent_parse;
        Bitmapset  *parent_relids = bms_make_singleton(top_parentRTindex);
        PlannerInfo **parent_roots = NULL;
+       List       *orig_append_rel_list = list_copy(root->append_rel_list);
+       List       *orig_row_marks = list_copy(root->rowMarks);
+       List       *orig_rtable = list_copy(root->parse->rtable);
+       List       *rtable_with_target;
+       List       *source_appinfos = NIL;
+       List       *source_child_rowmarks = NIL;
+       List       *source_child_rtes = NIL;
 
        Assert(parse->commandType != CMD_INSERT);
 
        /*
+        * Add child target relations.  Note that this only adds the children of
+        * the query's target relation and no other.  Especially, children of 
any
+        * source relations are added when the loop below calls grouping_planner
+        * on the *1st* child target relation.
+        */
+       expand_inherited_target_rtentry(root);
+       parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
+
+       /*
+        * If parent no longer has any children, then treat this as an update of
+        * a single table.
+        */
+       if (!parent_rte->inh)
+       {
+               grouping_planner(root, false, 0.0 /* retrieve all tuples */);
+               return;
+       }
+
+       /*
+        * This one also contains the child target relations, but no other
+        * child relations.
+        */
+       rtable_with_target = list_copy(root->parse->rtable);
+
+       /*
         * We generate a modified instance of the original Query for each target
         * relation, plan that, and put all the plans into a list that will be
         * controlled by a single ModifyTable node.  All the instances share the
@@ -1229,10 +1259,13 @@ inheritance_planner(PlannerInfo *root)
         * management of the rowMarks list.
         *
         * To begin with, generate a bitmapset of the relids of the subquery 
RTEs.
+        * We use orig_rtable, not rtable_with_target (parse->rtable), because 
we
+        * wouldn't need to consider any newly added RTEs as they all must be
+        * RTE_RELATION entries.
         */
        subqueryRTindexes = NULL;
        rti = 1;
-       foreach(lc, parse->rtable)
+       foreach(lc, orig_rtable)
        {
                RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
 
@@ -1245,26 +1278,24 @@ inheritance_planner(PlannerInfo *root)
         * Next, we want to identify which AppendRelInfo items contain 
references
         * to any of the aforesaid subquery RTEs.  These items will need to be
         * copied and modified to adjust their subquery references; whereas the
-        * other ones need not be touched.  It's worth being tense over this
-        * because we can usually avoid processing most of the AppendRelInfo
-        * items, thereby saving O(N^2) space and time when the target is a 
large
-        * inheritance tree.  We can identify AppendRelInfo items by their
-        * child_relid, since that should be unique within the list.
+        * other ones need not be touched.  We can assume that all (if any)
+        * entries in orig_append_rel_list contain references to subquery RTEs,
+        * because they correspond to flattneed UNION ALL subqueries.  
Especially,
+        * we don't need to bother with those added when adding the child target
+        * relations.  We can identify AppendRelInfo items by their child_relid,
+        * since that should be unique within the list.
         */
        modifiableARIindexes = NULL;
-       if (subqueryRTindexes != NULL)
+       foreach(lc, orig_append_rel_list)
        {
-               foreach(lc, root->append_rel_list)
-               {
-                       AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
+               AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
 
-                       if (bms_is_member(appinfo->parent_relid, 
subqueryRTindexes) ||
-                               bms_is_member(appinfo->child_relid, 
subqueryRTindexes) ||
-                               bms_overlap(pull_varnos((Node *) 
appinfo->translated_vars),
-                                                       subqueryRTindexes))
-                               modifiableARIindexes = 
bms_add_member(modifiableARIindexes,
-                                                                               
                          appinfo->child_relid);
-               }
+               Assert(bms_is_member(appinfo->parent_relid, subqueryRTindexes) 
||
+                          bms_is_member(appinfo->child_relid, 
subqueryRTindexes) ||
+                          bms_overlap(pull_varnos((Node *) 
appinfo->translated_vars),
+                                                  subqueryRTindexes));
+               modifiableARIindexes = bms_add_member(modifiableARIindexes,
+                                                                               
          appinfo->child_relid);
        }
 
        /*
@@ -1274,7 +1305,6 @@ inheritance_planner(PlannerInfo *root)
         * not appear anywhere else in the plan, so the confusion explained 
below
         * for non-partitioning inheritance cases is not possible.
         */
-       parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
        if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
        {
                nominalRelation = top_parentRTindex;
@@ -1316,7 +1346,6 @@ inheritance_planner(PlannerInfo *root)
                 */
                parent_root = parent_roots[appinfo->parent_relid];
                Assert(parent_root != NULL);
-               parent_parse = parent_root->parse;
 
                /*
                 * We need a working copy of the PlannerInfo so that we can 
control
@@ -1326,6 +1355,52 @@ inheritance_planner(PlannerInfo *root)
                memcpy(subroot, parent_root, sizeof(PlannerInfo));
 
                /*
+                * Per the above comment, we'll be changing only the 
AppendRelInfos
+                * that are contained in orig_append_rel_list, so only copy 
those.
+                */
+               subroot->append_rel_list = copyObject(orig_append_rel_list);
+
+               /*
+                * Likewise, for PlanRowMarks.  (Fortunately, the executor 
doesn't
+                * need to see the modified copies --- we can just pass it the
+                * original rowMarks list.)
+                */
+               subroot->rowMarks = copyObject(orig_row_marks);
+
+               /*
+                * No need to copy of the RTEs themselves, but do copy the List
+                * structure.
+                */
+               subroot->parse->rtable = list_copy(rtable_with_target);
+
+               /*
+                * If this isn't the first child query, then we can use the 
child
+                * objects for source child relations created during the 
planning of
+                * 1st child query.  IOW, this planning run doesn't need to 
create the
+                * child objects again, indicated by setting 
contains_inherit_children
+                * sub-PlannerInfo.
+                */
+               if (source_appinfos)
+               {
+                       subroot->append_rel_list = 
list_concat(subroot->append_rel_list,
+                                                                               
                   source_appinfos);
+                       /*
+                        * XXX Assert(source_child_rowmarks != NIL);
+                        */
+                       subroot->rowMarks = list_concat(subroot->rowMarks,
+                                                                               
        source_child_rowmarks);
+                       Assert(source_child_rtes != NIL);
+                       subroot->parse->rtable = 
list_concat(subroot->parse->rtable,
+                                                                               
                 source_child_rtes);
+
+                       /*
+                        * We have the children, so no need to add them again 
during this
+                        * planning cycle.
+                        */
+                       subroot->contains_inherit_children = true;
+               }
+
+               /*
                 * Generate modified query with this rel as target.  We first 
apply
                 * adjust_appendrel_attrs, which copies the Query and changes
                 * references to the parent RTE to refer to the current child 
RTE,
@@ -1333,7 +1408,7 @@ inheritance_planner(PlannerInfo *root)
                 */
                subroot->parse = (Query *)
                        adjust_appendrel_attrs(parent_root,
-                                                                  (Node *) 
parent_parse,
+                                                                  (Node *) 
subroot->parse,
                                                                   1, &appinfo);
 
                /*
@@ -1399,41 +1474,6 @@ inheritance_planner(PlannerInfo *root)
                        nominalRelation = appinfo->child_relid;
 
                /*
-                * The rowMarks list might contain references to subquery RTEs, 
so
-                * make a copy that we can apply ChangeVarNodes to.  
(Fortunately, the
-                * executor doesn't need to see the modified copies --- we can 
just
-                * pass it the original rowMarks list.)
-                */
-               subroot->rowMarks = copyObject(parent_root->rowMarks);
-
-               /*
-                * The append_rel_list likewise might contain references to 
subquery
-                * RTEs (if any subqueries were flattenable UNION ALLs).  So 
prepare
-                * to apply ChangeVarNodes to that, too.  As explained above, 
we only
-                * want to copy items that actually contain such references; 
the rest
-                * can just get linked into the subroot's append_rel_list.
-                *
-                * If we know there are no such references, we can just use the 
outer
-                * append_rel_list unmodified.
-                */
-               if (modifiableARIindexes != NULL)
-               {
-                       ListCell   *lc2;
-
-                       subroot->append_rel_list = NIL;
-                       foreach(lc2, parent_root->append_rel_list)
-                       {
-                               AppendRelInfo *appinfo2 = 
lfirst_node(AppendRelInfo, lc2);
-
-                               if (bms_is_member(appinfo2->child_relid, 
modifiableARIindexes))
-                                       appinfo2 = copyObject(appinfo2);
-
-                               subroot->append_rel_list = 
lappend(subroot->append_rel_list,
-                                                                               
                   appinfo2);
-                       }
-               }
-
-               /*
                 * Add placeholders to the child Query's rangetable list to 
fill the
                 * RT indexes already reserved for subqueries in previous 
children.
                 * These won't be referenced, so there's no need to make them 
very
@@ -1446,23 +1486,23 @@ inheritance_planner(PlannerInfo *root)
                /*
                 * If this isn't the first child Query, generate duplicates of 
all
                 * subquery RTEs, and adjust Var numbering to reference the
-                * duplicates. To simplify the loop logic, we scan the original 
rtable
-                * not the copy just made by adjust_appendrel_attrs; that 
should be OK
-                * since subquery RTEs couldn't contain any references to the 
target
-                * rel.
+                * duplicates.  Note that we scan the original rtable before any
+                * child target relations were added, which is OK, because no 
other
+                * RTEs would contain references to subquery rels being 
modified.
                 */
                if (final_rtable != NIL && subqueryRTindexes != NULL)
                {
                        ListCell   *lr;
 
                        rti = 1;
-                       foreach(lr, parent_parse->rtable)
+                       foreach(lr, orig_rtable)
                        {
                                RangeTblEntry *rte = lfirst_node(RangeTblEntry, 
lr);
 
                                if (bms_is_member(rti, subqueryRTindexes))
                                {
                                        Index           newrti;
+                                       ListCell   *lc2;
 
                                        /*
                                         * The RTE can't contain any references 
to its own RT
@@ -1473,19 +1513,20 @@ inheritance_planner(PlannerInfo *root)
                                        newrti = 
list_length(subroot->parse->rtable) + 1;
                                        ChangeVarNodes((Node *) subroot->parse, 
rti, newrti, 0);
                                        ChangeVarNodes((Node *) 
subroot->rowMarks, rti, newrti, 0);
-                                       /* Skip processing unchanging parts of 
append_rel_list */
-                                       if (modifiableARIindexes != NULL)
+                                       /*
+                                        * UNION ALL related appinfos are the 
beginning of the
+                                        * list, only change those.
+                                        */
+                                       foreach(lc2, subroot->append_rel_list)
                                        {
-                                               ListCell   *lc2;
+                                               AppendRelInfo *appinfo2 = 
lfirst_node(AppendRelInfo,
+                                                                               
                                         lc2);
 
-                                               foreach(lc2, 
subroot->append_rel_list)
-                                               {
-                                                       AppendRelInfo *appinfo2 
= lfirst_node(AppendRelInfo, lc2);
-
-                                                       if 
(bms_is_member(appinfo2->child_relid,
-                                                                               
          modifiableARIindexes))
-                                                               
ChangeVarNodes((Node *) appinfo2, rti, newrti, 0);
-                                               }
+                                               if 
(bms_is_member(appinfo2->child_relid,
+                                                                               
  modifiableARIindexes))
+                                                       ChangeVarNodes((Node *) 
appinfo2, rti, newrti, 0);
+                                               else
+                                                       break;
                                        }
                                        rte = copyObject(rte);
                                        ChangeVarNodes((Node *) 
rte->securityQuals, rti, newrti, 0);
@@ -1514,6 +1555,54 @@ inheritance_planner(PlannerInfo *root)
                subpath = sub_final_rel->cheapest_total_path;
 
                /*
+                * If we finished planning our first child query, copy the 
source
+                * child objects that were added during its planning.
+                */
+               if (source_appinfos == NIL && subroot->append_rel_list)
+               {
+                       int             num_skip_appinfos = 
list_length(orig_append_rel_list);
+                       int             num_skip_rowmarks = 
list_length(orig_row_marks);
+                       int             num_skip_rtes = 
list_length(rtable_with_target);
+                       ListCell *lc2;
+
+                       source_appinfos = 
list_copy_tail(subroot->append_rel_list,
+                                                                               
         num_skip_appinfos);
+                       Assert(source_child_rowmarks == NIL);
+                       source_child_rowmarks = 
list_copy_tail(subroot->rowMarks,
+                                                                               
                   num_skip_rowmarks);
+                       Assert(source_child_rtes == NIL);
+                       source_child_rtes = 
list_copy_tail(subroot->parse->rtable,
+                                                                               
           num_skip_rtes);
+
+                       /*
+                        * Original parent PlanRowMark is modified when adding 
the
+                        * child PlanRowMarks.  Copy those changes so that the 
planning
+                        * of subsequent child queries works correctly.  That is
+                        * necessary, because we won't be adding child objects 
again,
+                        * so there won't be an opportunity to modify the parent
+                        * PlanRowMark as desired.
+                        *
+                        * All the original parent row marks are the beginning 
of
+                        * subroot->rowMarks, skip the rest.
+                        */
+                       foreach(lc2, orig_row_marks)
+                       {
+                               PlanRowMark *oldrc = lfirst_node(PlanRowMark, 
lc2);
+                               ListCell *lc3;
+
+                               foreach(lc3, subroot->rowMarks)
+                               {
+                                       PlanRowMark *newrc = 
lfirst_node(PlanRowMark, lc3);
+
+                                       if (oldrc->rti == newrc->rti)
+                                               oldrc->allMarkTypes = 
newrc->allMarkTypes;
+                                       else
+                                               break;
+                               }
+                       }
+               }
+
+               /*
                 * If this child rel was excluded by constraint exclusion, 
exclude it
                 * from the result plan.
                 */
@@ -2618,7 +2707,7 @@ preprocess_rowmarks(PlannerInfo *root)
                newrc->allMarkTypes = (1 << newrc->markType);
                newrc->strength = rc->strength;
                newrc->waitPolicy = rc->waitPolicy;
-               newrc->isParent = false;
+               newrc->isParent = rte->inh;
 
                prowmarks = lappend(prowmarks, newrc);
        }
@@ -2643,7 +2732,7 @@ preprocess_rowmarks(PlannerInfo *root)
                newrc->allMarkTypes = (1 << newrc->markType);
                newrc->strength = LCS_NONE;
                newrc->waitPolicy = LockWaitBlock;      /* doesn't matter */
-               newrc->isParent = false;
+               newrc->isParent = rte->rtekind == RTE_RELATION ? rte->inh : 
false;
 
                prowmarks = lappend(prowmarks, newrc);
        }
@@ -7046,6 +7135,10 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
                        int                     nappinfos;
                        List       *child_scanjoin_targets = NIL;
 
+                       /* Skip processing pruned partitions. */
+                       if (child_rel == NULL)
+                               continue;
+
                        /* Translate scan/join targets for this child. */
                        appinfos = find_appinfos_by_relids(root, 
child_rel->relids,
                                                                                
           &nappinfos);
@@ -7147,6 +7240,10 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
                RelOptInfo *child_grouped_rel;
                RelOptInfo *child_partially_grouped_rel;
 
+               /* Skip processing pruned partitions. */
+               if (child_input_rel == NULL)
+                       continue;
+
                /* Input child rel must have a path */
                Assert(child_input_rel->pathlist != NIL);
 
diff --git a/src/backend/optimizer/plan/setrefs.c 
b/src/backend/optimizer/plan/setrefs.c
index 0213a37670..154ccda432 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -326,6 +326,12 @@ add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
                                                                                
                          UPPERREL_FINAL, NULL)))
                                        add_rtes_to_flat_rtable(rel->subroot, 
true);
                        }
+                       /*
+                        * A NULL rel also means an unplanned subquery rte, so 
apply
+                        * flatten_unplanned_rtes.
+                        */
+                       else
+                               flatten_unplanned_rtes(glob, rte);
                }
                rti++;
        }
diff --git a/src/backend/optimizer/prep/preptlist.c 
b/src/backend/optimizer/prep/preptlist.c
index 5392d1a561..87565d2be3 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -126,61 +126,23 @@ preprocess_targetlist(PlannerInfo *root)
        foreach(lc, root->rowMarks)
        {
                PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
-               Var                *var;
-               char            resname[32];
-               TargetEntry *tle;
+               List       *junk_tles;
 
                /* child rels use the same junk attrs as their parents */
                if (rc->rti != rc->prti)
                        continue;
 
-               if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
-               {
-                       /* Need to fetch TID */
-                       var = makeVar(rc->rti,
-                                                 
SelfItemPointerAttributeNumber,
-                                                 TIDOID,
-                                                 -1,
-                                                 InvalidOid,
-                                                 0);
-                       snprintf(resname, sizeof(resname), "ctid%u", 
rc->rowmarkId);
-                       tle = makeTargetEntry((Expr *) var,
-                                                                 
list_length(tlist) + 1,
-                                                                 
pstrdup(resname),
-                                                                 true);
-                       tlist = lappend(tlist, tle);
-               }
-               if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
-               {
-                       /* Need the whole row as a junk var */
-                       var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
-                                                                 rc->rti,
-                                                                 0,
-                                                                 false);
-                       snprintf(resname, sizeof(resname), "wholerow%u", 
rc->rowmarkId);
-                       tle = makeTargetEntry((Expr *) var,
-                                                                 
list_length(tlist) + 1,
-                                                                 
pstrdup(resname),
-                                                                 true);
-                       tlist = lappend(tlist, tle);
-               }
+               /*
+                * For inheritance parent row marks, we defer adding junk 
columns
+                * until we've added child row marks, because some children 
might
+                * require different row mark types which will change the 
parent row
+                * mark's allMarkTypes fields.
+                */
+               if (rc->isParent && !root->contains_inherit_children)
+                       continue;
 
-               /* If parent of inheritance tree, always fetch the tableoid 
too. */
-               if (rc->isParent)
-               {
-                       var = makeVar(rc->rti,
-                                                 TableOidAttributeNumber,
-                                                 OIDOID,
-                                                 -1,
-                                                 InvalidOid,
-                                                 0);
-                       snprintf(resname, sizeof(resname), "tableoid%u", 
rc->rowmarkId);
-                       tle = makeTargetEntry((Expr *) var,
-                                                                 
list_length(tlist) + 1,
-                                                                 
pstrdup(resname),
-                                                                 true);
-                       tlist = lappend(tlist, tle);
-               }
+               junk_tles = get_rowmark_junk_tles(root, tlist, rc);
+               tlist = list_concat(tlist, junk_tles);
        }
 
        /*
@@ -434,3 +396,73 @@ get_plan_rowmark(List *rowmarks, Index rtindex)
        }
        return NULL;
 }
+
+/*
+ * add_rowmark_junk_columns
+ *             Add necessary junk columns for rowmarked inheritance parent rel.
+ *
+ * These values are needed for locking of rels selected FOR UPDATE/SHARE, and
+ * to do EvalPlanQual rechecking.  See comments for PlanRowMark.
+ */
+List *
+get_rowmark_junk_tles(PlannerInfo *root, List *tlist, PlanRowMark *rc)
+{
+       List       *range_table = root->parse->rtable;
+       int                     tlist_len = list_length(tlist);
+       List       *junk_tles = NIL;
+       Var                *var;
+       char            resname[32];
+       TargetEntry *tle;
+
+       if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
+       {
+               /* Need to fetch TID */
+               var = makeVar(rc->rti,
+                                         SelfItemPointerAttributeNumber,
+                                         TIDOID,
+                                         -1,
+                                         InvalidOid,
+                                         0);
+               snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
+               tle = makeTargetEntry((Expr *) var,
+                                                         tlist_len + 1,
+                                                         pstrdup(resname),
+                                                         true);
+               junk_tles = lappend(junk_tles, tle);
+               tlist_len++;
+       }
+       if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
+       {
+               /* Need the whole row as a junk var */
+               var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
+                                                         rc->rti,
+                                                         0,
+                                                         false);
+               snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
+               tle = makeTargetEntry((Expr *) var,
+                                                         tlist_len + 1,
+                                                         pstrdup(resname),
+                                                         true);
+               junk_tles = lappend(junk_tles, tle);
+               tlist_len++;
+       }
+
+       /* For inheritance cases, always fetch the tableoid too. */
+       if (rc->isParent)
+       {
+               var = makeVar(rc->rti,
+                                         TableOidAttributeNumber,
+                                         OIDOID,
+                                         -1,
+                                         InvalidOid,
+                                         0);
+               snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
+               tle = makeTargetEntry((Expr *) var,
+                                                         tlist_len + 1,
+                                                         pstrdup(resname),
+                                                         true);
+               junk_tles = lappend(junk_tles, tle);
+       }
+
+       return junk_tles;
+}
diff --git a/src/backend/optimizer/util/inherit.c 
b/src/backend/optimizer/util/inherit.c
index a014a12060..e437709fc3 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -18,69 +18,120 @@
 #include "access/table.h"
 #include "catalog/partition.h"
 #include "catalog/pg_inherits.h"
+#include "catalog/pg_type.h"
 #include "miscadmin.h"
+#include "nodes/makefuncs.h"
 #include "optimizer/appendinfo.h"
+#include "optimizer/clauses.h"
 #include "optimizer/inherit.h"
+#include "optimizer/pathnode.h"
+#include "optimizer/paths.h"
+#include "optimizer/plancat.h"
+#include "optimizer/planmain.h"
 #include "optimizer/planner.h"
 #include "optimizer/prep.h"
+#include "optimizer/restrictinfo.h"
+#include "parser/parsetree.h"
 #include "partitioning/partdesc.h"
+#include "partitioning/partprune.h"
 #include "utils/rel.h"
 
 
-static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
-                                                Index rti);
+static void expand_regular_inherited_rtentry(PlannerInfo *root,
+                                                                RangeTblEntry 
*rte,
+                                                                Index rti, 
bool is_target);
 static void expand_partitioned_rtentry(PlannerInfo *root,
-                                                  RangeTblEntry *parentrte,
-                                                  Index parentRTindex, 
Relation parentrel,
-                                                  PlanRowMark *top_parentrc, 
LOCKMODE lockmode,
-                                                  List **appinfos);
-static void expand_single_inheritance_child(PlannerInfo *root,
-                                                               RangeTblEntry 
*parentrte,
-                                                               Index 
parentRTindex, Relation parentrel,
-                                                               PlanRowMark 
*top_parentrc, Relation childrel,
-                                                               List 
**appinfos, RangeTblEntry **childrte_p,
-                                                               Index 
*childRTindex_p);
+                                                  RangeTblEntry *parentrte, 
Index parentRTindex);
+static void expand_partitioned_target_rtentry(PlannerInfo *root,
+                                                  RangeTblEntry *parentrte, 
Index parentRTindex);
+static void add_inheritance_child_rel(PlannerInfo *root,
+                                                 RangeTblEntry *parentrte,
+                                                 Index parentRTindex, Relation 
parentrel,
+                                                 PlanRowMark *top_parentrc, 
Relation childrel,
+                                                 RangeTblEntry **childrte_p, 
Index *childRTindex_p,
+                                                 AppendRelInfo **appinfo_p);
 static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
                                        List *translated_vars);
 
 
 /*
- * expand_inherited_tables
- *             Expand each rangetable entry that represents an inheritance set
- *             into an "append relation".  At the conclusion of this process,
- *             the "inh" flag is set in all and only those RTEs that are append
- *             relation parents.
+ * expand_inherited_rtentry
+ *             This initializes RelOptInfos for inheritance child relations if 
the
+ *             passed-in relation has any
+ *
+ * Passed in relation could either be a subquery (if a UNION ALL subquery was
+ * flattened) or a table that's known to have (or once had) inheritance
+ * children.  The latter consists of both regular inheritance parents and
+ * partitioned tables.
+ *
+ * For a subquery parent, there is not much to be done here because the
+ * children's RTEs are already present in the query, so we just initialize
+ * RelOptInfos for them.  Also, the AppendRelInfos for child subqueries
+ * have already been added.
+ *
+ * For tables, we need to add the children to the range table and initialize
+ * AppendRelInfos, RelOptInfos, and PlanRowMarks (if any) for them.  For
+ * a partitioned parent, we only add the children remaining after pruning.
+ * For regular inheritance parents, we find the children using
+ * find_all_inheritors and add all of them.
+ *
+ * If it turns out that there are no children, then we set rte->inh to false
+ * to let the caller know that only the parent table needs to be scanned.  The
+ * caller can accordingly switch to a non-Append path.  For a partitioned
+ * parent, that means an empty relation because parents themselves contain no
+ * data.
+ *
+ * For the regular inheritance case, the parent also gets another RTE with
+ * inh = false to represent it as a child to be scanned as part of the
+ * inheritance set.  The original RTE is considered to represent the whole
+ * inheritance set.
  */
 void
-expand_inherited_tables(PlannerInfo *root)
+expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 {
-       Index           nrtes;
-       Index           rti;
-       ListCell   *rl;
+       /* Only inheritance parent (partitioned or not) are allowed. */
+       Assert(rte->rtekind == RTE_RELATION && rte->inh);
 
        /*
-        * expand_inherited_rtentry may add RTEs to parse->rtable. The function 
is
-        * expected to recursively handle any RTEs that it creates with 
inh=true.
-        * So just scan as far as the original end of the rtable list.
+        * subquery_planner() must have set rte->inh if the following wasn't 
true.
         */
-       nrtes = list_length(root->parse->rtable);
-       rl = list_head(root->parse->rtable);
-       for (rti = 1; rti <= nrtes; rti++)
-       {
-               RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
+       Assert(has_subclass(rte->relid));
 
-               expand_inherited_rtentry(root, rte, rti);
-               rl = lnext(rl);
-       }
+       /*
+        * The rewriter should already have obtained an appropriate lock on
+        * each relation named in the query, so we can open the parent relation
+        * without locking it.  However, for each child relation we add to the
+        * query, we must obtain an appropriate lock, because this will be the
+        * first use of those relations in the parse/rewrite/plan pipeline.
+        * Child rels should use the same lockmode as their parent.
+        */
+       Assert(rte->rellockmode != NoLock);
+
+       if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+               expand_partitioned_rtentry(root, rte, rti);
+       else
+               expand_regular_inherited_rtentry(root, rte, rti, false);
+}
+
+void
+expand_inherited_target_rtentry(PlannerInfo *root)
+{
+       Index           resultRelation = root->parse->resultRelation;
+       RangeTblEntry *rte = rt_fetch(resultRelation, root->parse->rtable);
+
+       Assert(resultRelation > 0);
+       Assert(rte->rtekind == RTE_RELATION);
+       if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+               expand_partitioned_target_rtentry(root, rte, resultRelation);
+       else
+               expand_regular_inherited_rtentry(root, rte, resultRelation, 
true);
 }
 
 /*
- * expand_inherited_rtentry
- *             Check whether a rangetable entry represents an inheritance set.
- *             If so, add entries for all the child tables to the query's
- *             rangetable, and build AppendRelInfo nodes for all the child 
tables
- *             and add them to root->append_rel_list.  If not, clear the 
entry's
- *             "inh" flag to prevent later code from looking for 
AppendRelInfos.
+ * expand_regular_inherited_rtentry
+ *             Add entries for all the child tables to the query's rangetable, 
and
+ *             build AppendRelInfo nodes for all the child tables and add them 
to
+ *             root->append_rel_list.
  *
  * Note that the original RTE is considered to represent the whole
  * inheritance set.  The first of the generated RTEs is an RTE for the same
@@ -91,269 +142,339 @@ expand_inherited_tables(PlannerInfo *root)
  * regular inheritance, a parent RTE must always have at least two associated
  * AppendRelInfos: one corresponding to the parent table as a simple member of
  * inheritance set and one or more corresponding to the actual children.
- * Since a partitioned table is not scanned, it might have only one associated
- * AppendRelInfo.
  */
 static void
-expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
+expand_regular_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
+                                                                Index rti, 
bool is_target)
 {
        Oid                     parentOID;
-       PlanRowMark *oldrc;
-       Relation        oldrelation;
-       LOCKMODE        lockmode;
+       Relation        parentrel;
+       PlanRowMark *oldrc = NULL;
+       LOCKMODE        lockmode = rte->rellockmode;
        List       *inhOIDs;
        ListCell   *l;
+       int                     num_children;
+       int                     num_children_added = 0;
+       RelOptInfo *parent = NULL;
 
-       /* Does RT entry allow inheritance? */
-       if (!rte->inh)
-               return;
-       /* Ignore any already-expanded UNION ALL nodes */
-       if (rte->rtekind != RTE_RELATION)
-       {
-               Assert(rte->rtekind == RTE_SUBQUERY);
-               return;
-       }
-       /* Fast path for common case of childless table */
+       Assert(rte->rtekind == RTE_RELATION);
+       Assert(lockmode != NoLock);
        parentOID = rte->relid;
-       if (!has_subclass(parentOID))
+
+       /* Scan for all members of inheritance set, acquire needed locks */
+       inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+
+       /*
+        * Check that there's at least one descendant, else treat as no-child
+        * case.  This could happen despite has_subclass() check performed by
+        * subquery_planner, if table once had a child but no longer does.
+        */
+       num_children = list_length(inhOIDs);
+       if (num_children < 2)
        {
                /* Clear flag before returning */
                rte->inh = false;
                return;
        }
 
-       /*
-        * The rewriter should already have obtained an appropriate lock on each
-        * relation named in the query, so we can open the parent relation 
without
-        * locking it.  However, for each child relation we add to the query, we
-        * must obtain an appropriate lock, because this will be the first use 
of
-        * those relations in the parse/rewrite/plan pipeline.  Child rels 
should
-        * use the same lockmode as their parent.
-        */
-       oldrelation = table_open(parentOID, NoLock);
-       lockmode = rte->rellockmode;
+       /* Already locked. */
+       parentrel = table_open(parentOID, NoLock);
 
        /*
-        * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
-        * PlanRowMark as isParent = true, and generate a new PlanRowMark for 
each
-        * child.
+        * For inherited update/delete, there's no RelOptInfo for parent and we
+        * won't be creating one for the children either, so the following info
+        * is unnecessary.
         */
-       oldrc = get_plan_rowmark(root->rowMarks, rti);
-       if (oldrc)
-               oldrc->isParent = true;
-
-       /* Scan the inheritance set and expand it */
-       if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+       if (!is_target)
        {
-               Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
+               /*
+                * If parent relation is selected FOR UPDATE/SHARE,
+                * preprocess_rowmarks should've set isParent = true.  We'll 
generate
+                * a new PlanRowMark for each child.
+                */
+               oldrc = get_plan_rowmark(root->rowMarks, rti);
+               Assert(oldrc == NULL || oldrc->isParent);
+
+               parent = find_base_rel(root, rti);
 
                /*
-                * If this table has partitions, recursively expand and lock 
them.
-                * While at it, also extract the partition key columns of all 
the
-                * partitioned tables.
+                * Must expand PlannerInfo arrays by num_children before we can 
add
+                * children.
                 */
-               expand_partitioned_rtentry(root, rte, rti, oldrelation, oldrc,
-                                                                  lockmode, 
&root->append_rel_list);
+               Assert(num_children > 0);
+               expand_planner_arrays(root, num_children);
        }
-       else
+
+       foreach(l, inhOIDs)
        {
-               List       *appinfos = NIL;
+               Oid                     childOID = lfirst_oid(l);
+               /* Already locked. */
+               Relation        childrel = table_open(childOID, NoLock);
                RangeTblEntry *childrte;
                Index           childRTindex;
-
-               /* Scan for all members of inheritance set, acquire needed 
locks */
-               inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+               AppendRelInfo *appinfo;
 
                /*
-                * Check that there's at least one descendant, else treat as 
no-child
-                * case.  This could happen despite above has_subclass() check, 
if the
-                * table once had a child but no longer does.
+                * It is possible that the parent table has children that are 
temp
+                * tables of other backends.  We cannot safely access such 
tables
+                * (because of buffering issues), and the best thing to do seems
+                * to be to silently ignore them.
                 */
-               if (list_length(inhOIDs) < 2)
+               if (childOID != parentOID && RELATION_IS_OTHER_TEMP(childrel))
                {
-                       /* Clear flag before returning */
-                       rte->inh = false;
-                       heap_close(oldrelation, NoLock);
-                       return;
+                       table_close(childrel, lockmode);
+                       continue;
                }
 
-               /*
-                * This table has no partitions.  Expand any plain inheritance
-                * children in the order the OIDs were returned by
-                * find_all_inheritors.
-                */
-               foreach(l, inhOIDs)
+               /* Add RTE, AppendRelInfo, PlanRowMark for the child. */
+               add_inheritance_child_rel(root, rte, rti, parentrel, oldrc,
+                                                                 childrel, 
&childrte, &childRTindex,
+                                                                 &appinfo);
+               Assert(childrte != NULL && childRTindex > 0 && appinfo != NULL);
+
+               /* Close child relations, but keep locks */
+               table_close(childrel, NoLock);
+               num_children_added++;
+
+               /* All regular inheritance children are leaf children. */
+               Assert(!childrte->inh);
+
+               /* Also create the RelOptInfo in the non-target inheritance 
case. */
+               if (parent)
                {
-                       Oid                     childOID = lfirst_oid(l);
-                       Relation        newrelation;
+                       Assert(root->simple_rte_array[childRTindex] == NULL);
+                       root->simple_rte_array[childRTindex] = childrte;
+                       Assert(root->append_rel_array[childRTindex] == NULL);
+                       root->append_rel_array[childRTindex] = appinfo;
 
-                       /* Open rel if needed; we already have required locks */
-                       if (childOID != parentOID)
-                               newrelation = table_open(childOID, NoLock);
-                       else
-                               newrelation = oldrelation;
-
-                       /*
-                        * It is possible that the parent table has children 
that are temp
-                        * tables of other backends.  We cannot safely access 
such tables
-                        * (because of buffering issues), and the best thing to 
do seems
-                        * to be to silently ignore them.
-                        */
-                       if (childOID != parentOID && 
RELATION_IS_OTHER_TEMP(newrelation))
-                       {
-                               table_close(newrelation, lockmode);
-                               continue;
-                       }
-
-                       expand_single_inheritance_child(root, rte, rti, 
oldrelation, oldrc,
-                                                                               
        newrelation,
-                                                                               
        &appinfos, &childrte,
-                                                                               
        &childRTindex);
-
-                       /* Close child relations, but keep locks */
-                       if (childOID != parentOID)
-                               table_close(newrelation, NoLock);
+                       /* Add the RelOptInfo too. */
+                       (void) build_simple_rel(root, childRTindex, parent);
                }
-
-               /*
-                * If all the children were temp tables, pretend it's a
-                * non-inheritance situation; we don't need Append node in that 
case.
-                * The duplicate RTE we added for the parent table is harmless, 
so we
-                * don't bother to get rid of it; ditto for the useless 
PlanRowMark
-                * node.
-                */
-               if (list_length(appinfos) < 2)
-                       rte->inh = false;
-               else
-                       root->append_rel_list = 
list_concat(root->append_rel_list,
-                                                                               
                appinfos);
-
        }
 
-       table_close(oldrelation, NoLock);
+       /*
+        * If all the children except the parent itself in its role as a child
+        * were temp tables of other backends or were excluded, pretend it's a
+        * non-inheritance situation; we don't need Append node in that case.  
The
+        * duplicate RTE we added for the parent table is harmless, so we don't
+        * bother to get rid of it; ditto for the useless PlanRowMark node.
+        */
+       if (num_children_added == 1)
+               rte->inh = false;
+
+       if (parent)
+       {
+               /*
+                * Add junk columns needed by the row mark if any and also add 
the
+                * relevant expressions to the root parent's reltarget.
+                */
+               if (oldrc)
+               {
+                       List   *tlist = root->processed_tlist;
+                       List   *junk_tles = get_rowmark_junk_tles(root, tlist, 
oldrc);
+
+                       build_base_rel_tlists(root, junk_tles);
+                       root->processed_tlist = 
list_concat(root->processed_tlist,
+                                                                               
                junk_tles);
+               }
+       }
+
+       table_close(parentrel, NoLock);
 }
 
 /*
  * expand_partitioned_rtentry
- *             Recursively expand an RTE for a partitioned table.
+ *             Add partitions to Query and PlannerInfo
+ *
+ * If we're expanding source inheritance, there's enought information to
+ * perform partition pruning, so only add those that survive pruning.
+ *
+ * Partitions are locked and added to the query in order in which they are
+ * found in the parent's PartitionDesc.
  */
 static void
 expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
-                                                  Index parentRTindex, 
Relation parentrel,
-                                                  PlanRowMark *top_parentrc, 
LOCKMODE lockmode,
-                                                  List **appinfos)
+                                                  Index parentRTindex)
 {
+       Relation        parentrel;
+       PartitionDesc partdesc;
+       LOCKMODE        lockmode = parentrte->rellockmode;
        int                     i;
-       RangeTblEntry *childrte;
-       Index           childRTindex;
-       PartitionDesc partdesc = RelationGetPartitionDesc(parentrel);
+       RelOptInfo *parent = find_base_rel(root, parentRTindex);
+       PlanRowMark *oldrc = NULL;
+       Bitmapset  *partindexes;
 
-       check_stack_depth();
+       /* Already locked. */
+       parentrel = table_open(parentrte->relid, NoLock);
+       partdesc = RelationGetPartitionDesc(parentrel);
 
-       /* A partitioned table should always have a partition descriptor. */
-       Assert(partdesc);
+       /* Perform pruning. */
+       partindexes = prune_append_rel_partitions(parent);
 
-       Assert(parentrte->inh);
+       /* Must expand PlannerInfo arrays before we can add children. */
+       if (bms_num_members(partindexes) > 0)
+               expand_planner_arrays(root, bms_num_members(partindexes));
 
        /*
-        * Note down whether any partition key cols are being updated. Though 
it's
-        * the root partitioned table's updatedCols we are interested in, we
-        * instead use parentrte to get the updatedCols. This is convenient
-        * because parentrte already has the root partrel's updatedCols 
translated
-        * to match the attribute ordering of parentrel.
+        * For partitioned tables, we also store the partition RelOptInfo
+        * pointers in the parent's RelOptInfo.
         */
-       if (!root->partColsUpdated)
-               root->partColsUpdated =
-                       has_partition_attrs(parentrel, parentrte->updatedCols, 
NULL);
+       parent->part_rels = (RelOptInfo **) palloc0(sizeof(RelOptInfo *) *
+                                                                               
                parent->nparts);
 
-       /* First expand the partitioned table itself. */
-       expand_single_inheritance_child(root, parentrte, parentRTindex, 
parentrel,
-                                                                       
top_parentrc, parentrel,
-                                                                       
appinfos, &childrte, &childRTindex);
-
-       /*
-        * If the partitioned table has no partitions, treat this as the
-        * non-inheritance case.
-        */
-       if (partdesc->nparts == 0)
+       oldrc = get_plan_rowmark(root->rowMarks, parentRTindex);
+       Assert(oldrc == NULL || oldrc->isParent);
+       i = -1;
+       while ((i = bms_next_member(partindexes, i)) >= 0)
        {
-               parentrte->inh = false;
-               return;
+               Oid                     childOID = partdesc->oids[i];
+               /* Open rel, acquiring required locks */
+               Relation        childrel = table_open(childOID, lockmode);
+               RangeTblEntry *childrte = NULL;
+               Index           childRTindex = 0;
+               AppendRelInfo *appinfo = NULL;
+
+               /*
+                * A partitioned child table with 0 children is a dummy rel, so
+                * don't bother creating any planner objects for it.
+                */
+               if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+                       RelationGetPartitionDesc(childrel)->nparts == 0)
+               {
+                       table_close(childrel, NoLock);
+                       continue;
+               }
+
+               add_inheritance_child_rel(root, parentrte, parentRTindex,
+                                                                 parentrel, 
oldrc, childrel, &childrte,
+                                                                 
&childRTindex, &appinfo);
+               Assert(childrte != NULL && childRTindex > 0 && appinfo != NULL);
+               table_close(childrel, NoLock);
+
+               Assert(root->simple_rte_array[childRTindex] == NULL);
+               root->simple_rte_array[childRTindex] = childrte;
+               Assert(root->append_rel_array[childRTindex] == NULL);
+               root->append_rel_array[childRTindex] = appinfo;
+
+               /* Add the RelOptInfo too. */
+               parent->part_rels[i] = build_simple_rel(root, childRTindex, 
parent);
+
+               /* If the child is partitioned itself, expand it too. */
+               if (childrte->inh)
+               {
+                       Assert(parent->part_rels[i]->part_scheme != NULL);
+                       expand_partitioned_rtentry(root, childrte, 
childRTindex);
+               }
        }
 
+       /*
+        * Add junk columns needed by the row mark if any and also add the
+        * relevant expressions to the root parent's reltarget.
+        */
+       if (oldrc && oldrc->rti == oldrc->prti)
+       {
+               List   *tlist = root->processed_tlist;
+               List   *junk_tles = get_rowmark_junk_tles(root, tlist, oldrc);
+
+               build_base_rel_tlists(root, junk_tles);
+               root->processed_tlist = list_concat(root->processed_tlist, 
junk_tles);
+       }
+
+       table_close(parentrel, NoLock);
+}
+
+static void
+expand_partitioned_target_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
+                                                                 Index 
parentRTindex)
+{
+       Relation        parentrel;
+       PartitionDesc partdesc;
+       LOCKMODE        lockmode = parentrte->rellockmode;
+       int                     i;
+
+       /* Already locked. */
+       parentrel = table_open(parentrte->relid, NoLock);
+       partdesc = RelationGetPartitionDesc(parentrel);
+
+       /*
+        * For inherited update/delete query, just add RTEs and AppendRelInfos
+        * for *all* partitions.
+        */
        for (i = 0; i < partdesc->nparts; i++)
        {
                Oid                     childOID = partdesc->oids[i];
-               Relation        childrel;
-
                /* Open rel, acquiring required locks */
-               childrel = table_open(childOID, lockmode);
+               Relation        childrel = table_open(childOID, lockmode);
+               RangeTblEntry *childrte = NULL;
+               Index           childRTindex = 0;
+               AppendRelInfo *appinfo = NULL;
 
                /*
-                * Temporary partitions belonging to other sessions should have 
been
-                * disallowed at definition, but for paranoia's sake, let's 
double
-                * check.
+                * A partitioned child table with 0 children is a dummy rel, so
+                * don't bother creating any planner objects for it.
                 */
-               if (RELATION_IS_OTHER_TEMP(childrel))
-                       elog(ERROR, "temporary relation from another session 
found as partition");
+               if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+                       RelationGetPartitionDesc(childrel)->nparts == 0)
+               {
+                       table_close(childrel, NoLock);
+                       continue;
+               }
 
-               expand_single_inheritance_child(root, parentrte, parentRTindex,
-                                                                               
parentrel, top_parentrc, childrel,
-                                                                               
appinfos, &childrte, &childRTindex);
-
-               /* If this child is itself partitioned, recurse */
-               if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-                       expand_partitioned_rtentry(root, childrte, childRTindex,
-                                                                          
childrel, top_parentrc, lockmode,
-                                                                          
appinfos);
-
-               /* Close child relation, but keep locks */
+               /* Adds RTE and AppendRelInfo for the child. */
+               add_inheritance_child_rel(root, parentrte, parentRTindex,
+                                                                 parentrel, 
NULL, childrel,
+                                                                 &childrte, 
&childRTindex, &appinfo);
+               Assert(childrte != NULL && childRTindex > 0 && appinfo != NULL);
                table_close(childrel, NoLock);
+
+               /* Handle sub-partitioned child recursively. */
+               if (childrte->inh)
+                       expand_partitioned_target_rtentry(root, childrte, 
childRTindex);
        }
+
+       /*
+        * Note whether partition key columns are updated; due to recursion,
+        * also considers sub-partitioned children's partition key being
+        * updated.
+        */
+       root->partColsUpdated |= has_partition_attrs(parentrel,
+                                                                               
                 parentrte->updatedCols,
+                                                                               
                 NULL);
+
+       table_close(parentrel, NoLock);
 }
 
 /*
- * expand_single_inheritance_child
- *             Build a RangeTblEntry and an AppendRelInfo, if appropriate, plus
- *             maybe a PlanRowMark.
- *
- * We now expand the partition hierarchy level by level, creating a
- * corresponding hierarchy of AppendRelInfos and RelOptInfos, where each
- * partitioned descendant acts as a parent of its immediate partitions.
- * (This is a difference from what older versions of PostgreSQL did and what
- * is still done in the case of table inheritance for unpartitioned tables,
- * where the hierarchy is flattened during RTE expansion.)
+ * add_inheritance_child_rel
+ *             Build a RangeTblEntry, an AppendRelInfo, a PlanRowMark, and 
finally
+ *             a RelOptInfo for an inheritance child relation.
  *
  * PlanRowMarks still carry the top-parent's RTI, and the top-parent's
  * allMarkTypes field still accumulates values from all descendents.
  *
- * "parentrte" and "parentRTindex" are immediate parent's RTE and
- * RTI. "top_parentrc" is top parent's PlanRowMark.
- *
- * The child RangeTblEntry and its RTI are returned in "childrte_p" and
- * "childRTindex_p" resp.
+ * "parentrte" and "parentRTindex" are immediate parent's RTE and RTI, resp.
+ * "top_parentrc" is top parent's PlanRowMark.
  */
 static void
-expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
-                                                               Index 
parentRTindex, Relation parentrel,
-                                                               PlanRowMark 
*top_parentrc, Relation childrel,
-                                                               List 
**appinfos, RangeTblEntry **childrte_p,
-                                                               Index 
*childRTindex_p)
+add_inheritance_child_rel(PlannerInfo *root, RangeTblEntry *parentrte,
+                                                 Index parentRTindex, Relation 
parentrel,
+                                                 PlanRowMark *top_parentrc, 
Relation childrel,
+                                                 RangeTblEntry **childrte_p, 
Index *childRTindex_p,
+                                                 AppendRelInfo **appinfo_p)
 {
        Query      *parse = root->parse;
-       Oid                     parentOID = RelationGetRelid(parentrel);
        Oid                     childOID = RelationGetRelid(childrel);
-       RangeTblEntry *childrte;
        Index           childRTindex;
+       RangeTblEntry *childrte;
        AppendRelInfo *appinfo;
 
        /*
         * Build an RTE for the child, and attach to query's rangetable list. We
         * copy most fields of the parent's RTE, but replace relation OID and
-        * relkind, and set inh = false.  Also, set requiredPerms to zero since
-        * all required permissions checks are done on the original RTE. 
Likewise,
-        * set the child's securityQuals to empty, because we only want to apply
-        * the parent's RLS conditions regardless of what RLS properties
+        * relkind, and set inh appropriately.  Also, set requiredPerms to zero
+        * since all required permissions checks are done on the original RTE.
+        * Likewise, set the child's securityQuals to empty, because we only 
want
+        * to apply the parent's RLS conditions regardless of what RLS 
properties
         * individual children may have.  (This is an intentional choice to make
         * inherited RLS work like regular permissions checks.) The parent
         * securityQuals will be propagated to children along with other base
@@ -363,49 +484,40 @@ expand_single_inheritance_child(PlannerInfo *root, 
RangeTblEntry *parentrte,
        *childrte_p = childrte;
        childrte->relid = childOID;
        childrte->relkind = childrel->rd_rel->relkind;
-       /* A partitioned child will need to be expanded further. */
-       if (childOID != parentOID &&
-               childrte->relkind == RELKIND_PARTITIONED_TABLE)
-               childrte->inh = true;
-       else
-               childrte->inh = false;
+       /*
+        * A partitioned child will need to be expanded as an append parent
+        * itself, so set its inh to true.
+        */
+       childrte->inh = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
        childrte->requiredPerms = 0;
        childrte->securityQuals = NIL;
        parse->rtable = lappend(parse->rtable, childrte);
        childRTindex = list_length(parse->rtable);
        *childRTindex_p = childRTindex;
 
-       /*
-        * We need an AppendRelInfo if paths will be built for the child RTE. If
-        * childrte->inh is true, then we'll always need to generate append 
paths
-        * for it.  If childrte->inh is false, we must scan it if it's not a
-        * partitioned table; but if it is a partitioned table, then it never 
has
-        * any data of its own and need not be scanned.
-        */
-       if (childrte->relkind != RELKIND_PARTITIONED_TABLE || childrte->inh)
-       {
-               appinfo = make_append_rel_info(parentrel, childrel,
-                                                                          
parentRTindex, childRTindex);
-               *appinfos = lappend(*appinfos, appinfo);
+       /* Create an AppendRelInfo and add it to planner's global list. */
+       appinfo = make_append_rel_info(parentrel, childrel, parentRTindex,
+                                                                  
childRTindex);
+       root->append_rel_list = lappend(root->append_rel_list, appinfo);
+       *appinfo_p = appinfo;
 
-               /*
-                * Translate the column permissions bitmaps to the child's 
attnums (we
-                * have to build the translated_vars list before we can do 
this). But
-                * if this is the parent table, leave copyObject's result alone.
-                *
-                * Note: we need to do this even though the executor won't run 
any
-                * permissions checks on the child RTE.  The 
insertedCols/updatedCols
-                * bitmaps may be examined for trigger-firing purposes.
-                */
-               if (childOID != parentOID)
-               {
-                       childrte->selectedCols = 
translate_col_privs(parentrte->selectedCols,
-                                                                               
                                 appinfo->translated_vars);
-                       childrte->insertedCols = 
translate_col_privs(parentrte->insertedCols,
-                                                                               
                                 appinfo->translated_vars);
-                       childrte->updatedCols = 
translate_col_privs(parentrte->updatedCols,
-                                                                               
                                appinfo->translated_vars);
-               }
+       /*
+        * Translate the column permissions bitmaps to the child's attnums (we
+        * have to build the translated_vars list before we can do this). But
+        * if this is the parent table, leave copyObject's result alone.
+        *
+        * Note: we need to do this even though the executor won't run any
+        * permissions checks on the child RTE.  The insertedCols/updatedCols
+        * bitmaps may be examined for trigger-firing purposes.
+        */
+       if (childrte->relid != parentrte->relid)
+       {
+               childrte->selectedCols = 
translate_col_privs(parentrte->selectedCols,
+                                                                               
                         appinfo->translated_vars);
+               childrte->insertedCols = 
translate_col_privs(parentrte->insertedCols,
+                                                                               
                         appinfo->translated_vars);
+               childrte->updatedCols = 
translate_col_privs(parentrte->updatedCols,
+                                                                               
                        appinfo->translated_vars);
        }
 
        /*
diff --git a/src/backend/optimizer/util/plancat.c 
b/src/backend/optimizer/util/plancat.c
index 78a96b4ee2..b6d4725a31 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -27,6 +27,7 @@
 #include "catalog/catalog.h"
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
+#include "catalog/partition.h"
 #include "catalog/pg_am.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_statistic_ext.h"
@@ -107,20 +108,20 @@ static void set_baserel_partition_key_exprs(Relation 
relation,
  * important for it.
  */
 void
-get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
-                                 RelOptInfo *rel)
+get_relation_info(PlannerInfo *root, RangeTblEntry *rte, RelOptInfo *rel)
 {
        Index           varno = rel->relid;
        Relation        relation;
        bool            hasindex;
        List       *indexinfos = NIL;
+       bool            inhparent = rte->inh;
 
        /*
         * We need not lock the relation since it was already locked, either by
         * the rewriter or when expand_inherited_rtentry() added it to the 
query's
         * rangetable.
         */
-       relation = table_open(relationObjectId, NoLock);
+       relation = heap_open(rte->relid, NoLock);
 
        /* Temporary and unlogged relations are inaccessible during recovery. */
        if (!RelationNeedsWAL(relation) && RecoveryInProgress())
@@ -460,7 +461,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, 
bool inhparent,
         * removing an index, or adding a hypothetical index to the indexlist.
         */
        if (get_relation_info_hook)
-               (*get_relation_info_hook) (root, relationObjectId, inhparent, 
rel);
+               (*get_relation_info_hook) (root, rte->relid, rte->inh, rel);
 }
 
 /*
@@ -2082,16 +2083,19 @@ set_relation_partition_info(PlannerInfo *root, 
RelOptInfo *rel,
                                                        Relation relation)
 {
        PartitionDesc partdesc;
-       PartitionKey partkey;
 
        Assert(relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
 
        partdesc = RelationGetPartitionDesc(relation);
-       partkey = RelationGetPartitionKey(relation);
        rel->part_scheme = find_partition_scheme(root, relation);
        Assert(partdesc != NULL && rel->part_scheme != NULL);
-       rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey);
        rel->nparts = partdesc->nparts;
+
+       /*
+        * Since we must've taken a lock on the table, it's okay to simply copy
+        * the pointers to relcache data here.
+        */
+       rel->boundinfo = partdesc->boundinfo;
        set_baserel_partition_key_exprs(relation, rel);
        rel->partition_qual = RelationGetPartitionQual(relation);
 }
diff --git a/src/backend/optimizer/util/relnode.c 
b/src/backend/optimizer/util/relnode.c
index 4130514952..c5ab9ca8df 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -16,19 +16,26 @@
 
 #include <limits.h>
 
+#include "access/table.h"
 #include "miscadmin.h"
+#include "nodes/makefuncs.h"
 #include "optimizer/appendinfo.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
+#include "optimizer/inherit.h"
+#include "optimizer/optimizer.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/placeholder.h"
 #include "optimizer/plancat.h"
+#include "optimizer/planmain.h"
 #include "optimizer/prep.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/tlist.h"
 #include "partitioning/partbounds.h"
+#include "partitioning/partdesc.h"
 #include "utils/hsearch.h"
+#include "utils/rel.h"
 
 
 typedef struct JoinHashEntry
@@ -63,6 +70,9 @@ static void build_child_join_reltarget(PlannerInfo *root,
                                                   RelOptInfo *childrel,
                                                   int nappinfos,
                                                   AppendRelInfo **appinfos);
+static bool apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
+                                         RelOptInfo *childrel, RangeTblEntry 
*childRTE,
+                                         AppendRelInfo *appinfo);
 
 
 /*
@@ -132,6 +142,50 @@ setup_append_rel_array(PlannerInfo *root)
 }
 
 /*
+ * expand_planner_arrays
+ *             Expand the PlannerInfo arrays by add_size members and 
initialize the
+ *             the     newly added bytes with zero
+ */
+void
+expand_planner_arrays(PlannerInfo *root, int add_size)
+{
+       int             new_size;
+
+       Assert(add_size > 0);
+
+       new_size = root->simple_rel_array_size + add_size;
+
+       /* Expand various arrays and 0-initialize added bytes. */
+       root->simple_rte_array = (RangeTblEntry **)
+                                                       
repalloc(root->simple_rte_array,
+                                                                        
sizeof(RangeTblEntry *) * new_size);
+       MemSet(root->simple_rte_array + root->simple_rel_array_size,
+                  0, sizeof(RangeTblEntry *) * add_size);
+       root->simple_rel_array = (RelOptInfo **)
+                                                               
repalloc(root->simple_rel_array,
+                                                                               
 sizeof(RelOptInfo *) * new_size);
+       MemSet(root->simple_rel_array + root->simple_rel_array_size,
+                  0, sizeof(RelOptInfo *) * add_size);
+
+       if (root->append_rel_array)
+       {
+               root->append_rel_array = (AppendRelInfo **)
+                                                                       
repalloc(root->append_rel_array,
+                                                                        
sizeof(AppendRelInfo *) * new_size);
+               MemSet(root->append_rel_array + root->simple_rel_array_size,
+                          0, sizeof(AppendRelInfo *) * add_size);
+       }
+       else
+       {
+               root->append_rel_array = (AppendRelInfo **)
+                                                                       
palloc0(sizeof(AppendRelInfo *) *
+                                                                               
        new_size);
+       }
+
+       root->simple_rel_array_size = new_size;
+}
+
+/*
  * build_simple_rel
  *       Construct a new RelOptInfo for a base relation or 'other' relation.
  */
@@ -195,6 +249,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo 
*parent)
        rel->joininfo = NIL;
        rel->has_eclass_joins = false;
        rel->consider_partitionwise_join = false;       /* might get changed 
later */
+       rel->top_parent_relids = NULL;  /* might be changed later */
        rel->part_scheme = NULL;
        rel->nparts = 0;
        rel->boundinfo = NULL;
@@ -217,15 +272,13 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo 
*parent)
                else
                        rel->top_parent_relids = bms_copy(parent->relids);
        }
-       else
-               rel->top_parent_relids = NULL;
 
        /* Check type of rtable entry */
        switch (rte->rtekind)
        {
                case RTE_RELATION:
                        /* Table --- retrieve statistics from the system 
catalogs */
-                       get_relation_info(root, rte->relid, rte->inh, rel);
+                       get_relation_info(root, rte, rel);
                        break;
                case RTE_SUBQUERY:
                case RTE_FUNCTION:
@@ -274,55 +327,287 @@ build_simple_rel(PlannerInfo *root, int relid, 
RelOptInfo *parent)
                                                                                
list_length(rte->securityQuals));
 
        /*
-        * If this rel is an appendrel parent, recurse to build "other rel"
-        * RelOptInfos for its children.  They are "other rels" because they are
-        * not in the main join tree, but we will need RelOptInfos to plan 
access
-        * to them.
+        * Add the parent to partitioned_child_rels.
+        *
+        * Note that during the set_append_rel_pathlist() phase, values of the
+        * indexes of partitioned relations that appear down in the tree will
+        * be bubbled up into root parent's list so that when we've created
+        * Paths for all the children, the root table's list will contain all
+        * such indexes.
         */
-       if (rte->inh)
+       if (rel->part_scheme)
+               rel->partitioned_child_rels = list_make1_int(relid);
+
+       if (parent)
        {
-               ListCell   *l;
-               int                     nparts = rel->nparts;
-               int                     cnt_parts = 0;
+               AppendRelInfo *appinfo = root->append_rel_array[relid];
 
-               if (nparts > 0)
-                       rel->part_rels = (RelOptInfo **)
-                               palloc(sizeof(RelOptInfo *) * nparts);
+               Assert(appinfo != NULL);
 
-               foreach(l, root->append_rel_list)
+               /*
+                * Propagate lateral_relids and lateral_referencers from 
appendrel
+                * parent rels to their child rels.  We intentionally give each 
child
+                * rel the same minimum parameterization, even though it's quite
+                * possible that some don't reference all the lateral rels.  
This is
+                * because any append path for the parent will have to have the 
same
+                * parameterization for every child anyway, and there's no 
value in
+                * forcing extra reparameterize_path() calls.  Similarly, a 
lateral
+                * reference to the parent prevents use of otherwise-movable 
join rels
+                * for each child.
+                *
+                * It's possible for child rels to have their own children, in 
which
+                * case the topmost parent's lateral info must be propagated 
all the
+                * way down.  That's ensured by having childrel be expanded via 
this
+                * same path.
+                */
+               rel->direct_lateral_relids = parent->direct_lateral_relids;
+               rel->lateral_relids = parent->lateral_relids;
+               rel->lateral_referencers = parent->lateral_referencers;
+
+               /*
+                * We have to copy the parent's quals to the child, with 
appropriate
+                * substitution of variables.  However, only the 
baserestrictinfo
+                * quals are needed before we can check for constraint 
exclusion; so
+                * do that first and then check to see if we can disregard this 
child.
+                */
+               if (!apply_child_basequals(root, parent, rel, rte, appinfo))
                {
-                       AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
-                       RelOptInfo *childrel;
-
-                       /* append_rel_list contains all append rels; ignore 
others */
-                       if (appinfo->parent_relid != relid)
-                               continue;
-
-                       childrel = build_simple_rel(root, appinfo->child_relid,
-                                                                               
rel);
-
-                       /* Nothing more to do for an unpartitioned table. */
-                       if (!rel->part_scheme)
-                               continue;
-
                        /*
-                        * The order of partition OIDs in append_rel_list is 
the same as
-                        * the order in the PartitionDesc, so the order of 
part_rels will
-                        * also match the PartitionDesc.  See 
expand_partitioned_rtentry.
+                        * Some restriction clause reduced to constant FALSE or 
NULL after
+                        * substitution, so this child need not be scanned.  
Note that
+                        * apply_child_basequals won't have copied quals in 
this case.
                         */
-                       Assert(cnt_parts < nparts);
-                       rel->part_rels[cnt_parts] = childrel;
-                       cnt_parts++;
+                       set_dummy_rel_pathlist(rel);
                }
 
-               /* We should have seen all the child partitions. */
-               Assert(cnt_parts == nparts);
+               /* Constraint exclusion. */
+               if (relation_excluded_by_constraints(root, rel, rte))
+                       set_dummy_rel_pathlist(rel);
        }
 
        return rel;
 }
 
 /*
+ * apply_child_basequals
+ *             Populate childrel's quals based on rel's quals, translating 
them using
+ *             appinfo.
+ *
+ * If any of the resulting clauses evaluate to false or NULL, we return false
+ * and don't apply any quals.  Caller can mark the relation as a dummy rel in
+ * this case, since it needn't be scanned.
+ *
+ * If any resulting clauses evaluate to true, they're unnecessary and we don't
+ * apply then.
+ */
+static bool
+apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
+                                         RelOptInfo *childrel, RangeTblEntry 
*childRTE,
+                                         AppendRelInfo *appinfo)
+{
+       List       *childquals;
+       Index           cq_min_security;
+       ListCell   *lc;
+
+       /*
+        * The child rel's targetlist might contain non-Var expressions, which
+        * means that substitution into the quals could produce opportunities 
for
+        * const-simplification, and perhaps even pseudoconstant quals. 
Therefore,
+        * transform each RestrictInfo separately to see if it reduces to a
+        * constant or pseudoconstant.  (We must process them separately to keep
+        * track of the security level of each qual.)
+        */
+       childquals = NIL;
+       cq_min_security = UINT_MAX;
+       foreach(lc, rel->baserestrictinfo)
+       {
+               RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+               Node       *childqual;
+               ListCell   *lc2;
+
+               Assert(IsA(rinfo, RestrictInfo));
+               childqual = adjust_appendrel_attrs(root,
+                                                                               
   (Node *) rinfo->clause,
+                                                                               
   1, &appinfo);
+               childqual = eval_const_expressions(root, childqual);
+               /* check for flat-out constant */
+               if (childqual && IsA(childqual, Const))
+               {
+                       if (((Const *) childqual)->constisnull ||
+                               !DatumGetBool(((Const *) 
childqual)->constvalue))
+                       {
+                               /* Restriction reduces to constant FALSE or 
NULL */
+                               return false;
+                       }
+                       /* Restriction reduces to constant TRUE, so drop it */
+                       continue;
+               }
+               /* might have gotten an AND clause, if so flatten it */
+               foreach(lc2, make_ands_implicit((Expr *) childqual))
+               {
+                       Node       *onecq = (Node *) lfirst(lc2);
+                       bool            pseudoconstant;
+
+                       /* check for pseudoconstant (no Vars or volatile 
functions) */
+                       pseudoconstant =
+                               !contain_vars_of_level(onecq, 0) &&
+                               !contain_volatile_functions(onecq);
+                       if (pseudoconstant)
+                       {
+                               /* tell createplan.c to check for gating quals 
*/
+                               root->hasPseudoConstantQuals = true;
+                       }
+                       /* reconstitute RestrictInfo with appropriate 
properties */
+                       childquals = lappend(childquals,
+                                                                
make_restrictinfo((Expr *) onecq,
+                                                                               
                   rinfo->is_pushed_down,
+                                                                               
                   rinfo->outerjoin_delayed,
+                                                                               
                   pseudoconstant,
+                                                                               
                   rinfo->security_level,
+                                                                               
                   NULL, NULL, NULL));
+                       /* track minimum security level among child quals */
+                       cq_min_security = Min(cq_min_security, 
rinfo->security_level);
+               }
+       }
+
+       /*
+        * In addition to the quals inherited from the parent, we might have
+        * securityQuals associated with this particular child node. (Currently
+        * this can only happen in appendrels originating from UNION ALL;
+        * inheritance child tables don't have their own securityQuals, see
+        * expand_inherited_rtentry().) Pull any such securityQuals up into the
+        * baserestrictinfo for the child.  This is similar to
+        * process_security_barrier_quals() for the parent rel, except that we
+        * can't make any general deductions from such quals, since they don't
+        * hold for the whole appendrel.
+        */
+       if (childRTE->securityQuals)
+       {
+               Index           security_level = 0;
+
+               foreach(lc, childRTE->securityQuals)
+               {
+                       List       *qualset = (List *) lfirst(lc);
+                       ListCell   *lc2;
+
+                       foreach(lc2, qualset)
+                       {
+                               Expr       *qual = (Expr *) lfirst(lc2);
+
+                               /* not likely that we'd see constants here, so 
no check */
+                               childquals = lappend(childquals,
+                                                                        
make_restrictinfo(qual,
+                                                                               
                           true, false, false,
+                                                                               
                           security_level,
+                                                                               
                           NULL, NULL, NULL));
+                               cq_min_security = Min(cq_min_security, 
security_level);
+                       }
+                       security_level++;
+               }
+               Assert(security_level <= root->qual_security_level);
+       }
+
+       /*
+        * OK, we've got all the baserestrictinfo quals for this child.
+        */
+       childrel->baserestrictinfo = childquals;
+       childrel->baserestrict_min_security = cq_min_security;
+
+       return true;
+}
+
+/*
+ * add_appendrel_other_rels
+ *
+ */
+void
+add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti)
+{
+       ListCell           *l;
+       RelOptInfo         *rel;
+       Relation                relation = NULL;
+       PartitionDesc   partdesc;
+
+       /*
+        * If a table, expand_inherited_rtentry takes care of recursively adds
+        * all the otherrels, performing partition pruning for both this
+        * rel and recursively added partitioned tables.
+        */
+       if (rte->rtekind == RTE_RELATION && !root->contains_inherit_children)
+       {
+               expand_inherited_rtentry(root, rte, rti);
+               return;
+       }
+
+       /*
+        * UNION ALL children already got RTEs and AppendRelInfos, so just build
+        * RelOptInfos and return.
+        */
+       rel = find_base_rel(root, rti);
+
+       if (rel->part_scheme)
+       {
+               rel->part_rels = (RelOptInfo **)
+                               palloc0(sizeof(RelOptInfo *) * rel->nparts);
+               relation = table_open(rte->relid, NoLock);
+               partdesc = RelationGetPartitionDesc(relation);
+       }
+
+       /*
+        * We don't need to use expand_planner_arrays in this case, because
+        * no new child RTEs are created.  setup_simple_rel_arrays() and
+        * setup_append_rel_array would've considered these child RTEs when
+        * allocating space for various arrays.
+        */
+       foreach(l, root->append_rel_list)
+       {
+               AppendRelInfo  *appinfo = lfirst(l);
+               Index                   childRTindex = appinfo->child_relid;
+               RangeTblEntry  *childrte;
+               RelOptInfo         *childrel;
+               int             i = 0;
+
+               if (appinfo->parent_relid != rti)
+                               continue;
+
+               Assert(childRTindex < root->simple_rel_array_size);
+               childrte = root->simple_rte_array[childRTindex];
+               Assert(childrte != NULL);
+               childrel = build_simple_rel(root, childRTindex, rel);
+
+               /* Nothing more to do for an unpartitioned table. */
+               if (rel->part_scheme != NULL)
+               {
+                       /*
+                        * Add childrel to part_rels array.  Considering that
+                        * append_rel_list may not contain all partitions due 
to some
+                        * being pruned, we must skip the slots of part_rels 
array
+                        * that would otherwise contain pruned partitions.  
This works
+                        * because, partitions appear in append_rel_list in the 
same
+                        * order as the order in which they appear in the 
PartitionDesc.
+                        * See expand_partitioned_rtentry.
+                        */
+                       Assert(partdesc != NULL);
+                       for (i = 0; i < partdesc->nparts; i++)
+                       {
+                               if (childrte->relid == partdesc->oids[i])
+                               {
+                                       rel->part_rels[i] = childrel;
+                                       break;
+                               }
+                       }
+               }
+
+               /* Child may itself be an inherited relation. */
+               if (childrte->inh)
+                       add_appendrel_other_rels(root, childrte, childRTindex);
+       }
+
+       if (relation)
+               table_close(relation, NoLock);
+}
+
+/*
  * find_base_rel
  *       Find a base or other relation entry, which must already exist.
  */
diff --git a/src/backend/partitioning/partprune.c 
b/src/backend/partitioning/partprune.c
index 8c9721935d..472a6cd331 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -45,6 +45,8 @@
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/appendinfo.h"
+#include "optimizer/clauses.h"
+#include "optimizer/cost.h"
 #include "optimizer/optimizer.h"
 #include "optimizer/pathnode.h"
 #include "partitioning/partprune.h"
@@ -433,17 +435,23 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, 
RelOptInfo *parentrel,
                 * is, not pruned already).
                 */
                subplan_map = (int *) palloc(nparts * sizeof(int));
+               memset(subplan_map, -1, nparts * sizeof(int));
                subpart_map = (int *) palloc(nparts * sizeof(int));
+               memset(subpart_map, -1, nparts * sizeof(int));
                present_parts = NULL;
 
                for (i = 0; i < nparts; i++)
                {
                        RelOptInfo *partrel = subpart->part_rels[i];
-                       int                     subplanidx = 
relid_subplan_map[partrel->relid] - 1;
-                       int                     subpartidx = 
relid_subpart_map[partrel->relid] - 1;
+                       int                     subplanidx;
+                       int                     subpartidx;
 
-                       subplan_map[i] = subplanidx;
-                       subpart_map[i] = subpartidx;
+                       /* Skip processing pruned partitions. */
+                       if (partrel == NULL)
+                               continue;
+
+                       subplan_map[i] = subplanidx = 
relid_subplan_map[partrel->relid] - 1;
+                       subpart_map[i] = subpartidx = 
relid_subpart_map[partrel->relid] - 1;
                        if (subplanidx >= 0)
                        {
                                present_parts = bms_add_member(present_parts, 
i);
@@ -537,23 +545,20 @@ gen_partprune_steps(RelOptInfo *rel, List *clauses, bool 
*contradictory)
 
 /*
  * prune_append_rel_partitions
- *             Returns RT indexes of the minimum set of child partitions which 
must
- *             be scanned to satisfy rel's baserestrictinfo quals.
+ *             Returns indexes into rel->part_rels of the minimum set of child
+ *             partitions which must be scanned to satisfy rel's 
baserestrictinfo
+ *             quals.
  *
  * Callers must ensure that 'rel' is a partitioned table.
  */
-Relids
+Bitmapset *
 prune_append_rel_partitions(RelOptInfo *rel)
 {
-       Relids          result;
        List       *clauses = rel->baserestrictinfo;
        List       *pruning_steps;
        bool            contradictory;
        PartitionPruneContext context;
-       Bitmapset  *partindexes;
-       int                     i;
 
-       Assert(clauses != NIL);
        Assert(rel->part_scheme != NULL);
 
        /* If there are no partitions, return the empty set */
@@ -561,6 +566,13 @@ prune_append_rel_partitions(RelOptInfo *rel)
                return NULL;
 
        /*
+        * If pruning is disabled or if there are no clauses to prune with,
+        * return all partitions.
+        */
+       if (!enable_partition_pruning || clauses == NIL)
+               return bms_add_range(NULL, 0, rel->nparts - 1);
+
+       /*
         * Process clauses.  If the clauses are found to be contradictory, we 
can
         * return the empty set.
         */
@@ -587,15 +599,7 @@ prune_append_rel_partitions(RelOptInfo *rel)
        context.evalexecparams = false;
 
        /* Actual pruning happens here. */
-       partindexes = get_matching_partitions(&context, pruning_steps);
-
-       /* Add selected partitions' RT indexes to result. */
-       i = -1;
-       result = NULL;
-       while ((i = bms_next_member(partindexes, i)) >= 0)
-               result = bms_add_member(result, rel->part_rels[i]->relid);
-
-       return result;
+       return get_matching_partitions(&context, pruning_steps);
 }
 
 /*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index a008ae07da..c2e292e54c 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -348,6 +348,13 @@ struct PlannerInfo
 
        /* Does this query modify any partition key columns? */
        bool            partColsUpdated;
+
+       /*
+        * Does this PlannerInfo and its Query object contain *all* inheritance
+        * children?  If true, the RTEs, the AppendRelInfos, and the 
PlanRowMarks
+        * of all the children are assumed to be present.
+        */
+       bool            contains_inherit_children;
 };
 
 
diff --git a/src/include/optimizer/inherit.h b/src/include/optimizer/inherit.h
index d2418f15cf..bf3dd357d6 100644
--- a/src/include/optimizer/inherit.h
+++ b/src/include/optimizer/inherit.h
@@ -16,7 +16,8 @@
 
 #include "nodes/pathnodes.h"
 
-
-extern void expand_inherited_tables(PlannerInfo *root);
+extern void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
+                                                               Index rti);
+extern void expand_inherited_target_rtentry(PlannerInfo *root);
 
 #endif                                                 /* INHERIT_H */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 574bb85b50..60361507d2 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -277,8 +277,11 @@ extern Path *reparameterize_path_by_child(PlannerInfo 
*root, Path *path,
  */
 extern void setup_simple_rel_arrays(PlannerInfo *root);
 extern void setup_append_rel_array(PlannerInfo *root);
+extern void expand_planner_arrays(PlannerInfo *root, int add_size);
 extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
                                 RelOptInfo *parent);
+extern void add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte,
+                                Index rti);
 extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
 extern RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids);
 extern RelOptInfo *build_join_rel(PlannerInfo *root,
diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h
index c337f047cb..04731f532f 100644
--- a/src/include/optimizer/plancat.h
+++ b/src/include/optimizer/plancat.h
@@ -25,8 +25,8 @@ typedef void (*get_relation_info_hook_type) (PlannerInfo 
*root,
 extern PGDLLIMPORT get_relation_info_hook_type get_relation_info_hook;
 
 
-extern void get_relation_info(PlannerInfo *root, Oid relationObjectId,
-                                 bool inhparent, RelOptInfo *rel);
+extern void get_relation_info(PlannerInfo *root, RangeTblEntry *rte,
+                                 RelOptInfo *rel);
 
 extern List *infer_arbiter_indexes(PlannerInfo *root);
 
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 3bbdb5e2f7..035caac500 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -65,6 +65,7 @@ extern int    from_collapse_limit;
 extern int     join_collapse_limit;
 
 extern void add_base_rels_to_query(PlannerInfo *root, Node *jtnode);
+extern void add_other_rels_to_query(PlannerInfo *root, Node *jtnode);
 extern void build_base_rel_tlists(PlannerInfo *root, List *final_tlist);
 extern void add_vars_to_targetlist(PlannerInfo *root, List *vars,
                                           Relids where_needed, bool 
create_new_ph);
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index a9b2c9026c..5979c9885e 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -37,6 +37,8 @@ extern Relids get_relids_for_join(Query *query, int 
joinrelid);
 extern List *preprocess_targetlist(PlannerInfo *root);
 
 extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex);
+extern List *get_rowmark_junk_tles(PlannerInfo *root, List *tlist,
+                                                       PlanRowMark *rc);
 
 /*
  * prototypes for prepunion.c
diff --git a/src/test/regress/expected/partition_aggregate.out 
b/src/test/regress/expected/partition_aggregate.out
index 6bc106831e..1450cef057 100644
--- a/src/test/regress/expected/partition_aggregate.out
+++ b/src/test/regress/expected/partition_aggregate.out
@@ -144,7 +144,7 @@ SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c;
            QUERY PLAN           
 --------------------------------
  HashAggregate
-   Group Key: pagg_tab.c
+   Group Key: c
    ->  Result
          One-Time Filter: false
 (4 rows)
@@ -159,7 +159,7 @@ SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c;
            QUERY PLAN           
 --------------------------------
  GroupAggregate
-   Group Key: pagg_tab.c
+   Group Key: c
    ->  Result
          One-Time Filter: false
 (4 rows)
-- 
2.11.0

From e9d3d5d8ea899f1fd028cb5b628337197d1b2b32 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Mon, 15 Oct 2018 10:59:24 +0900
Subject: [PATCH v25 2/2] Teach planner to only process unpruned partitions

This adds a bitmapset field live_parts to RelOptInfo and stores
the partition indexes of non-dummy partitions in it, meaning it
contains indexes of only those partitions that have a non-NULL
RelOptInfo present in its parent's RelOptInfo's part_rels array.

This speeds up processing partitioned table's partitions compared
to going through the whole part_rels array in a number of places.
---
 src/backend/optimizer/path/joinrels.c |  3 +++
 src/backend/optimizer/plan/planner.c  | 18 +++++++++---------
 src/backend/optimizer/util/inherit.c  |  1 +
 src/backend/optimizer/util/relnode.c  |  4 ++++
 src/backend/partitioning/partprune.c  | 18 +++++-------------
 src/include/nodes/pathnodes.h         |  4 ++++
 6 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/src/backend/optimizer/path/joinrels.c 
b/src/backend/optimizer/path/joinrels.c
index 66a5cf3334..57158d90ec 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1470,6 +1470,9 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo 
*rel1, RelOptInfo *rel2,
                populate_joinrel_with_paths(root, child_rel1, child_rel2,
                                                                        
child_joinrel, child_sjinfo,
                                                                        
child_restrictlist);
+               if (!IS_DUMMY_REL(child_joinrel))
+                       joinrel->live_parts = 
bms_add_member(joinrel->live_parts,
+                                                                               
                 cnt_parts);
        }
 
        if (baserel1)
diff --git a/src/backend/optimizer/plan/planner.c 
b/src/backend/optimizer/plan/planner.c
index ddc4d27f67..bcfa84b4ce 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -7127,7 +7127,9 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
                List       *live_children = NIL;
 
                /* Adjust each partition. */
-               for (partition_idx = 0; partition_idx < rel->nparts; 
partition_idx++)
+               partition_idx = -1;
+               while ((partition_idx = bms_next_member(rel->live_parts,
+                                                                               
                partition_idx)) >= 0)
                {
                        RelOptInfo *child_rel = rel->part_rels[partition_idx];
                        ListCell   *lc;
@@ -7135,9 +7137,7 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
                        int                     nappinfos;
                        List       *child_scanjoin_targets = NIL;
 
-                       /* Skip processing pruned partitions. */
-                       if (child_rel == NULL)
-                               continue;
+                       Assert(child_rel != NULL);
 
                        /* Translate scan/join targets for this child. */
                        appinfos = find_appinfos_by_relids(root, 
child_rel->relids,
@@ -7218,7 +7218,6 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
                                                                        
PartitionwiseAggregateType patype,
                                                                        
GroupPathExtraData *extra)
 {
-       int                     nparts = input_rel->nparts;
        int                     cnt_parts;
        List       *grouped_live_children = NIL;
        List       *partially_grouped_live_children = NIL;
@@ -7230,7 +7229,9 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
                   partially_grouped_rel != NULL);
 
        /* Add paths for partitionwise aggregation/grouping. */
-       for (cnt_parts = 0; cnt_parts < nparts; cnt_parts++)
+       cnt_parts = -1;
+       while ((cnt_parts = bms_next_member(input_rel->live_parts,
+                                                                               
cnt_parts)) >= 0)
        {
                RelOptInfo *child_input_rel = input_rel->part_rels[cnt_parts];
                PathTarget *child_target = copy_pathtarget(target);
@@ -7240,9 +7241,8 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
                RelOptInfo *child_grouped_rel;
                RelOptInfo *child_partially_grouped_rel;
 
-               /* Skip processing pruned partitions. */
-               if (child_input_rel == NULL)
-                       continue;
+               /* A live partition must have a RelOptInfo. */
+               Assert(child_input_rel != NULL);
 
                /* Input child rel must have a path */
                Assert(child_input_rel->pathlist != NIL);
diff --git a/src/backend/optimizer/util/inherit.c 
b/src/backend/optimizer/util/inherit.c
index e437709fc3..e1a8a35561 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -310,6 +310,7 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry 
*parentrte,
 
        /* Perform pruning. */
        partindexes = prune_append_rel_partitions(parent);
+       parent->live_parts = partindexes;
 
        /* Must expand PlannerInfo arrays before we can add children. */
        if (bms_num_members(partindexes) > 0)
diff --git a/src/backend/optimizer/util/relnode.c 
b/src/backend/optimizer/util/relnode.c
index c5ab9ca8df..6d8b862535 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -593,6 +593,7 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry 
*rte, Index rti)
                                if (childrte->relid == partdesc->oids[i])
                                {
                                        rel->part_rels[i] = childrel;
+                                       rel->live_parts = 
bms_add_member(rel->live_parts, i);
                                        break;
                                }
                        }
@@ -2019,6 +2020,9 @@ build_joinrel_partition_info(RelOptInfo *joinrel, 
RelOptInfo *outer_rel,
                joinrel->partexprs[cnt] = partexpr;
                joinrel->nullable_partexprs[cnt] = nullable_partexpr;
        }
+
+       /* Partitions will be added by try_partitionwise_join. */
+       joinrel->live_parts = NULL;
 }
 
 /*
diff --git a/src/backend/partitioning/partprune.c 
b/src/backend/partitioning/partprune.c
index 472a6cd331..babb7d3406 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -438,29 +438,21 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, 
RelOptInfo *parentrel,
                memset(subplan_map, -1, nparts * sizeof(int));
                subpart_map = (int *) palloc(nparts * sizeof(int));
                memset(subpart_map, -1, nparts * sizeof(int));
-               present_parts = NULL;
+               present_parts = bms_copy(subpart->live_parts);
 
-               for (i = 0; i < nparts; i++)
+               i = -1;
+               while ((i = bms_next_member(present_parts, i)) >= 0)
                {
                        RelOptInfo *partrel = subpart->part_rels[i];
                        int                     subplanidx;
                        int                     subpartidx;
 
-                       /* Skip processing pruned partitions. */
-                       if (partrel == NULL)
-                               continue;
-
+                       Assert(partrel != NULL);
                        subplan_map[i] = subplanidx = 
relid_subplan_map[partrel->relid] - 1;
                        subpart_map[i] = subpartidx = 
relid_subpart_map[partrel->relid] - 1;
+                       /* Record finding this subplan */
                        if (subplanidx >= 0)
-                       {
-                               present_parts = bms_add_member(present_parts, 
i);
-
-                               /* Record finding this subplan  */
                                subplansfound = bms_add_member(subplansfound, 
subplanidx);
-                       }
-                       else if (subpartidx >= 0)
-                               present_parts = bms_add_member(present_parts, 
i);
                }
 
                pinfo = makeNode(PartitionedRelPruneInfo);
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index c2e292e54c..53d0485964 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -712,6 +712,10 @@ typedef struct RelOptInfo
        List       *partition_qual; /* partition constraint */
        struct RelOptInfo **part_rels;  /* Array of RelOptInfos of partitions,
                                                                         * 
stored in the same order of bounds */
+       Bitmapset  *live_parts;         /* Indexes into part_rels of the 
non-NULL
+                                                                * RelOptInfos 
of unpruned partitions; exists
+                                                                * to avoid 
having to iterate over the entire
+                                                                * part_rels 
array to filter NULL entries. */
        List      **partexprs;          /* Non-nullable partition key 
expressions. */
        List      **nullable_partexprs; /* Nullable partition key expressions. 
*/
        List       *partitioned_child_rels; /* List of RT indexes. */
-- 
2.11.0

Reply via email to