diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 9ad9035..310c715 100644
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
*************** select * from bar where f1 in (select f1
*** 7116,7124 ****
                                            QUERY PLAN                                          
  ----------------------------------------------------------------------------------------------
   LockRows
!    Output: bar.f1, bar.f2, bar.ctid, bar.*, bar.tableoid, foo.ctid, foo.*, foo.tableoid
     ->  Hash Join
!          Output: bar.f1, bar.f2, bar.ctid, bar.*, bar.tableoid, foo.ctid, foo.*, foo.tableoid
           Inner Unique: true
           Hash Cond: (bar.f1 = foo.f1)
           ->  Append
--- 7116,7124 ----
                                            QUERY PLAN                                          
  ----------------------------------------------------------------------------------------------
   LockRows
!    Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
     ->  Hash Join
!          Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
           Inner Unique: true
           Hash Cond: (bar.f1 = foo.f1)
           ->  Append
*************** select * from bar where f1 in (select f1
*** 7128,7142 ****
                       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
                 ->  HashAggregate
!                      Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1
                                   Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
  (23 rows)
  
--- 7128,7142 ----
                       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.f1, foo.*, foo.tableoid
                 ->  HashAggregate
!                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.f1, foo2.*, foo2.tableoid
                                   Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
  (23 rows)
  
*************** select * from bar where f1 in (select f1
*** 7154,7162 ****
                                            QUERY PLAN                                          
  ----------------------------------------------------------------------------------------------
   LockRows
!    Output: bar.f1, bar.f2, bar.ctid, bar.*, bar.tableoid, foo.ctid, foo.*, foo.tableoid
     ->  Hash Join
!          Output: bar.f1, bar.f2, bar.ctid, bar.*, bar.tableoid, foo.ctid, foo.*, foo.tableoid
           Inner Unique: true
           Hash Cond: (bar.f1 = foo.f1)
           ->  Append
--- 7154,7162 ----
                                            QUERY PLAN                                          
  ----------------------------------------------------------------------------------------------
   LockRows
!    Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
     ->  Hash Join
!          Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
           Inner Unique: true
           Hash Cond: (bar.f1 = foo.f1)
           ->  Append
*************** select * from bar where f1 in (select f1
*** 7166,7180 ****
                       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
                 ->  HashAggregate
!                      Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1
                                   Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
  (23 rows)
  
--- 7166,7180 ----
                       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.f1, foo.*, foo.tableoid
                 ->  HashAggregate
!                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.f1, foo2.*, foo2.tableoid
                                   Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
  (23 rows)
  
*************** update bar set f2 = f2 + 100 where f1 in
*** 7203,7217 ****
           ->  Seq Scan on public.bar
                 Output: bar.f1, bar.f2, bar.ctid
           ->  Hash
!                Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                 ->  HashAggregate
!                      Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1
                                   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
--- 7203,7217 ----
           ->  Seq Scan on public.bar
                 Output: bar.f1, bar.f2, bar.ctid
           ->  Hash
!                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                 ->  HashAggregate
!                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.f1, 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
*************** update bar set f2 = f2 + 100 where f1 in
*** 7221,7235 ****
                 Output: bar2.f1, bar2.f2, bar2.f3, bar2.ctid
                 Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
           ->  Hash
!                Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                 ->  HashAggregate
!                      Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.*, foo.tableoid, foo.f1
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1
                                   Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
  (39 rows)
  
--- 7221,7235 ----
                 Output: bar2.f1, bar2.f2, bar2.f3, bar2.ctid
                 Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
           ->  Hash
!                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                 ->  HashAggregate
!                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                       Group Key: foo.f1
                       ->  Append
                             ->  Seq Scan on public.foo
!                                  Output: foo.ctid, foo.f1, foo.*, foo.tableoid
                             ->  Foreign Scan on public.foo2
!                                  Output: foo2.ctid, foo2.f1, foo2.*, foo2.tableoid
                                   Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
  (39 rows)
  
*************** SELECT t1.a,t2.b,t2.c FROM fprt1 t1 LEFT
*** 8435,8441 ****
   Foreign Scan
     Output: t1.a, ftprt2_p1.b, ftprt2_p1.c
     Relations: (public.ftprt1_p1 t1) LEFT JOIN (public.ftprt2_p1 fprt2)
!    Remote SQL: SELECT r5.a, r7.b, r7.c FROM (public.fprt1_p1 r5 LEFT JOIN public.fprt2_p1 r7 ON (((r5.a = r7.b)) AND ((r5.b = r7.a)) AND ((r7.a < 10)))) WHERE ((r5.a < 10)) ORDER BY r5.a ASC NULLS LAST, r7.b ASC NULLS LAST, r7.c ASC NULLS LAST
  (4 rows)
  
  SELECT t1.a,t2.b,t2.c FROM fprt1 t1 LEFT JOIN (SELECT * FROM fprt2 WHERE a < 10) t2 ON (t1.a = t2.b and t1.b = t2.a) WHERE t1.a < 10 ORDER BY 1,2,3;
--- 8435,8441 ----
   Foreign Scan
     Output: t1.a, ftprt2_p1.b, ftprt2_p1.c
     Relations: (public.ftprt1_p1 t1) LEFT JOIN (public.ftprt2_p1 fprt2)
!    Remote SQL: SELECT r5.a, r6.b, r6.c FROM (public.fprt1_p1 r5 LEFT JOIN public.fprt2_p1 r6 ON (((r5.a = r6.b)) AND ((r5.b = r6.a)) AND ((r6.a < 10)))) WHERE ((r5.a < 10)) ORDER BY r5.a ASC NULLS LAST, r6.b ASC NULLS LAST, r6.c ASC NULLS LAST
  (4 rows)
  
  SELECT t1.a,t2.b,t2.c FROM fprt1 t1 LEFT JOIN (SELECT * FROM fprt2 WHERE a < 10) t2 ON (t1.a = t2.b and t1.b = t2.a) WHERE t1.a < 10 ORDER BY 1,2,3;
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index cfad8a3..b72db85 100644
*** a/src/backend/executor/execPartition.c
--- b/src/backend/executor/execPartition.c
*************** ExecCreatePartitionPruneState(PlanState 
*** 1654,1662 ****
  				memcpy(pprune->subplan_map, pinfo->subplan_map,
  					   sizeof(int) * pinfo->nparts);
  
! 				/* Double-check that list of relations has not changed. */
! 				Assert(memcmp(partdesc->oids, pinfo->relid_map,
! 					   pinfo->nparts * sizeof(Oid)) == 0);
  			}
  			else
  			{
--- 1654,1670 ----
  				memcpy(pprune->subplan_map, pinfo->subplan_map,
  					   sizeof(int) * pinfo->nparts);
  
! 				/*
! 				 * Double-check that the list of unpruned relations has not
! 				 * changed.  (Pruned partitions are not in relid_map[].)
! 				 */
! #ifdef USE_ASSERT_CHECKING
! 				for (int k = 0; k < pinfo->nparts; k++)
! 				{
! 					Assert(partdesc->oids[k] == pinfo->relid_map[k] ||
! 						   pinfo->subplan_map[k] == -1);
! 				}
! #endif
  			}
  			else
  			{
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 3c9d84f..727da33 100644
*** a/src/backend/optimizer/path/allpaths.c
--- b/src/backend/optimizer/path/allpaths.c
*************** static void subquery_push_qual(Query *su
*** 139,147 ****
  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);
  
  
  /*
--- 139,144 ----
*************** set_rel_size(PlannerInfo *root, RelOptIn
*** 396,403 ****
  				else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
  				{
  					/*
! 					 * A partitioned table without any partitions is marked as
! 					 * a dummy rel.
  					 */
  					set_dummy_rel_pathlist(rel);
  				}
--- 393,401 ----
  				else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
  				{
  					/*
! 					 * We could get here if asked to scan a partitioned table
! 					 * with ONLY.  In that case we shouldn't scan any of the
! 					 * partitions, so mark it as a dummy rel.
  					 */
  					set_dummy_rel_pathlist(rel);
  				}
*************** set_append_rel_size(PlannerInfo *root, R
*** 946,953 ****
  	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();
--- 944,949 ----
*************** set_append_rel_size(PlannerInfo *root, R
*** 966,986 ****
  		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.
--- 962,967 ----
*************** set_append_rel_size(PlannerInfo *root, R
*** 1034,1063 ****
  		childrel = find_base_rel(root, childRTindex);
  		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.
  		 */
- 		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);
- 			continue;
- 		}
- 
  		if (relation_excluded_by_constraints(root, childrel, childRTE))
  		{
  			/*
--- 1015,1031 ----
  		childrel = find_base_rel(root, childRTindex);
  		Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
  
! 		/* We may have already proven the child to be dummy. */
! 		if (IS_DUMMY_REL(childrel))
  			continue;
  
  		/*
  		 * We have to copy the parent's targetlist and quals to the child,
! 		 * with appropriate substitution of variables.  However, the
! 		 * baserestrictinfo quals were already copied/substituted when the
! 		 * child RelOptInfo was built.  So we don't need any additional setup
! 		 * before applying constraint exclusion.
  		 */
  		if (relation_excluded_by_constraints(root, childrel, childRTE))
  		{
  			/*
*************** set_append_rel_size(PlannerInfo *root, R
*** 1069,1075 ****
  		}
  
  		/*
! 		 * CE failed, so finish copying/modifying targetlist and join quals.
  		 *
  		 * NB: the resulting childrel->reltarget->exprs may contain arbitrary
  		 * expressions, which otherwise would not occur in a rel's targetlist.
--- 1037,1044 ----
  		}
  
  		/*
! 		 * Constraint exclusion failed, so copy the parent's join quals and
! 		 * targetlist to the child, with appropriate variable substitutions.
  		 *
  		 * NB: the resulting childrel->reltarget->exprs may contain arbitrary
  		 * expressions, which otherwise would not occur in a rel's targetlist.
*************** generate_partitionwise_join_paths(Planne
*** 3596,3728 ****
  	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
--- 3565,3570 ----
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 62dfac6..9798dca 100644
*** a/src/backend/optimizer/plan/initsplan.c
--- b/src/backend/optimizer/plan/initsplan.c
***************
*** 20,25 ****
--- 20,26 ----
  #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"
*************** add_other_rels_to_query(PlannerInfo *roo
*** 159,170 ****
  
  		/* If it's marked as inheritable, look for children. */
  		if (rte->inh)
! 		{
! 			/* Only relation and subquery RTEs can have children. */
! 			Assert(rte->rtekind == RTE_RELATION ||
! 				   rte->rtekind == RTE_SUBQUERY);
! 			add_appendrel_other_rels(root, rel, rti);
! 		}
  	}
  }
  
--- 160,166 ----
  
  		/* If it's marked as inheritable, look for children. */
  		if (rte->inh)
! 			expand_inherited_rtentry(root, rel, rte, rti);
  	}
  }
  
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 031e709..f08f1cd 100644
*** a/src/backend/optimizer/plan/planner.c
--- b/src/backend/optimizer/plan/planner.c
***************
*** 25,30 ****
--- 25,31 ----
  #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"
*************** subquery_planner(PlannerGlobal *glob, Qu
*** 679,690 ****
  		flatten_simple_union_all(root);
  
  	/*
! 	 * Detect whether any rangetable entries are RTE_JOIN kind; if not, we can
! 	 * avoid the expense of doing flatten_join_alias_vars().  Likewise check
! 	 * whether any are RTE_RESULT kind; if not, we can skip
! 	 * remove_useless_result_rtes().  Also check for outer joins --- if none,
! 	 * we can skip reduce_outer_joins().  And check for LATERAL RTEs, too.
! 	 * This must be done after we have done pull_up_subqueries(), of course.
  	 */
  	root->hasJoinRTEs = false;
  	root->hasLateralRTEs = false;
--- 680,693 ----
  		flatten_simple_union_all(root);
  
  	/*
! 	 * Survey the rangetable to see what kinds of entries are present.  We can
! 	 * skip some later processing if relevant SQL features are not used; for
! 	 * example if there are no JOIN RTEs we can avoid the expense of doing
! 	 * flatten_join_alias_vars().  This must be done after we have finished
! 	 * adding rangetable entries, of course.  (Note: actually, processing of
! 	 * inherited or partitioned rels can cause RTEs for their child tables to
! 	 * get added later; but those must all be RTE_RELATION entries, so they
! 	 * don't invalidate the conclusions drawn here.)
  	 */
  	root->hasJoinRTEs = false;
  	root->hasLateralRTEs = false;
*************** subquery_planner(PlannerGlobal *glob, Qu
*** 694,732 ****
  	{
  		RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
  
! 		if (rte->rtekind == RTE_JOIN)
! 		{
! 			root->hasJoinRTEs = true;
! 			if (IS_OUTER_JOIN(rte->jointype))
! 				hasOuterJoins = true;
! 		}
! 		else if (rte->rtekind == RTE_RESULT)
  		{
! 			hasResultRTEs = true;
  		}
  		if (rte->lateral)
  			root->hasLateralRTEs = true;
  	}
  
  	/*
  	 * 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).
  	 */
  	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.
--- 697,745 ----
  	{
  		RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
  
! 		switch (rte->rtekind)
  		{
! 			case RTE_RELATION:
! 				if (rte->inh)
! 				{
! 					/*
! 					 * Check to see if the relation actually has any children;
! 					 * if not, clear the inh flag so we can treat it as a
! 					 * plain base relation.
! 					 *
! 					 * Note: this could give a false-positive result, if the
! 					 * rel once had children but no longer does.  We used to
! 					 * be able to clear rte->inh later on when we discovered
! 					 * that, but no more; we have to handle such cases as
! 					 * full-fledged inheritance.
! 					 */
! 					rte->inh = has_subclass(rte->relid);
! 				}
! 				break;
! 			case RTE_JOIN:
! 				root->hasJoinRTEs = true;
! 				if (IS_OUTER_JOIN(rte->jointype))
! 					hasOuterJoins = true;
! 				break;
! 			case RTE_RESULT:
! 				hasResultRTEs = true;
! 				break;
! 			default:
! 				/* No work here for other RTE types */
! 				break;
  		}
+ 
  		if (rte->lateral)
  			root->hasLateralRTEs = true;
  	}
  
  	/*
  	 * Preprocess RowMark information.  We need to do this after subquery
! 	 * pullup, so that all base relations are present.
  	 */
  	preprocess_rowmarks(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.
*************** inheritance_planner(PlannerInfo *root)
*** 1180,1190 ****
  {
  	Query	   *parse = root->parse;
  	int			top_parentRTindex = parse->resultRelation;
  	Bitmapset  *subqueryRTindexes;
! 	Bitmapset  *modifiableARIindexes;
  	int			nominalRelation = -1;
  	Index		rootRelation = 0;
  	List	   *final_rtable = NIL;
  	int			save_rel_array_size = 0;
  	RelOptInfo **save_rel_array = NULL;
  	AppendRelInfo **save_append_rel_array = NULL;
--- 1193,1209 ----
  {
  	Query	   *parse = root->parse;
  	int			top_parentRTindex = parse->resultRelation;
+ 	List	   *select_rtable;
+ 	List	   *select_appinfos;
+ 	List	   *child_appinfos;
+ 	List	   *old_child_rtis;
+ 	List	   *new_child_rtis;
  	Bitmapset  *subqueryRTindexes;
! 	Index		next_subquery_rti;
  	int			nominalRelation = -1;
  	Index		rootRelation = 0;
  	List	   *final_rtable = NIL;
+ 	List	   *final_rowmarks = NIL;
  	int			save_rel_array_size = 0;
  	RelOptInfo **save_rel_array = NULL;
  	AppendRelInfo **save_append_rel_array = NULL;
*************** inheritance_planner(PlannerInfo *root)
*** 1196,1209 ****
  	List	   *rowMarks;
  	RelOptInfo *final_rel;
  	ListCell   *lc;
  	Index		rti;
  	RangeTblEntry *parent_rte;
! 	PlannerInfo *parent_root;
! 	Query	   *parent_parse;
! 	Bitmapset  *parent_relids = bms_make_singleton(top_parentRTindex);
! 	PlannerInfo **parent_roots = NULL;
  
! 	Assert(parse->commandType != CMD_INSERT);
  
  	/*
  	 * We generate a modified instance of the original Query for each target
--- 1215,1229 ----
  	List	   *rowMarks;
  	RelOptInfo *final_rel;
  	ListCell   *lc;
+ 	ListCell   *lc2;
  	Index		rti;
  	RangeTblEntry *parent_rte;
! 	Bitmapset  *parent_relids;
! 	Query	  **parent_parses;
  
! 	/* Should only get here for UPDATE or DELETE */
! 	Assert(parse->commandType == CMD_UPDATE ||
! 		   parse->commandType == CMD_DELETE);
  
  	/*
  	 * We generate a modified instance of the original Query for each target
*************** inheritance_planner(PlannerInfo *root)
*** 1234,1272 ****
  	}
  
  	/*
- 	 * 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.
- 	 */
- 	modifiableARIindexes = NULL;
- 	if (subqueryRTindexes != NULL)
- 	{
- 		foreach(lc, root->append_rel_list)
- 		{
- 			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);
- 		}
- 	}
- 
- 	/*
  	 * If the parent RTE is a partitioned table, we should use that as the
  	 * nominal target relation, because the RTEs added for partitioned tables
  	 * (including the root parent) as child members of the inheritance set do
  	 * 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;
--- 1254,1267 ----
  	}
  
  	/*
  	 * If the parent RTE is a partitioned table, we should use that as the
  	 * nominal target relation, because the RTEs added for partitioned tables
  	 * (including the root parent) as child members of the inheritance set do
  	 * 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, parse->rtable);
! 	Assert(parent_rte->inh);
  	if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
  	{
  		nominalRelation = top_parentRTindex;
*************** inheritance_planner(PlannerInfo *root)
*** 1274,1321 ****
  	}
  
  	/*
! 	 * The PlannerInfo for each child is obtained by translating the relevant
! 	 * members of the PlannerInfo for its immediate parent, which we find
! 	 * using the parent_relid in its AppendRelInfo.  We save the PlannerInfo
! 	 * for each parent in an array indexed by relid for fast retrieval. Since
! 	 * the maximum number of parents is limited by the number of RTEs in the
! 	 * query, we use that number to allocate the array. An extra entry is
! 	 * needed since relids start from 1.
  	 */
! 	parent_roots = (PlannerInfo **) palloc0((list_length(parse->rtable) + 1) *
! 											sizeof(PlannerInfo *));
! 	parent_roots[top_parentRTindex] = root;
  
  	/*
  	 * And now we can get on with generating a plan for each child table.
  	 */
! 	foreach(lc, root->append_rel_list)
  	{
  		AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
  		PlannerInfo *subroot;
  		RangeTblEntry *child_rte;
  		RelOptInfo *sub_final_rel;
  		Path	   *subpath;
  
- 		/* append_rel_list contains all append rels; ignore others */
- 		if (!bms_is_member(appinfo->parent_relid, parent_relids))
- 			continue;
- 
  		/*
  		 * expand_inherited_rtentry() always processes a parent before any of
! 		 * that parent's children, so the parent_root for this relation should
! 		 * already be available.
  		 */
! 		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
  		 * propagation of information back to the main copy.
  		 */
  		subroot = makeNode(PlannerInfo);
! 		memcpy(subroot, parent_root, sizeof(PlannerInfo));
  
  		/*
  		 * Generate modified query with this rel as target.  We first apply
--- 1269,1486 ----
  	}
  
  	/*
! 	 * Before generating the real per-child-relation plans, do a cycle of
! 	 * planning as though the query were a SELECT.  The objective here is to
! 	 * find out which child relations need to be processed, using the same
! 	 * expansion and pruning logic as for a SELECT.  We'll then pull out the
! 	 * RangeTblEntry-s generated for the child rels, and make use of the
! 	 * AppendRelInfo entries for them to guide the real planning.  (This is
! 	 * rather inefficient; we could perhaps stop short of making a full Path
! 	 * tree.  But this whole function is inefficient and slated for
! 	 * destruction, so let's not contort query_planner for that.)
  	 */
! 	{
! 		PlannerInfo *subroot;
! 
! 		/*
! 		 * Flat-copy the PlannerInfo to prevent modification of the original.
! 		 */
! 		subroot = makeNode(PlannerInfo);
! 		memcpy(subroot, root, sizeof(PlannerInfo));
! 
! 		/*
! 		 * Make a deep copy of the parsetree for this planning cycle to mess
! 		 * around with, and change it to look like a SELECT.  (Hack alert: the
! 		 * target RTE still has updatedCols set if this is an UPDATE, so that
! 		 * expand_partitioned_rtentry will correctly update
! 		 * subroot->partColsUpdated.)
! 		 */
! 		subroot->parse = copyObject(root->parse);
! 
! 		subroot->parse->commandType = CMD_SELECT;
! 		subroot->parse->resultRelation = 0;
! 
! 		/*
! 		 * Ensure the subroot has its own copy of the original
! 		 * append_rel_list, since it'll be scribbled on.  (Note that at this
! 		 * point, the list only contains AppendRelInfos for flattened UNION
! 		 * ALL subqueries.)
! 		 */
! 		subroot->append_rel_list = copyObject(root->append_rel_list);
! 
! 		/*
! 		 * Better make a private copy of the rowMarks, too.
! 		 */
! 		subroot->rowMarks = copyObject(root->rowMarks);
! 
! 		/* There shouldn't be any OJ info to translate, as yet */
! 		Assert(subroot->join_info_list == NIL);
! 		/* and we haven't created PlaceHolderInfos, either */
! 		Assert(subroot->placeholder_list == NIL);
! 
! 		/* Generate Path(s) for accessing this result relation */
! 		grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
! 
! 		/* Extract the info we need. */
! 		select_rtable = subroot->parse->rtable;
! 		select_appinfos = subroot->append_rel_list;
! 
! 		/*
! 		 * We need to propagate partColsUpdated back, too.  (The later
! 		 * planning cycles will not set this because they won't run
! 		 * expand_partitioned_rtentry for the UPDATE target.)
! 		 */
! 		root->partColsUpdated = subroot->partColsUpdated;
! 	}
! 
! 	/*----------
! 	 * Since only one rangetable can exist in the final plan, we need to make
! 	 * sure that it contains all the RTEs needed for any child plan.  This is
! 	 * complicated by the need to use separate subquery RTEs for each child.
! 	 * We arrange the final rtable as follows:
! 	 * 1. All original rtable entries (with their original RT indexes).
! 	 * 2. All the relation RTEs generated for children of the target table.
! 	 * 3. Subquery RTEs for children after the first.  We need N * (K - 1)
! 	 *    RT slots for this, if there are N subqueries and K child tables.
! 	 * 4. Additional RTEs generated during the child planning runs, such as
! 	 *    children of inheritable RTEs other than the target table.
! 	 * We assume that each child planning run will create an identical set
! 	 * of type-4 RTEs.
! 	 *
! 	 * So the next thing to do is append the type-2 RTEs (the target table's
! 	 * children) to the original rtable.  We look through select_appinfos
! 	 * to find them.
! 	 *
! 	 * To identify which AppendRelInfos are relevant as we thumb through
! 	 * select_appinfos, we need to look for both direct and indirect children
! 	 * of top_parentRTindex, so we use a bitmap of known parent relids.
! 	 * expand_inherited_rtentry() always processes a parent before any of that
! 	 * parent's children, so we should see an intermediate parent before its
! 	 * children.
! 	 *----------
! 	 */
! 	child_appinfos = NIL;
! 	old_child_rtis = NIL;
! 	new_child_rtis = NIL;
! 	parent_relids = bms_make_singleton(top_parentRTindex);
! 	foreach(lc, select_appinfos)
! 	{
! 		AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
! 		RangeTblEntry *child_rte;
! 
! 		/* append_rel_list contains all append rels; ignore others */
! 		if (!bms_is_member(appinfo->parent_relid, parent_relids))
! 			continue;
! 
! 		/* remember relevant AppendRelInfos for use below */
! 		child_appinfos = lappend(child_appinfos, appinfo);
! 
! 		/* extract RTE for this child rel */
! 		child_rte = rt_fetch(appinfo->child_relid, select_rtable);
! 
! 		/* and append it to the original rtable */
! 		parse->rtable = lappend(parse->rtable, child_rte);
! 
! 		/* remember child's index in the SELECT rtable */
! 		old_child_rtis = lappend_int(old_child_rtis, appinfo->child_relid);
! 
! 		/* and its new index in the final rtable */
! 		new_child_rtis = lappend_int(new_child_rtis, list_length(parse->rtable));
! 
! 		/* if child is itself partitioned, update parent_relids */
! 		if (child_rte->inh)
! 		{
! 			Assert(child_rte->relkind == RELKIND_PARTITIONED_TABLE);
! 			parent_relids = bms_add_member(parent_relids, appinfo->child_relid);
! 		}
! 	}
! 
! 	/*
! 	 * It's possible that the RTIs we just assigned for the child rels in the
! 	 * final rtable are different from what they were in the SELECT query.
! 	 * Adjust the AppendRelInfos so that they will correctly map RT indexes to
! 	 * the final indexes.  We can do this left-to-right since no child rel's
! 	 * final RT index could be greater than what it had in the SELECT query.
! 	 */
! 	forboth(lc, old_child_rtis, lc2, new_child_rtis)
! 	{
! 		int			old_child_rti = lfirst_int(lc);
! 		int			new_child_rti = lfirst_int(lc2);
! 
! 		if (old_child_rti == new_child_rti)
! 			continue;			/* nothing to do */
! 
! 		Assert(old_child_rti > new_child_rti);
! 
! 		ChangeVarNodes((Node *) child_appinfos,
! 					   old_child_rti, new_child_rti, 0);
! 	}
! 
! 	/*
! 	 * Now set up rangetable entries for subqueries for additional children
! 	 * (the first child will just use the original ones).  These all have to
! 	 * look more or less real, or EXPLAIN will get unhappy; so we just make
! 	 * them all clones of the original subqueries.
! 	 */
! 	next_subquery_rti = list_length(parse->rtable) + 1;
! 	if (subqueryRTindexes != NULL)
! 	{
! 		int			n_children = list_length(child_appinfos);
! 
! 		while (n_children-- > 1)
! 		{
! 			int			oldrti = -1;
! 
! 			while ((oldrti = bms_next_member(subqueryRTindexes, oldrti)) >= 0)
! 			{
! 				RangeTblEntry *subqrte;
! 
! 				subqrte = rt_fetch(oldrti, parse->rtable);
! 				parse->rtable = lappend(parse->rtable, copyObject(subqrte));
! 			}
! 		}
! 	}
! 
! 	/*
! 	 * The query for each child is obtained by translating the query for its
! 	 * immediate parent, since the AppendRelInfo data we have shows deltas
! 	 * between parents and children.  We use the parent_parses array to
! 	 * remember the appropriate query trees.  This is indexed by parent relid.
! 	 * Since the maximum number of parents is limited by the number of RTEs in
! 	 * the SELECT query, we use that number to allocate the array.  An extra
! 	 * entry is needed since relids start from 1.
! 	 */
! 	parent_parses = (Query **) palloc0((list_length(select_rtable) + 1) *
! 									   sizeof(Query *));
! 	parent_parses[top_parentRTindex] = parse;
  
  	/*
  	 * And now we can get on with generating a plan for each child table.
  	 */
! 	foreach(lc, child_appinfos)
  	{
  		AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
+ 		Index		this_subquery_rti = next_subquery_rti;
+ 		Query	   *parent_parse;
  		PlannerInfo *subroot;
  		RangeTblEntry *child_rte;
  		RelOptInfo *sub_final_rel;
  		Path	   *subpath;
  
  		/*
  		 * expand_inherited_rtentry() always processes a parent before any of
! 		 * that parent's children, so the parent query for this relation
! 		 * should already be available.
  		 */
! 		parent_parse = parent_parses[appinfo->parent_relid];
! 		Assert(parent_parse != NULL);
  
  		/*
  		 * We need a working copy of the PlannerInfo so that we can control
  		 * propagation of information back to the main copy.
  		 */
  		subroot = makeNode(PlannerInfo);
! 		memcpy(subroot, root, sizeof(PlannerInfo));
  
  		/*
  		 * Generate modified query with this rel as target.  We first apply
*************** inheritance_planner(PlannerInfo *root)
*** 1324,1330 ****
  		 * then fool around with subquery RTEs.
  		 */
  		subroot->parse = (Query *)
! 			adjust_appendrel_attrs(parent_root,
  								   (Node *) parent_parse,
  								   1, &appinfo);
  
--- 1489,1495 ----
  		 * then fool around with subquery RTEs.
  		 */
  		subroot->parse = (Query *)
! 			adjust_appendrel_attrs(subroot,
  								   (Node *) parent_parse,
  								   1, &appinfo);
  
*************** inheritance_planner(PlannerInfo *root)
*** 1360,1368 ****
  		if (child_rte->inh)
  		{
  			Assert(child_rte->relkind == RELKIND_PARTITIONED_TABLE);
! 			parent_relids = bms_add_member(parent_relids, appinfo->child_relid);
! 			parent_roots[appinfo->child_relid] = subroot;
! 
  			continue;
  		}
  
--- 1525,1531 ----
  		if (child_rte->inh)
  		{
  			Assert(child_rte->relkind == RELKIND_PARTITIONED_TABLE);
! 			parent_parses[appinfo->child_relid] = subroot->parse;
  			continue;
  		}
  
*************** inheritance_planner(PlannerInfo *root)
*** 1383,1490 ****
  		 * is used elsewhere in the plan, so using the original parent RTE
  		 * would give rise to confusing use of multiple aliases in EXPLAIN
  		 * output for what the user will think is the "same" table.  OTOH,
! 		 * it's not a problem in the partitioned inheritance case, because the
! 		 * duplicate child RTE added for the parent does not appear anywhere
! 		 * else in the plan tree.
  		 */
  		if (nominalRelation < 0)
  			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
! 		 * valid-looking.
  		 */
! 		while (list_length(subroot->parse->rtable) < list_length(final_rtable))
! 			subroot->parse->rtable = lappend(subroot->parse->rtable,
! 											 makeNode(RangeTblEntry));
  
  		/*
! 		 * 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.
  		 */
  		if (final_rtable != NIL && subqueryRTindexes != NULL)
  		{
! 			ListCell   *lr;
  
! 			rti = 1;
! 			foreach(lr, parent_parse->rtable)
  			{
! 				RangeTblEntry *rte = lfirst_node(RangeTblEntry, lr);
! 
! 				if (bms_is_member(rti, subqueryRTindexes))
! 				{
! 					Index		newrti;
! 
! 					/*
! 					 * The RTE can't contain any references to its own RT
! 					 * index, except in its securityQuals, so we can save a
! 					 * few cycles by applying ChangeVarNodes to the rest of
! 					 * the rangetable before we append the RTE to it.
! 					 */
! 					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)
! 					{
! 						ListCell   *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);
! 						}
! 					}
! 					rte = copyObject(rte);
! 					ChangeVarNodes((Node *) rte->securityQuals, rti, newrti, 0);
! 					subroot->parse->rtable = lappend(subroot->parse->rtable,
! 													 rte);
! 				}
! 				rti++;
  			}
  		}
  
--- 1546,1583 ----
  		 * is used elsewhere in the plan, so using the original parent RTE
  		 * would give rise to confusing use of multiple aliases in EXPLAIN
  		 * output for what the user will think is the "same" table.  OTOH,
! 		 * it's not a problem in the partitioned inheritance case, because
! 		 * there is no duplicate RTE for the parent.
  		 */
  		if (nominalRelation < 0)
  			nominalRelation = appinfo->child_relid;
  
  		/*
! 		 * As above, each child plan run needs its own append_rel_list and
! 		 * rowmarks, which should start out as pristine copies of the
! 		 * originals.  There can't be any references to UPDATE/DELETE target
! 		 * rels in them; but there could be subquery references, which we'll
! 		 * fix up in a moment.
  		 */
! 		subroot->append_rel_list = copyObject(root->append_rel_list);
! 		subroot->rowMarks = copyObject(root->rowMarks);
  
  		/*
! 		 * If this isn't the first child Query, adjust Vars and jointree
! 		 * entries to reference the appropriate set of subquery RTEs.
  		 */
  		if (final_rtable != NIL && subqueryRTindexes != NULL)
  		{
! 			int			oldrti = -1;
  
! 			while ((oldrti = bms_next_member(subqueryRTindexes, oldrti)) >= 0)
  			{
! 				Index		newrti = next_subquery_rti++;
  
! 				ChangeVarNodes((Node *) subroot->parse, oldrti, newrti, 0);
! 				ChangeVarNodes((Node *) subroot->append_rel_list,
! 							   oldrti, newrti, 0);
! 				ChangeVarNodes((Node *) subroot->rowMarks, oldrti, newrti, 0);
  			}
  		}
  
*************** inheritance_planner(PlannerInfo *root)
*** 1514,1535 ****
  
  		/*
  		 * If this is the first non-excluded child, its post-planning rtable
! 		 * becomes the initial contents of final_rtable; otherwise, append
! 		 * just its modified subquery RTEs to final_rtable.
  		 */
  		if (final_rtable == NIL)
  			final_rtable = subroot->parse->rtable;
  		else
! 			final_rtable = list_concat(final_rtable,
! 									   list_copy_tail(subroot->parse->rtable,
! 													  list_length(final_rtable)));
  
  		/*
  		 * We need to collect all the RelOptInfos from all child plans into
  		 * the main PlannerInfo, since setrefs.c will need them.  We use the
! 		 * last child's simple_rel_array (previous ones are too short), so we
! 		 * have to propagate forward the RelOptInfos that were already built
! 		 * in previous children.
  		 */
  		Assert(subroot->simple_rel_array_size >= save_rel_array_size);
  		for (rti = 1; rti < save_rel_array_size; rti++)
--- 1607,1649 ----
  
  		/*
  		 * If this is the first non-excluded child, its post-planning rtable
! 		 * becomes the initial contents of final_rtable; otherwise, copy its
! 		 * modified subquery RTEs into final_rtable, to ensure we have sane
! 		 * copies of those.  Also save the first non-excluded child's version
! 		 * of the rowmarks list; we assume all children will end up with
! 		 * equivalent versions of that.
  		 */
  		if (final_rtable == NIL)
+ 		{
  			final_rtable = subroot->parse->rtable;
+ 			final_rowmarks = subroot->rowMarks;
+ 		}
  		else
! 		{
! 			Assert(list_length(final_rtable) ==
! 				   list_length(subroot->parse->rtable));
! 			if (subqueryRTindexes != NULL)
! 			{
! 				int			oldrti = -1;
! 
! 				while ((oldrti = bms_next_member(subqueryRTindexes, oldrti)) >= 0)
! 				{
! 					Index		newrti = this_subquery_rti++;
! 					RangeTblEntry *subqrte;
! 					ListCell   *newrticell;
! 
! 					subqrte = rt_fetch(newrti, subroot->parse->rtable);
! 					newrticell = list_nth_cell(final_rtable, newrti - 1);
! 					lfirst(newrticell) = subqrte;
! 				}
! 			}
! 		}
  
  		/*
  		 * We need to collect all the RelOptInfos from all child plans into
  		 * the main PlannerInfo, since setrefs.c will need them.  We use the
! 		 * last child's simple_rel_array, so we have to propagate forward the
! 		 * RelOptInfos that were already built in previous children.
  		 */
  		Assert(subroot->simple_rel_array_size >= save_rel_array_size);
  		for (rti = 1; rti < save_rel_array_size; rti++)
*************** inheritance_planner(PlannerInfo *root)
*** 1543,1549 ****
  		save_rel_array = subroot->simple_rel_array;
  		save_append_rel_array = subroot->append_rel_array;
  
! 		/* Make sure any initplans from this rel get into the outer list */
  		root->init_plans = subroot->init_plans;
  
  		/* Build list of sub-paths */
--- 1657,1667 ----
  		save_rel_array = subroot->simple_rel_array;
  		save_append_rel_array = subroot->append_rel_array;
  
! 		/*
! 		 * Make sure any initplans from this rel get into the outer list. Note
! 		 * we're effectively assuming all children generate the same
! 		 * init_plans.
! 		 */
  		root->init_plans = subroot->init_plans;
  
  		/* Build list of sub-paths */
*************** inheritance_planner(PlannerInfo *root)
*** 1626,1631 ****
--- 1744,1752 ----
  
  			root->simple_rte_array[rti++] = rte;
  		}
+ 
+ 		/* Put back adjusted rowmarks, too */
+ 		root->rowMarks = final_rowmarks;
  	}
  
  	/*
*************** plan_create_index_workers(Oid tableOid, 
*** 6127,6135 ****
  	/*
  	 * Build a minimal RTE.
  	 *
! 	 * Set the target's table to be an inheritance parent.  This is a kludge
! 	 * that prevents problems within get_relation_info(), which does not
! 	 * expect that any IndexOptInfo is currently undergoing REINDEX.
  	 */
  	rte = makeNode(RangeTblEntry);
  	rte->rtekind = RTE_RELATION;
--- 6248,6257 ----
  	/*
  	 * Build a minimal RTE.
  	 *
! 	 * Mark the RTE with inh = true.  This is a kludge to prevent
! 	 * get_relation_info() from fetching index info, which is necessary
! 	 * because it does not expect that any IndexOptInfo is currently
! 	 * undergoing REINDEX.
  	 */
  	rte = makeNode(RangeTblEntry);
  	rte->rtekind = RTE_RELATION;
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 5392d1a..66e6ad9 100644
*** a/src/backend/optimizer/prep/preptlist.c
--- b/src/backend/optimizer/prep/preptlist.c
*************** preprocess_targetlist(PlannerInfo *root)
*** 121,127 ****
  	/*
  	 * Add necessary junk columns for rowmarked rels.  These values are needed
  	 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
! 	 * rechecking.  See comments for PlanRowMark in plannodes.h.
  	 */
  	foreach(lc, root->rowMarks)
  	{
--- 121,129 ----
  	/*
  	 * Add necessary junk columns for rowmarked rels.  These values are needed
  	 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
! 	 * rechecking.  See comments for PlanRowMark in plannodes.h.  If you
! 	 * change this stanza, see also expand_inherited_rtentry(), which has to
! 	 * be able to add on junk columns equivalent to these.
  	 */
  	foreach(lc, root->rowMarks)
  	{
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 1d1e506..6b5709a 100644
*** a/src/backend/optimizer/util/inherit.c
--- b/src/backend/optimizer/util/inherit.c
***************
*** 18,127 ****
  #include "access/table.h"
  #include "catalog/partition.h"
  #include "catalog/pg_inherits.h"
  #include "miscadmin.h"
  #include "optimizer/appendinfo.h"
  #include "optimizer/inherit.h"
  #include "optimizer/planner.h"
  #include "optimizer/prep.h"
  #include "partitioning/partdesc.h"
  #include "utils/rel.h"
  
  
! static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
! 						 Index rti);
! 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);
  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.
-  */
- void
- expand_inherited_tables(PlannerInfo *root)
- {
- 	Index		nrtes;
- 	Index		rti;
- 	ListCell   *rl;
- 
- 	/*
- 	 * 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.
- 	 */
- 	nrtes = list_length(root->parse->rtable);
- 	rl = list_head(root->parse->rtable);
- 	for (rti = 1; rti <= nrtes; rti++)
- 	{
- 		RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
- 
- 		expand_inherited_rtentry(root, rte, rti);
- 		rl = lnext(rl);
- 	}
- }
- 
- /*
   * 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.
   *
!  * 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
!  * table, but with inh = false, to represent the parent table in its role
!  * as a simple member of the inheritance set.
   *
!  * A childless table is never considered to be an inheritance set. For
!  * regular inheritance, a parent RTE must always have at least two associated
!  * AppendRelInfos: one corresponding to the parent table as a simple member of
!  * the inheritance set and one or more corresponding to the actual children.
!  * (But a partitioned table might have only one associated AppendRelInfo,
!  * since it's not itself scanned and hence doesn't need a second RTE to
!  * represent itself as a member of the set.)
   */
! static void
! expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
  {
  	Oid			parentOID;
- 	PlanRowMark *oldrc;
  	Relation	oldrelation;
  	LOCKMODE	lockmode;
! 	List	   *inhOIDs;
! 	ListCell   *l;
  
! 	/* 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 */
  	parentOID = rte->relid;
! 	if (!has_subclass(parentOID))
! 	{
! 		/* Clear flag before returning */
! 		rte->inh = false;
! 		return;
! 	}
  
  	/*
  	 * The rewriter should already have obtained an appropriate lock on each
--- 18,107 ----
  #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/inherit.h"
+ #include "optimizer/optimizer.h"
+ #include "optimizer/pathnode.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_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
  						   RangeTblEntry *parentrte,
  						   Index parentRTindex, Relation parentrel,
! 						   PlanRowMark *top_parentrc, LOCKMODE lockmode);
  static void expand_single_inheritance_child(PlannerInfo *root,
  								RangeTblEntry *parentrte,
  								Index parentRTindex, Relation parentrel,
  								PlanRowMark *top_parentrc, Relation childrel,
! 								RangeTblEntry **childrte_p,
  								Index *childRTindex_p);
  static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
  					List *translated_vars);
+ static void expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel,
+ 						  RangeTblEntry *rte, Index rti);
  
  
  /*
   * expand_inherited_rtentry
!  *		Expand a rangetable entry that has the "inh" bit set.
   *
!  * "inh" is only allowed in two cases: RELATION and SUBQUERY RTEs.
   *
!  * "inh" on a plain RELATION RTE means that it is a partitioned table or the
!  * parent of a traditional-inheritance set.  In this case we must add entries
!  * for all the interesting child tables to the query's rangetable, and build
!  * additional planner data structures for them, including RelOptInfos,
!  * AppendRelInfos, and possibly PlanRowMarks.
!  *
!  * Note that the original RTE is considered to represent the whole inheritance
!  * set.  In the case of traditional inheritance, the first of the generated
!  * RTEs is an RTE for the same table, but with inh = false, to represent the
!  * parent table in its role as a simple member of the inheritance set.  For
!  * partitioning, we don't need a second RTE because the partitioned table
!  * itself has no data and need not be scanned.
!  *
!  * "inh" on a SUBQUERY RTE means that it's the parent of a UNION ALL group,
!  * which is treated as an appendrel similarly to inheritance cases; however,
!  * we already made RTEs and AppendRelInfos for the subqueries.  We only need
!  * to build RelOptInfos for them, which is done by expand_appendrel_subquery.
   */
! void
! expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel,
! 						 RangeTblEntry *rte, Index rti)
  {
  	Oid			parentOID;
  	Relation	oldrelation;
  	LOCKMODE	lockmode;
! 	PlanRowMark *oldrc;
! 	bool		old_isParent = false;
! 	int			old_allMarkTypes = 0;
  
! 	Assert(rte->inh);			/* else caller error */
! 
! 	if (rte->rtekind == RTE_SUBQUERY)
  	{
! 		expand_appendrel_subquery(root, rel, rte, rti);
  		return;
  	}
! 
! 	Assert(rte->rtekind == RTE_RELATION);
! 
  	parentOID = rte->relid;
! 
! 	/*
! 	 * We used to check has_subclass() here, but there's no longer any need
! 	 * to, because subquery_planner already did.
! 	 */
  
  	/*
  	 * The rewriter should already have obtained an appropriate lock on each
*************** expand_inherited_rtentry(PlannerInfo *ro
*** 141,147 ****
--- 121,132 ----
  	 */
  	oldrc = get_plan_rowmark(root->rowMarks, rti);
  	if (oldrc)
+ 	{
+ 		old_isParent = oldrc->isParent;
  		oldrc->isParent = true;
+ 		/* Save initial value of allMarkTypes before children add to it */
+ 		old_allMarkTypes = oldrc->allMarkTypes;
+ 	}
  
  	/* Scan the inheritance set and expand it */
  	if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
*************** expand_inherited_rtentry(PlannerInfo *ro
*** 151,167 ****
  		 */
  		Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
  
- 		if (root->glob->partition_directory == NULL)
- 			root->glob->partition_directory =
- 				CreatePartitionDirectory(CurrentMemoryContext);
- 
  		/*
! 		 * If this table has partitions, recursively expand and lock them.
! 		 * While at it, also extract the partition key columns of all the
! 		 * partitioned tables.
  		 */
! 		expand_partitioned_rtentry(root, rte, rti, oldrelation, oldrc,
! 								   lockmode, &root->append_rel_list);
  	}
  	else
  	{
--- 136,147 ----
  		 */
  		Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
  
  		/*
! 		 * Recursively expand and lock the partitions.  While at it, also
! 		 * extract the partition key columns of all the partitioned tables.
  		 */
! 		expand_partitioned_rtentry(root, rel, rte, rti,
! 								   oldrelation, oldrc, lockmode);
  	}
  	else
  	{
*************** expand_inherited_rtentry(PlannerInfo *ro
*** 170,194 ****
  		 * that partitioned tables are not allowed to have inheritance
  		 * children, so it's not possible for both cases to apply.)
  		 */
! 		List	   *appinfos = NIL;
! 		RangeTblEntry *childrte;
! 		Index		childRTindex;
  
  		/* 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 above has_subclass() check, if the
! 		 * table once had a child but no longer does.
  		 */
! 		if (list_length(inhOIDs) < 2)
! 		{
! 			/* Clear flag before returning */
! 			rte->inh = false;
! 			heap_close(oldrelation, NoLock);
! 			return;
! 		}
  
  		/*
  		 * Expand inheritance children in the order the OIDs were returned by
--- 150,174 ----
  		 * that partitioned tables are not allowed to have inheritance
  		 * children, so it's not possible for both cases to apply.)
  		 */
! 		List	   *inhOIDs;
! 		ListCell   *l;
  
  		/* Scan for all members of inheritance set, acquire needed locks */
  		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
  
  		/*
! 		 * We used to special-case the situation where the table no longer has
! 		 * any children, by clearing rte->inh and exiting.  That no longer
! 		 * works, because this function doesn't get run until after decisions
! 		 * have been made that depend on rte->inh.  We have to treat such
! 		 * situations as normal inheritance.  The table itself should always
! 		 * have been found, though.
  		 */
! 		Assert(inhOIDs != NIL);
! 		Assert(linitial_oid(inhOIDs) == parentOID);
! 
! 		/* Expand simple_rel_array and friends to hold child objects. */
! 		expand_planner_arrays(root, list_length(inhOIDs));
  
  		/*
  		 * Expand inheritance children in the order the OIDs were returned by
*************** expand_inherited_rtentry(PlannerInfo *ro
*** 198,203 ****
--- 178,185 ----
  		{
  			Oid			childOID = lfirst_oid(l);
  			Relation	newrelation;
+ 			RangeTblEntry *childrte;
+ 			Index		childRTindex;
  
  			/* Open rel if needed; we already have required locks */
  			if (childOID != parentOID)
*************** expand_inherited_rtentry(PlannerInfo *ro
*** 217,245 ****
  				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);
  		}
  
  		/*
! 		 * 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);
--- 199,276 ----
  				continue;
  			}
  
! 			/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
! 			expand_single_inheritance_child(root, rte, rti, oldrelation,
! 											oldrc, newrelation,
! 											&childrte, &childRTindex);
! 
! 			/* Create the otherrel RelOptInfo too. */
! 			(void) build_simple_rel(root, childRTindex, rel);
  
  			/* Close child relations, but keep locks */
  			if (childOID != parentOID)
  				table_close(newrelation, NoLock);
  		}
+ 	}
+ 
+ 	/*
+ 	 * Some children might require different mark types, which would've been
+ 	 * reported into oldrc.  If so, add relevant entries to the top-level
+ 	 * targetlist and update parent rel's reltarget.  This should match what
+ 	 * preprocess_targetlist() would have added if the mark types had been
+ 	 * requested originally.
+ 	 */
+ 	if (oldrc)
+ 	{
+ 		int			new_allMarkTypes = oldrc->allMarkTypes;
+ 		Var		   *var;
+ 		TargetEntry *tle;
+ 		char		resname[32];
+ 		List	   *newvars = NIL;
+ 
+ 		/* The old PlanRowMark should already have necessitated adding TID */
+ 		Assert(old_allMarkTypes & ~(1 << ROW_MARK_COPY));
+ 
+ 		/* Add whole-row junk Var if needed, unless we had it already */
+ 		if ((new_allMarkTypes & (1 << ROW_MARK_COPY)) &&
+ 			!(old_allMarkTypes & (1 << ROW_MARK_COPY)))
+ 		{
+ 			var = makeWholeRowVar(planner_rt_fetch(oldrc->rti, root),
+ 								  oldrc->rti,
+ 								  0,
+ 								  false);
+ 			snprintf(resname, sizeof(resname), "wholerow%u", oldrc->rowmarkId);
+ 			tle = makeTargetEntry((Expr *) var,
+ 								  list_length(root->processed_tlist) + 1,
+ 								  pstrdup(resname),
+ 								  true);
+ 			root->processed_tlist = lappend(root->processed_tlist, tle);
+ 			newvars = lappend(newvars, var);
+ 		}
+ 
+ 		/* Add tableoid junk Var, unless we had it already */
+ 		if (!old_isParent)
+ 		{
+ 			var = makeVar(oldrc->rti,
+ 						  TableOidAttributeNumber,
+ 						  OIDOID,
+ 						  -1,
+ 						  InvalidOid,
+ 						  0);
+ 			snprintf(resname, sizeof(resname), "tableoid%u", oldrc->rowmarkId);
+ 			tle = makeTargetEntry((Expr *) var,
+ 								  list_length(root->processed_tlist) + 1,
+ 								  pstrdup(resname),
+ 								  true);
+ 			root->processed_tlist = lappend(root->processed_tlist, tle);
+ 			newvars = lappend(newvars, var);
+ 		}
  
  		/*
! 		 * Add the newly added Vars to parent's reltarget.  We needn't worry
! 		 * about the children's reltargets, they'll be made later.
  		 */
! 		add_vars_to_targetlist(root, newvars, bms_make_singleton(0), false);
  	}
  
  	table_close(oldrelation, NoLock);
*************** expand_inherited_rtentry(PlannerInfo *ro
*** 250,275 ****
   *		Recursively expand an RTE for a partitioned table.
   */
  static void
! expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
  						   Index parentRTindex, Relation parentrel,
! 						   PlanRowMark *top_parentrc, LOCKMODE lockmode,
! 						   List **appinfos)
  {
- 	int			i;
- 	RangeTblEntry *childrte;
- 	Index		childRTindex;
  	PartitionDesc partdesc;
  
  	partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
  										parentrel);
  
- 	check_stack_depth();
- 
  	/* A partitioned table should always have a partition descriptor. */
  	Assert(partdesc);
  
- 	Assert(parentrte->inh);
- 
  	/*
  	 * Note down whether any partition key cols are being updated. Though it's
  	 * the root partitioned table's updatedCols we are interested in, we
--- 281,306 ----
   *		Recursively expand an RTE for a partitioned table.
   */
  static void
! expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
! 						   RangeTblEntry *parentrte,
  						   Index parentRTindex, Relation parentrel,
! 						   PlanRowMark *top_parentrc, LOCKMODE lockmode)
  {
  	PartitionDesc partdesc;
+ 	Bitmapset  *live_parts;
+ 	int			num_live_parts;
+ 	int			i;
+ 
+ 	check_stack_depth();
+ 
+ 	Assert(parentrte->inh);
  
  	partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
  										parentrel);
  
  	/* A partitioned table should always have a partition descriptor. */
  	Assert(partdesc);
  
  	/*
  	 * Note down whether any partition key cols are being updated. Though it's
  	 * the root partitioned table's updatedCols we are interested in, we
*************** expand_partitioned_rtentry(PlannerInfo *
*** 281,305 ****
  		root->partColsUpdated =
  			has_partition_attrs(parentrel, parentrte->updatedCols, NULL);
  
! 	/*
! 	 * If the partitioned table has no partitions, treat this as the
! 	 * non-inheritance case.
! 	 */
  	if (partdesc->nparts == 0)
- 	{
- 		parentrte->inh = false;
  		return;
- 	}
  
  	/*
! 	 * Create a child RTE for each partition.  Note that unlike traditional
! 	 * inheritance, we don't need a child RTE for the partitioned table
! 	 * itself, because it's not going to be scanned.
  	 */
! 	for (i = 0; i < partdesc->nparts; i++)
  	{
  		Oid			childOID = partdesc->oids[i];
  		Relation	childrel;
  
  		/* Open rel, acquiring required locks */
  		childrel = table_open(childOID, lockmode);
--- 312,356 ----
  		root->partColsUpdated =
  			has_partition_attrs(parentrel, parentrte->updatedCols, NULL);
  
! 	/* Nothing further to do here if there are no partitions. */
  	if (partdesc->nparts == 0)
  		return;
  
  	/*
! 	 * Perform partition pruning using restriction clauses assigned to parent
! 	 * relation.  live_parts will contain PartitionDesc indexes of partitions
! 	 * that survive pruning.  Below, we will initialize child objects for the
! 	 * surviving partitions.
  	 */
! 	live_parts = prune_append_rel_partitions(relinfo);
! 
! 	/* Expand simple_rel_array and friends to hold child objects. */
! 	num_live_parts = bms_num_members(live_parts);
! 	if (num_live_parts > 0)
! 		expand_planner_arrays(root, num_live_parts);
! 
! 	/*
! 	 * We also store partition RelOptInfo pointers in the parent relation.
! 	 * Since we're palloc0'ing, slots corresponding to pruned partitions will
! 	 * contain NULL.
! 	 */
! 	Assert(relinfo->part_rels == NULL);
! 	relinfo->part_rels = (RelOptInfo **)
! 		palloc0(relinfo->nparts * sizeof(RelOptInfo *));
! 
! 	/*
! 	 * Create a child RTE for each live partition.  Note that unlike
! 	 * traditional inheritance, we don't need a child RTE for the partitioned
! 	 * table itself, because it's not going to be scanned.
! 	 */
! 	i = -1;
! 	while ((i = bms_next_member(live_parts, i)) >= 0)
  	{
  		Oid			childOID = partdesc->oids[i];
  		Relation	childrel;
+ 		RangeTblEntry *childrte;
+ 		Index		childRTindex;
+ 		RelOptInfo *childrelinfo;
  
  		/* Open rel, acquiring required locks */
  		childrel = table_open(childOID, lockmode);
*************** expand_partitioned_rtentry(PlannerInfo *
*** 312,326 ****
  		if (RELATION_IS_OTHER_TEMP(childrel))
  			elog(ERROR, "temporary relation from another session found as partition");
  
  		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 */
  		table_close(childrel, NoLock);
--- 363,382 ----
  		if (RELATION_IS_OTHER_TEMP(childrel))
  			elog(ERROR, "temporary relation from another session found as partition");
  
+ 		/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
  		expand_single_inheritance_child(root, parentrte, parentRTindex,
  										parentrel, top_parentrc, childrel,
! 										&childrte, &childRTindex);
! 
! 		/* Create the otherrel RelOptInfo too. */
! 		childrelinfo = build_simple_rel(root, childRTindex, relinfo);
! 		relinfo->part_rels[i] = childrelinfo;
  
  		/* If this child is itself partitioned, recurse */
  		if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
! 			expand_partitioned_rtentry(root, childrelinfo,
! 									   childrte, childRTindex,
! 									   childrel, top_parentrc, lockmode);
  
  		/* Close child relation, but keep locks */
  		table_close(childrel, NoLock);
*************** static void
*** 351,357 ****
  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)
  {
  	Query	   *parse = root->parse;
--- 407,413 ----
  expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
  								Index parentRTindex, Relation parentrel,
  								PlanRowMark *top_parentrc, Relation childrel,
! 								RangeTblEntry **childrte_p,
  								Index *childRTindex_p)
  {
  	Query	   *parse = root->parse;
*************** expand_single_inheritance_child(PlannerI
*** 363,370 ****
  
  	/*
  	 * 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
--- 419,426 ----
  
  	/*
  	 * 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,
! 	 * relkind, and inh for the child.  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
*************** expand_single_inheritance_child(PlannerI
*** 396,402 ****
  	 */
  	appinfo = make_append_rel_info(parentrel, childrel,
  								   parentRTindex, childRTindex);
! 	*appinfos = lappend(*appinfos, appinfo);
  
  	/*
  	 * Translate the column permissions bitmaps to the child's attnums (we
--- 452,458 ----
  	 */
  	appinfo = make_append_rel_info(parentrel, childrel,
  								   parentRTindex, childRTindex);
! 	root->append_rel_list = lappend(root->append_rel_list, appinfo);
  
  	/*
  	 * Translate the column permissions bitmaps to the child's attnums (we
*************** expand_single_inheritance_child(PlannerI
*** 418,423 ****
--- 474,489 ----
  	}
  
  	/*
+ 	 * Store the RTE and appinfo in the respective PlannerInfo arrays, which
+ 	 * the caller must already have allocated space for.
+ 	 */
+ 	Assert(childRTindex < root->simple_rel_array_size);
+ 	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;
+ 
+ 	/*
  	 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
  	 */
  	if (top_parentrc)
*************** expand_single_inheritance_child(PlannerI
*** 437,443 ****
  		/*
  		 * We mark RowMarks for partitioned child tables as parent RowMarks so
  		 * that the executor ignores them (except their existence means that
! 		 * the child tables be locked using appropriate mode).
  		 */
  		childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
  
--- 503,509 ----
  		/*
  		 * We mark RowMarks for partitioned child tables as parent RowMarks so
  		 * that the executor ignores them (except their existence means that
! 		 * the child tables will be locked using the appropriate mode).
  		 */
  		childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
  
*************** translate_col_privs(const Bitmapset *par
*** 499,501 ****
--- 565,733 ----
  
  	return child_privs;
  }
+ 
+ /*
+  * expand_appendrel_subquery
+  *		Add "other rel" RelOptInfos for the children of an appendrel baserel
+  *
+  * "rel" is a subquery relation that has the rte->inh flag set, meaning it
+  * is a UNION ALL subquery that's been flattened into an appendrel, with
+  * child subqueries listed in root->append_rel_list.  We need to build
+  * a RelOptInfo for each child relation so that we can plan scans on them.
+  */
+ static void
+ expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel,
+ 						  RangeTblEntry *rte, Index rti)
+ {
+ 	ListCell   *l;
+ 
+ 	foreach(l, root->append_rel_list)
+ 	{
+ 		AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
+ 		Index		childRTindex = appinfo->child_relid;
+ 		RangeTblEntry *childrte;
+ 		RelOptInfo *childrel;
+ 
+ 		/* append_rel_list contains all append rels; ignore others */
+ 		if (appinfo->parent_relid != rti)
+ 			continue;
+ 
+ 		/* find the child RTE, which should already exist */
+ 		Assert(childRTindex < root->simple_rel_array_size);
+ 		childrte = root->simple_rte_array[childRTindex];
+ 		Assert(childrte != NULL);
+ 
+ 		/* Build the child RelOptInfo. */
+ 		childrel = build_simple_rel(root, childRTindex, rel);
+ 
+ 		/* Child may itself be an inherited rel, either table or subquery. */
+ 		if (childrte->inh)
+ 			expand_inherited_rtentry(root, childrel, childrte, childRTindex);
+ 	}
+ }
+ 
+ 
+ /*
+  * apply_child_basequals
+  *		Populate childrel's base restriction quals from parent rel's quals,
+  *		translating them using appinfo.
+  *
+  * If any of the resulting clauses evaluate to constant false or NULL, we
+  * return false and don't apply any quals.  Caller should mark the relation as
+  * a dummy rel in this case, since it doesn't need to be scanned.
+  */
+ bool
+ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
+ 					  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, parentrel->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_single_inheritance_child().)  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;
+ }
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index a0a7c54..2946e50 100644
*** a/src/backend/optimizer/util/plancat.c
--- b/src/backend/optimizer/util/plancat.c
*************** set_relation_partition_info(PlannerInfo 
*** 2094,2100 ****
  {
  	PartitionDesc partdesc;
  
! 	Assert(relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
  
  	partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
  										relation);
--- 2094,2103 ----
  {
  	PartitionDesc partdesc;
  
! 	/* Create the PartitionDirectory infrastructure if we didn't already */
! 	if (root->glob->partition_directory == NULL)
! 		root->glob->partition_directory =
! 			CreatePartitionDirectory(CurrentMemoryContext);
  
  	partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
  										relation);
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 0d40b8d..f86f39c 100644
*** a/src/backend/optimizer/util/relnode.c
--- b/src/backend/optimizer/util/relnode.c
***************
*** 20,30 ****
  #include "optimizer/appendinfo.h"
  #include "optimizer/clauses.h"
  #include "optimizer/cost.h"
  #include "optimizer/pathnode.h"
  #include "optimizer/paths.h"
  #include "optimizer/placeholder.h"
  #include "optimizer/plancat.h"
- #include "optimizer/prep.h"
  #include "optimizer/restrictinfo.h"
  #include "optimizer/tlist.h"
  #include "partitioning/partbounds.h"
--- 20,30 ----
  #include "optimizer/appendinfo.h"
  #include "optimizer/clauses.h"
  #include "optimizer/cost.h"
+ #include "optimizer/inherit.h"
  #include "optimizer/pathnode.h"
  #include "optimizer/paths.h"
  #include "optimizer/placeholder.h"
  #include "optimizer/plancat.h"
  #include "optimizer/restrictinfo.h"
  #include "optimizer/tlist.h"
  #include "partitioning/partbounds.h"
*************** setup_append_rel_array(PlannerInfo *root
*** 132,137 ****
--- 132,180 ----
  }
  
  /*
+  * expand_planner_arrays
+  *		Expand the PlannerInfo's per-RTE arrays by add_size members
+  *		and initialize the newly added entries to NULLs
+  */
+ 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;
+ 
+ 	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.
   */
*************** build_simple_rel(PlannerInfo *root, int 
*** 281,373 ****
  			break;
  	}
  
- 	/* Save the finished struct in the query's simple_rel_array */
- 	root->simple_rel_array[relid] = rel;
- 
  	/*
  	 * This is a convenient spot at which to note whether rels participating
  	 * in the query have any securityQuals attached.  If so, increase
  	 * root->qual_security_level to ensure it's larger than the maximum
! 	 * security level needed for securityQuals.
  	 */
  	if (rte->securityQuals)
  		root->qual_security_level = Max(root->qual_security_level,
  										list_length(rte->securityQuals));
  
- 	return rel;
- }
- 
- /*
-  * add_appendrel_other_rels
-  *		Add "other rel" RelOptInfos for the children of an appendrel baserel
-  *
-  * "rel" is a relation that (still) has the rte->inh flag set, meaning it
-  * has appendrel children listed in root->append_rel_list.  We need to build
-  * a RelOptInfo for each child relation so that we can plan scans on them.
-  * (The parent relation might be a partitioned table, a table with
-  * traditional inheritance children, or a flattened UNION ALL subquery.)
-  */
- void
- add_appendrel_other_rels(PlannerInfo *root, RelOptInfo *rel, Index rti)
- {
- 	int			cnt_parts = 0;
- 	ListCell   *l;
- 
  	/*
! 	 * If rel is a partitioned table, then we also need to build a part_rels
! 	 * array so that the child RelOptInfos can be conveniently accessed from
! 	 * the parent.
  	 */
! 	if (rel->part_scheme != NULL)
! 	{
! 		Assert(rel->nparts > 0);
! 		rel->part_rels = (RelOptInfo **)
! 			palloc0(sizeof(RelOptInfo *) * rel->nparts);
! 	}
! 
! 	foreach(l, root->append_rel_list)
  	{
! 		AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
! 		Index		childRTindex = appinfo->child_relid;
! 		RangeTblEntry *childrte;
! 		RelOptInfo *childrel;
! 
! 		/* append_rel_list contains all append rels; ignore others */
! 		if (appinfo->parent_relid != rti)
! 			continue;
! 
! 		/* find the child RTE, which should already exist */
! 		Assert(childRTindex < root->simple_rel_array_size);
! 		childrte = root->simple_rte_array[childRTindex];
! 		Assert(childrte != NULL);
! 
! 		/* build child RelOptInfo, and add to main query data structures */
! 		childrel = build_simple_rel(root, childRTindex, rel);
! 
! 		/*
! 		 * If rel is a partitioned table, fill in the part_rels array.  The
! 		 * order in which child tables appear in append_rel_list is the same
! 		 * as the order in which they appear in the parent's PartitionDesc, so
! 		 * assigning partitions like this works.
! 		 */
! 		if (rel->part_scheme != NULL)
! 		{
! 			Assert(cnt_parts < rel->nparts);
! 			rel->part_rels[cnt_parts++] = childrel;
! 		}
  
! 		/* Child may itself be an inherited relation. */
! 		if (childrte->inh)
  		{
! 			/* Only relation and subquery RTEs can have children. */
! 			Assert(childrte->rtekind == RTE_RELATION ||
! 				   childrte->rtekind == RTE_SUBQUERY);
! 			add_appendrel_other_rels(root, childrel, childRTindex);
  		}
  	}
  
! 	/* We should have filled all of the part_rels array if it's partitioned */
! 	Assert(cnt_parts == rel->nparts);
  }
  
  /*
--- 324,365 ----
  			break;
  	}
  
  	/*
  	 * This is a convenient spot at which to note whether rels participating
  	 * in the query have any securityQuals attached.  If so, increase
  	 * root->qual_security_level to ensure it's larger than the maximum
! 	 * security level needed for securityQuals.  (Must do this before we call
! 	 * apply_child_basequals, else we'll hit an Assert therein.)
  	 */
  	if (rte->securityQuals)
  		root->qual_security_level = Max(root->qual_security_level,
  										list_length(rte->securityQuals));
  
  	/*
! 	 * Copy the parent's quals to the child, with appropriate substitution of
! 	 * variables.  If any constant false or NULL clauses turn up, we can mark
! 	 * the child as dummy right away.  (We must do this immediately so that
! 	 * pruning works correctly when recursing in expand_partitioned_rtentry.)
  	 */
! 	if (parent)
  	{
! 		AppendRelInfo *appinfo = root->append_rel_array[relid];
  
! 		Assert(appinfo != NULL);
! 		if (!apply_child_basequals(root, parent, rel, rte, appinfo))
  		{
! 			/*
! 			 * Some restriction clause reduced to constant FALSE or NULL after
! 			 * substitution, so this child need not be scanned.
! 			 */
! 			mark_dummy_rel(rel);
  		}
  	}
  
! 	/* Save the finished struct in the query's simple_rel_array */
! 	root->simple_rel_array[relid] = rel;
! 
! 	return rel;
  }
  
  /*
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index af3f911..aecea82 100644
*** a/src/backend/partitioning/partprune.c
--- b/src/backend/partitioning/partprune.c
***************
*** 45,50 ****
--- 45,51 ----
  #include "nodes/makefuncs.h"
  #include "nodes/nodeFuncs.h"
  #include "optimizer/appendinfo.h"
+ #include "optimizer/cost.h"
  #include "optimizer/optimizer.h"
  #include "optimizer/pathnode.h"
  #include "parser/parsetree.h"
*************** make_partitionedrel_pruneinfo(PlannerInf
*** 474,491 ****
  		 * is, not pruned already).
  		 */
  		subplan_map = (int *) palloc(nparts * sizeof(int));
  		subpart_map = (int *) palloc(nparts * sizeof(int));
! 		relid_map = (Oid *) palloc(nparts * sizeof(Oid));
  		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;
  
! 			subplan_map[i] = subplanidx;
! 			subpart_map[i] = subpartidx;
  			relid_map[i] = planner_rt_fetch(partrel->relid, root)->relid;
  			if (subplanidx >= 0)
  			{
--- 475,498 ----
  		 * 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(Oid));
! 		relid_map = (Oid *) palloc0(nparts * sizeof(Oid));
  		present_parts = NULL;
  
  		for (i = 0; i < nparts; i++)
  		{
  			RelOptInfo *partrel = subpart->part_rels[i];
! 			int			subplanidx;
! 			int			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;
  			relid_map[i] = planner_rt_fetch(partrel->relid, root)->relid;
  			if (subplanidx >= 0)
  			{
*************** gen_partprune_steps(RelOptInfo *rel, Lis
*** 567,589 ****
  
  /*
   * prune_append_rel_partitions
!  *		Returns RT indexes 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
  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 */
--- 574,593 ----
  
  /*
   * prune_append_rel_partitions
!  *		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.
   */
! Bitmapset *
  prune_append_rel_partitions(RelOptInfo *rel)
  {
  	List	   *clauses = rel->baserestrictinfo;
  	List	   *pruning_steps;
  	bool		contradictory;
  	PartitionPruneContext context;
  
  	Assert(rel->part_scheme != NULL);
  
  	/* If there are no partitions, return the empty set */
*************** prune_append_rel_partitions(RelOptInfo *
*** 591,596 ****
--- 595,607 ----
  		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.
  	 */
*************** prune_append_rel_partitions(RelOptInfo *
*** 617,631 ****
  	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;
  }
  
  /*
--- 628,634 ----
  	context.evalexecparams = false;
  
  	/* Actual pruning happens here. */
! 	return get_matching_partitions(&context, pruning_steps);
  }
  
  /*
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 24740c3..1cce762 100644
*** a/src/include/nodes/plannodes.h
--- b/src/include/nodes/plannodes.h
*************** typedef struct PartitionPruneInfo
*** 1103,1108 ****
--- 1103,1109 ----
   * it is -1 if the partition is a leaf or has been pruned.  Note that subplan
   * indexes, as stored in 'subplan_map', are global across the parent plan
   * node, but partition indexes are valid only within a particular hierarchy.
+  * relid_map[p] contains the partition's OID, or 0 if the partition was pruned.
   */
  typedef struct PartitionedRelPruneInfo
  {
*************** typedef struct PartitionedRelPruneInfo
*** 1115,1121 ****
  	int			nexprs;			/* Length of hasexecparam[] */
  	int		   *subplan_map;	/* subplan index by partition index, or -1 */
  	int		   *subpart_map;	/* subpart index by partition index, or -1 */
! 	Oid		   *relid_map;		/* relation OID by partition index, or -1 */
  	bool	   *hasexecparam;	/* true if corresponding pruning_step contains
  								 * any PARAM_EXEC Params. */
  	bool		do_initial_prune;	/* true if pruning should be performed
--- 1116,1122 ----
  	int			nexprs;			/* Length of hasexecparam[] */
  	int		   *subplan_map;	/* subplan index by partition index, or -1 */
  	int		   *subpart_map;	/* subpart index by partition index, or -1 */
! 	Oid		   *relid_map;		/* relation OID by partition index, or 0 */
  	bool	   *hasexecparam;	/* true if corresponding pruning_step contains
  								 * any PARAM_EXEC Params. */
  	bool		do_initial_prune;	/* true if pruning should be performed
diff --git a/src/include/optimizer/inherit.h b/src/include/optimizer/inherit.h
index d2418f1..02a23e5 100644
*** a/src/include/optimizer/inherit.h
--- b/src/include/optimizer/inherit.h
***************
*** 17,22 ****
  #include "nodes/pathnodes.h"
  
  
! extern void expand_inherited_tables(PlannerInfo *root);
  
  #endif							/* INHERIT_H */
--- 17,27 ----
  #include "nodes/pathnodes.h"
  
  
! extern void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel,
! 						 RangeTblEntry *rte, Index rti);
! 
! extern bool apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
! 					  RelOptInfo *childrel, RangeTblEntry *childRTE,
! 					  AppendRelInfo *appinfo);
  
  #endif							/* INHERIT_H */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 9e79e1c..3a803b3 100644
*** a/src/include/optimizer/pathnode.h
--- b/src/include/optimizer/pathnode.h
*************** extern Path *reparameterize_path_by_chil
*** 277,286 ****
   */
  extern void setup_simple_rel_arrays(PlannerInfo *root);
  extern void setup_append_rel_array(PlannerInfo *root);
  extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
  				 RelOptInfo *parent);
- extern void add_appendrel_other_rels(PlannerInfo *root, RelOptInfo *rel,
- 						 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,
--- 277,285 ----
   */
  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 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/test/regress/expected/partition_aggregate.out b/src/test/regress/expected/partition_aggregate.out
index 9783281..a7305fc 100644
*** a/src/test/regress/expected/partition_aggregate.out
--- b/src/test/regress/expected/partition_aggregate.out
*************** SELECT c, sum(a) FROM pagg_tab WHERE 1 =
*** 144,150 ****
             QUERY PLAN           
  --------------------------------
   HashAggregate
!    Group Key: pagg_tab.c
     ->  Result
           One-Time Filter: false
  (4 rows)
--- 144,150 ----
             QUERY PLAN           
  --------------------------------
   HashAggregate
!    Group Key: c
     ->  Result
           One-Time Filter: false
  (4 rows)
*************** SELECT c, sum(a) FROM pagg_tab WHERE c =
*** 159,165 ****
             QUERY PLAN           
  --------------------------------
   GroupAggregate
!    Group Key: pagg_tab.c
     ->  Result
           One-Time Filter: false
  (4 rows)
--- 159,165 ----
             QUERY PLAN           
  --------------------------------
   GroupAggregate
!    Group Key: c
     ->  Result
           One-Time Filter: false
  (4 rows)
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 50ca03b..7806ba1 100644
*** a/src/test/regress/expected/partition_prune.out
--- b/src/test/regress/expected/partition_prune.out
*************** table ab;
*** 2568,2573 ****
--- 2568,2627 ----
   1 | 3
  (1 row)
  
+ -- Test UPDATE where source relation has run-time pruning enabled
+ truncate ab;
+ insert into ab values (1, 1), (1, 2), (1, 3), (2, 1);
+ explain (analyze, costs off, summary off, timing off)
+ update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1);
+                               QUERY PLAN                              
+ ----------------------------------------------------------------------
+  Update on ab_a1 (actual rows=0 loops=1)
+    Update on ab_a1_b1
+    Update on ab_a1_b2
+    Update on ab_a1_b3
+    InitPlan 1 (returns $0)
+      ->  Result (actual rows=1 loops=1)
+    ->  Nested Loop (actual rows=1 loops=1)
+          ->  Seq Scan on ab_a1_b1 (actual rows=1 loops=1)
+          ->  Materialize (actual rows=1 loops=1)
+                ->  Append (actual rows=1 loops=1)
+                      ->  Seq Scan on ab_a2_b1 (actual rows=1 loops=1)
+                            Filter: (b = $0)
+                      ->  Seq Scan on ab_a2_b2 (never executed)
+                            Filter: (b = $0)
+                      ->  Seq Scan on ab_a2_b3 (never executed)
+                            Filter: (b = $0)
+    ->  Nested Loop (actual rows=1 loops=1)
+          ->  Seq Scan on ab_a1_b2 (actual rows=1 loops=1)
+          ->  Materialize (actual rows=1 loops=1)
+                ->  Append (actual rows=1 loops=1)
+                      ->  Seq Scan on ab_a2_b1 (actual rows=1 loops=1)
+                            Filter: (b = $0)
+                      ->  Seq Scan on ab_a2_b2 (never executed)
+                            Filter: (b = $0)
+                      ->  Seq Scan on ab_a2_b3 (never executed)
+                            Filter: (b = $0)
+    ->  Nested Loop (actual rows=1 loops=1)
+          ->  Seq Scan on ab_a1_b3 (actual rows=1 loops=1)
+          ->  Materialize (actual rows=1 loops=1)
+                ->  Append (actual rows=1 loops=1)
+                      ->  Seq Scan on ab_a2_b1 (actual rows=1 loops=1)
+                            Filter: (b = $0)
+                      ->  Seq Scan on ab_a2_b2 (never executed)
+                            Filter: (b = $0)
+                      ->  Seq Scan on ab_a2_b3 (never executed)
+                            Filter: (b = $0)
+ (36 rows)
+ 
+ select tableoid::regclass, * from ab;
+  tableoid | a | b 
+ ----------+---+---
+  ab_a1_b3 | 1 | 3
+  ab_a1_b3 | 1 | 3
+  ab_a1_b3 | 1 | 3
+  ab_a2_b1 | 2 | 1
+ (4 rows)
+ 
  drop table ab, lprt_a;
  -- Join
  create table tbl1(col1 int);
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index a5514c7..2e4d2b4 100644
*** a/src/test/regress/sql/partition_prune.sql
--- b/src/test/regress/sql/partition_prune.sql
*************** explain (analyze, costs off, summary off
*** 588,593 ****
--- 588,600 ----
  update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a;
  table ab;
  
+ -- Test UPDATE where source relation has run-time pruning enabled
+ truncate ab;
+ insert into ab values (1, 1), (1, 2), (1, 3), (2, 1);
+ explain (analyze, costs off, summary off, timing off)
+ update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1);
+ select tableoid::regclass, * from ab;
+ 
  drop table ab, lprt_a;
  
  -- Join
