diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 98fed55..66537cf 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -2078,7 +2078,6 @@ find_partition_scheme(PlannerInfo *root, Relation relation)
 	int		nparts;
 	int		partnatts;
 	int		cnt_pks;
-	int		cnt_parts;
 	PartitionScheme	part_scheme = NULL;
 
 	/* No partition scheme for an unpartitioned relation. */
@@ -2088,21 +2087,6 @@ find_partition_scheme(PlannerInfo *root, Relation relation)
 	nparts = part_desc->nparts;
 	partnatts = part_key->partnatts;
 
-	/*
-	 * For a multi-level partitioned table, we do not retain the partitioning
-	 * hierarchy while expanding RTE for the topmost parent. Thus the number of
-	 * children as per root->append_rel_list does not match the number of
-	 * partitions specified in the partition descriptor and hence the
-	 * partitioning scheme of a multi-partitioned table does not reflect the
-	 * true picture. So for now, treat a multi-partitioned table as not
-	 * partitioned.
-	 */
-	for (cnt_parts = 0; cnt_parts < nparts; cnt_parts++)
-	{
-		if (has_subclass(part_desc->oids[cnt_parts]))
-			return NULL;
-	}
-
 	/* Search for a matching partition scheme and return if found one. */
 	foreach (lc, root->part_schemes)
 	{
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 0a2c131..b8af23e 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -98,9 +98,6 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
 						   List *live_childrels, List *all_child_pathkeys,
 						   bool partition_join_path);
-static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
-									  RelOptInfo *rel,
-									  Relids required_outer);
 static List *accumulate_append_subpath(List *subpaths, Path *path);
 static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
 					  Index rti, RangeTblEntry *rte);
@@ -1646,7 +1643,7 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
  *
  * Returns NULL if unable to create such a path.
  */
-static Path *
+Path *
 get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel,
 									  Relids required_outer)
 {
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 7839f0f..e7e06c8 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1526,7 +1526,6 @@ add_paths_to_child_joinrel(PlannerInfo *root, RelOptInfo *parent_joinrel,
 											   child_rel1->relids,
 											   child_rel2->relids);
 
-
 		/*
 		 * Construct restrictions applicable to the child join from
 		 * those applicable to the parent join.
@@ -1619,6 +1618,58 @@ adjust_child_relids(Relids relids, List *append_rel_infos)
 }
 
 /*
+ * Replace any relid present in top_parent_relids with its child in
+ * child_relids. Members of child_relids can be multiple levels below top
+ * parent in the partition hierarchy.
+ */
+Relids
+adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
+							   Relids child_relids, Relids top_parent_relids)
+{
+	List	   *appinfos;
+	Relids		parent_relids = NULL;
+	ListCell   *lc;
+	Relids		result;
+	Relids		tmp_result = NULL;
+
+	/*
+	 * If the given relids set doesn't contain any of the top parent relids,
+	 * it will remain unchanged.
+	 */
+	if (!bms_overlap(relids, top_parent_relids))
+		return relids;
+
+	appinfos = find_appinfos_by_relids(root, child_relids);
+
+	/* Construct relids set for the immediate parent of the given child. */
+	foreach (lc, appinfos)
+	{
+		AppendRelInfo   *appinfo = lfirst(lc);
+
+		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+	}
+
+	/* Recurse if immediate parent is not the top parent. */
+	if (!bms_equal(parent_relids, top_parent_relids))
+	{
+		tmp_result = adjust_child_relids_multilevel(root, relids,
+													parent_relids,
+													top_parent_relids);
+		relids = tmp_result;
+	}
+
+	result = adjust_child_relids(relids, appinfos);
+
+	/* Free memory consumed by any immediate result. */
+	if (tmp_result)
+		bms_free(tmp_result);
+
+	bms_free(parent_relids);
+	list_free(appinfos);
+	return result;
+}
+
+/*
  * Returns true if there exists an equi-join condition for each pair of
  * partition key from given relations being joined.
  */
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 3a223c8..baf0fdf 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -4097,13 +4097,32 @@ create_partition_join_plan(PlannerInfo *root, PartitionJoinPath *best_path)
 		 * Search for a child path with pathkeys or parameterization
 		 * matching that of the given path.
 		 */
-		child_path = get_cheapest_path_for_pathkeys(child_join->pathlist,
-													best_path->path.pathkeys,
-											 PATH_REQ_OUTER(&best_path->path),
-													TOTAL_COST);
+		if (!PATH_REQ_OUTER(&best_path->path))
+			child_path = get_cheapest_path_for_pathkeys(child_join->pathlist,
+													  best_path->path.pathkeys,
+														NULL,
+														TOTAL_COST);
+		else if (best_path->reparamterized_by)
+		{
+			child_path = get_cheapest_parameterized_child_path(root,
+															   child_join,
+													best_path->old_param);
+
+			if (!child_path)
+				elog(ERROR, "Could not find a child-join path with required pathkeys or parameterization.");
+
+			child_path = reparameterize_path_by_child(root, child_path,
+												 best_path->reparamterized_by);
+		}
+		else
+			child_path = get_cheapest_parameterized_child_path(root,
+															   child_join,
+											  PATH_REQ_OUTER(&best_path->path));
 
 		if (!child_path)
-			elog(ERROR, "Could not find a path with required pathkeys.");
+			elog(ERROR, "Could not find a child-join path with required pathkeys or parameterization.");
+
+		MemoryContextSwitchTo(old_context);
 
 		MemoryContextSwitchTo(old_context);
 
@@ -4155,7 +4174,19 @@ create_partition_join_plan(PlannerInfo *root, PartitionJoinPath *best_path)
 			}
 		}
 
-		child_plans = lappend(child_plans, child_plan);
+		/* Flatten Merge/Append plans. */
+		if (IsA(child_plan, Append))
+		{
+			Append	   *append = (Append *) child_plan;
+			child_plans = list_concat(child_plans, append->appendplans);
+		}
+		else if (IsA(child_plan, MergeAppend))
+		{
+			MergeAppend	   *mappend = (MergeAppend *) child_plan;
+			child_plans = list_concat(child_plans, mappend->mergeplans);
+		}
+		else
+			child_plans = lappend(child_plans, child_plan);
 
 		/*
 		 * Reset the child_join memory context to reclaim the memory consumed
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 84ce6b3..61f3886 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -14,6 +14,7 @@
  */
 #include "postgres.h"
 
+#include "catalog/pg_class.h"
 #include "catalog/pg_type.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
@@ -623,8 +624,22 @@ create_lateral_join_info(PlannerInfo *root)
 	for (rti = 1; rti < root->simple_rel_array_size; rti++)
 	{
 		RelOptInfo *brel = root->simple_rel_array[rti];
+		RangeTblEntry *rte = root->simple_rte_array[rti];
 
-		if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
+		if (brel == NULL)
+			continue;
+
+		/*
+		 * If an "other rel" RTE is a "partitioned table", we must propagate
+		 * the lateral info inherited all the way from the root parent to its
+		 * children. That's because the children are not linked directly with
+		 * the root parent via AppendRelInfo's unlike in case of a regular
+		 * inheritance set (see expand_inherited_rtentry()).  Failing to
+		 * do this would result in those children not getting marked with the
+		 * appropriate lateral info.
+		 */
+		if (brel->reloptkind != RELOPT_BASEREL &&
+			rte->relkind != RELKIND_PARTITIONED_TABLE)
 			continue;
 
 		if (root->simple_rte_array[rti]->inh)
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 8b6a183..ecaffd0 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -110,6 +110,14 @@ static Node *adjust_appendrel_attrs_mutator(Node *node,
 							   adjust_appendrel_attrs_context *context);
 static List *adjust_inherited_tlist(List *tlist,
 					   AppendRelInfo *context);
+static List *expand_inherited_rte_internal(PlannerInfo *root, RangeTblEntry *rte,
+							 Index rti, PlanRowMark *oldrc,
+							 LOCKMODE lockmode, bool flatten);
+static AppendRelInfo *process_one_child_table(PlannerInfo *root,
+						RangeTblEntry *parentRTE, Index parentRTindex,
+						Relation parentrel, Relation childrel,
+						PlanRowMark *parent_rc, bool inh,
+						RangeTblEntry **childRTE, Index *childRTindex);
 
 
 /*
@@ -1323,7 +1331,10 @@ expand_inherited_tables(PlannerInfo *root)
 
 	/*
 	 * expand_inherited_rtentry may add RTEs to parse->rtable; there is no
-	 * need to scan them since they can't have inh=true.  So just scan as far
+	 * need to scan them here since they can't normally have inh=true.  If
+	 * the inheritance set represents a partitioned table, some newly added
+	 * RTEs will break the above rule if they are partitioned tables
+	 * themselves, but they are expanded recursively.  So just scan as far
 	 * as the original end of the rtable list.
 	 */
 	nrtes = list_length(root->parse->rtable);
@@ -1346,9 +1357,11 @@ expand_inherited_tables(PlannerInfo *root)
  *		"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.
+ * inheritance set.  If the RTE represents a partitioned table, inheritance
+ * set is expanded recursively.  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.  The same applies
+ * to each individual inheritance set in the recursive expansion case.
  *
  * A childless table is never considered to be an inheritance set; therefore
  * a parent RTE must always have at least two associated AppendRelInfos.
@@ -1359,11 +1372,8 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	Query	   *parse = root->parse;
 	Oid			parentOID;
 	PlanRowMark *oldrc;
-	Relation	oldrelation;
 	LOCKMODE	lockmode;
-	List	   *inhOIDs;
 	List	   *appinfos;
-	ListCell   *l;
 
 	/* Does RT entry allow inheritance? */
 	if (!rte->inh)
@@ -1404,19 +1414,69 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	else
 		lockmode = AccessShareLock;
 
-	/* Scan for all members of inheritance set, acquire needed locks */
-	inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+	/*
+	 * Do not flatten the inheritance hierarchy if partitioned table, unless
+	 * this is the result relation.
+	 */
+	if (rte->relkind == RELKIND_PARTITIONED_TABLE &&
+		rti != root->parse->resultRelation)
+		appinfos = expand_inherited_rte_internal(root, rte, rti, oldrc,
+												 lockmode, false);
+	else
+		appinfos = expand_inherited_rte_internal(root, rte, rti, oldrc,
+												 lockmode, true);
+
+	/* Add to root->append_rel_list */
+	root->append_rel_list = list_concat(root->append_rel_list, appinfos);
+}
+
+/*
+ * expand_inherited_rte_internal
+ *		Expand an inheritance set in either non-recursive (flatten=true) or
+ *		recursive (flatten=false) manner.
+ *
+ * A inheritance hierarchy is not flttened if it represents a partitioned
+ * table.  This allows later planning steps to apply any partitioning
+ * related optimizations in suitable manner.
+ */
+static List *
+expand_inherited_rte_internal(PlannerInfo *root, RangeTblEntry *rte,
+							  Index rti, PlanRowMark *oldrc,
+							  LOCKMODE lockmode, bool flatten)
+{
+	Oid			parentOID;
+	Relation	oldrelation;
+	List	   *inhOIDs;
+	List	   *appinfos = NIL;
+	ListCell   *l;
+	bool		has_descendents;
+
+	Assert(rte->rtekind == RTE_RELATION);
+	parentOID = rte->relid;
 
 	/*
-	 * Check that there's at least one descendant, else treat as no-child
+	 * Get the list of inheritors.
+	 *
+	 * Also check that there's at least one descendant, else treat as no-child
 	 * case.  This could happen despite above has_subclass() check, if table
 	 * once had a child but no longer does.
 	 */
-	if (list_length(inhOIDs) < 2)
+	if (flatten)
+	{
+		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+		has_descendents = list_length(inhOIDs) >= 2;
+	}
+	else
+	{
+		inhOIDs = find_inheritance_children(parentOID, lockmode);
+		has_descendents = list_length(inhOIDs) >= 1;
+	}
+
+	if (!has_descendents)
 	{
 		/* Clear flag before returning */
 		rte->inh = false;
-		return;
+		return NIL;
 	}
 
 	/*
@@ -1433,15 +1493,24 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	 */
 	oldrelation = heap_open(parentOID, NoLock);
 
+	/*
+	 * Process parent relation in its role as inheritance set member; remember
+	 * that parent table OID is not in inhOIDs if we did not flatten the
+	 * inheritance tree.
+	 */
+	if (!flatten)
+		appinfos = list_make1(process_one_child_table(root, rte, rti,
+													  oldrelation, oldrelation,
+													  oldrc, false,
+													  NULL, NULL));
+
 	/* Scan the inheritance set and expand it */
-	appinfos = NIL;
 	foreach(l, inhOIDs)
 	{
 		Oid			childOID = lfirst_oid(l);
 		Relation	newrelation;
 		RangeTblEntry *childrte;
 		Index		childRTindex;
-		AppendRelInfo *appinfo;
 
 		/* Open rel if needed; we already have required locks */
 		if (childOID != parentOID)
@@ -1462,75 +1531,29 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 		}
 
 		/*
-		 * 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.
-		 */
-		childrte = copyObject(rte);
-		childrte->relid = childOID;
-		childrte->relkind = newrelation->rd_rel->relkind;
-		childrte->inh = false;
-		childrte->requiredPerms = 0;
-		parse->rtable = lappend(parse->rtable, childrte);
-		childRTindex = list_length(parse->rtable);
-
-		/*
-		 * Build an AppendRelInfo for this parent and child.
-		 */
-		appinfo = makeNode(AppendRelInfo);
-		appinfo->parent_relid = rti;
-		appinfo->child_relid = childRTindex;
-		appinfo->parent_reltype = oldrelation->rd_rel->reltype;
-		appinfo->child_reltype = newrelation->rd_rel->reltype;
-		make_inh_translation_list(oldrelation, newrelation, childRTindex,
-								  &appinfo->translated_vars);
-		appinfo->parent_reloid = parentOID;
-		appinfos = lappend(appinfos, appinfo);
-
-		/*
-		 * Translate the column permissions bitmaps to the child's attnums (we
-		 * have to build the translated_vars list before we can do this). But
-		 * if this is the parent table, leave copyObject's result alone.
+		 * process_one_child_table() performs the following actions for the
+		 * child table:
 		 *
-		 * Note: we need to do this even though the executor won't run any
-		 * permissions checks on the child RTE.  The insertedCols/updatedCols
-		 * bitmaps may be examined for trigger-firing purposes.
-		 */
-		if (childOID != parentOID)
-		{
-			childrte->selectedCols = translate_col_privs(rte->selectedCols,
-												   appinfo->translated_vars);
-			childrte->insertedCols = translate_col_privs(rte->insertedCols,
-												   appinfo->translated_vars);
-			childrte->updatedCols = translate_col_privs(rte->updatedCols,
-												   appinfo->translated_vars);
-		}
-
-		/*
-		 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
+		 * 1. add a new RTE to the query rtable,
+		 * 2. builds a PlanRowMark and adds to the root->rowMarks list
+		 * 3. builds and returns AppendRelInfo for parent-child pair
 		 */
-		if (oldrc)
+		appinfos = lappend(appinfos,
+						   process_one_child_table(root, rte, rti,
+												   oldrelation, newrelation,
+												   oldrc, false,
+												   &childrte, &childRTindex));
+
+		/* Recurse if we did not flatten the inheritance tree */
+		if (!flatten && has_subclass(childOID))
 		{
-			PlanRowMark *newrc = makeNode(PlanRowMark);
-
-			newrc->rti = childRTindex;
-			newrc->prti = rti;
-			newrc->rowmarkId = oldrc->rowmarkId;
-			/* Reselect rowmark type, because relkind might not match parent */
-			newrc->markType = select_rowmark_type(childrte, oldrc->strength);
-			newrc->allMarkTypes = (1 << newrc->markType);
-			newrc->strength = oldrc->strength;
-			newrc->waitPolicy = oldrc->waitPolicy;
-			newrc->isParent = false;
-
-			/* Include child's rowmark type in parent's allMarkTypes */
-			oldrc->allMarkTypes |= newrc->allMarkTypes;
-
-			root->rowMarks = lappend(root->rowMarks, newrc);
+			Assert(childrte->relkind == RELKIND_PARTITIONED_TABLE);
+			childrte->inh = true;
+			appinfos = list_concat(appinfos,
+							   expand_inherited_rte_internal(root, childrte,
+										childRTindex, oldrc, lockmode, flatten));
 		}
 
-		/* Close child relations, but keep locks */
 		if (childOID != parentOID)
 			heap_close(newrelation, NoLock);
 	}
@@ -1546,11 +1569,108 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	{
 		/* Clear flag before returning */
 		rte->inh = false;
-		return;
+		return NIL;
 	}
+	return appinfos;
+}
 
-	/* Otherwise, OK to add to root->append_rel_list */
-	root->append_rel_list = list_concat(root->append_rel_list, appinfos);
+/*
+ * process_one_child_table
+ *		Process one child table in context of inheritance expansion for a
+ *		query
+ *
+ * *childRTE & *childRTindex are output variables when non-NULL.
+ */
+static AppendRelInfo *
+process_one_child_table(PlannerInfo *root,
+						RangeTblEntry *parentRTE, Index parentRTindex,
+						Relation parentrel, Relation childrel,
+						PlanRowMark *parent_rc, bool inh,
+						RangeTblEntry **childRTE, Index *childRTindex)
+{
+	Query  *parse = root->parse;
+	Oid		parentOID = RelationGetRelid(parentrel),
+			childOID = RelationGetRelid(childrel);
+	RangeTblEntry  *newrte;
+	Index			newrti;
+	AppendRelInfo  *appinfo;
+
+	/*
+	 * Build an RTE for the child, and attach to query's rangetable list.
+	 * We copy most fields of the parent's RTE, but replace relation OID
+	 * and relkind, and set inh as requested.  Also, set requiredPerms to
+	 * zero since all required permissions checks are done on the original
+	 * RTE.
+	 */
+	newrte = copyObject(parentRTE);
+	newrte->relid = RelationGetRelid(childrel);
+	newrte->relkind = childrel->rd_rel->relkind;
+	newrte->inh = inh;
+	newrte->requiredPerms = 0;
+	parse->rtable = lappend(parse->rtable, newrte);
+	newrti = list_length(parse->rtable);
+
+	/* Return the child table RT entry and index if requested */
+	if (childRTE)
+		*childRTE = newrte;
+	if (childRTindex)
+		*childRTindex = newrti;
+
+	/*
+	 * Build an AppendRelInfo for this parent and child.
+	 */
+	appinfo = makeNode(AppendRelInfo);
+	appinfo->parent_relid = parentRTindex;
+	appinfo->child_relid = newrti;
+	appinfo->parent_reltype = parentrel->rd_rel->reltype;
+	appinfo->child_reltype = childrel->rd_rel->reltype;
+	make_inh_translation_list(parentrel, childrel, newrti,
+							  &appinfo->translated_vars);
+	appinfo->parent_reloid = parentOID;
+
+	/*
+	 * Translate the column permissions bitmaps to the child's attnums (we
+	 * have to build the translated_vars list before we can do this). But
+	 * if this is the parent table, leave copyObject's result alone.
+	 *
+	 * Note: we need to do this even though the executor won't run any
+	 * permissions checks on the child RTE.  The insertedCols/updatedCols
+	 * bitmaps may be examined for trigger-firing purposes.
+	 */
+	if (childOID != parentOID)
+	{
+		newrte->selectedCols = translate_col_privs(parentRTE->selectedCols,
+											   appinfo->translated_vars);
+		newrte->insertedCols = translate_col_privs(parentRTE->insertedCols,
+											   appinfo->translated_vars);
+		newrte->updatedCols = translate_col_privs(parentRTE->updatedCols,
+											   appinfo->translated_vars);
+	}
+
+	/*
+	 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
+	 */
+	if (parent_rc)
+	{
+		PlanRowMark *newrc = makeNode(PlanRowMark);
+
+		newrc->rti = newrti;
+		newrc->prti = parentRTindex;
+		newrc->rowmarkId = parent_rc->rowmarkId;
+		/* Reselect rowmark type, because relkind might not match parent */
+		newrc->markType = select_rowmark_type(newrte, parent_rc->strength);
+		newrc->allMarkTypes = (1 << newrc->markType);
+		newrc->strength = parent_rc->strength;
+		newrc->waitPolicy = parent_rc->waitPolicy;
+		newrc->isParent = false;
+
+		/* Include child's rowmark type in parent's allMarkTypes */
+		parent_rc->allMarkTypes |= newrc->allMarkTypes;
+
+		root->rowMarks = lappend(root->rowMarks, newrc);
+	}
+
+	return appinfo;
 }
 
 /*
@@ -2166,23 +2286,47 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
  * adjust_appendrel_attrs_multilevel
  *	  Apply Var translations from a toplevel appendrel parent down to a child.
  *
- * In some cases we need to translate expressions referencing a baserel
+ * In some cases we need to translate expressions referencing a parent relation
  * to reference an appendrel child that's multiple levels removed from it.
  */
 Node *
 adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 								  RelOptInfo *child_rel)
 {
-	AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, child_rel);
-	RelOptInfo *parent_rel = find_base_rel(root, appinfo->parent_relid);
+	List	   *appinfos = find_appinfos_by_relids(root, child_rel->relids);
+	RelOptInfo *parent_rel;
+
+	if (child_rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+	{
+		AppendRelInfo *appinfo = linitial(appinfos);
+		parent_rel = find_base_rel(root, appinfo->parent_relid);
+	}
+	else
+	{
+		Relids		parent_relids = NULL;
+		ListCell   *lc;
+
+		/* Construct relids set for the immediate parent of the given child. */
+		foreach (lc, appinfos)
+		{
+			AppendRelInfo   *appinfo = lfirst(lc);
+
+			parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+		}
+
+		parent_rel = find_join_rel(root, parent_relids);
+		bms_free(parent_relids);
+	}
 
 	/* If parent is also a child, first recurse to apply its translations */
-	if (parent_rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+	if (IS_OTHER_REL(parent_rel))
 		node = adjust_appendrel_attrs_multilevel(root, node, parent_rel);
 	else
-		Assert(parent_rel->reloptkind == RELOPT_BASEREL);
+		Assert(parent_rel->reloptkind == RELOPT_BASEREL ||
+			   parent_rel->reloptkind == RELOPT_JOINREL);
+
 	/* Now translate for this child */
-	return adjust_appendrel_attrs(root, node, list_make1(appinfo));
+	return adjust_appendrel_attrs(root, node, appinfos);
 }
 
 /*
@@ -2210,7 +2354,6 @@ build_child_restrictinfo(PlannerInfo *root, RestrictInfo *rinfo,
 	child_required_relids = adjust_child_relids(rinfo->required_relids,
 												append_rel_infos);
 
-
 	/* Nothing to do, if the clause does not need any translation. */
 	if (bms_equal(child_required_relids, rinfo->required_relids))
 	{
@@ -2279,3 +2422,50 @@ build_child_clauses(PlannerInfo *root, List *clauses, List *append_rel_infos)
 
 	return child_clauses;
 }
+
+/*
+ * build_child_clauses_multilevel
+ *		Similar to build_child_clauses but used when the child relation
+ *		represented by child_relids is
+ *		deeper down in the partition hierarchy reprepresented by parent
+ *		relation with relids top_parent_relids.
+ */
+List *
+build_child_clauses_multilevel(PlannerInfo *root, List *clauses,
+							   Relids child_relids, Relids top_parent_relids)
+{
+	List	   *appinfos;
+	Relids		parent_relids = NULL;
+	ListCell   *lc;
+	List	   *result;
+	List	   *tmp_result = NIL;
+
+	appinfos = find_appinfos_by_relids(root, child_relids);
+
+	/* Construct relids set for the immediate parent of the given child. */
+	foreach (lc, appinfos)
+	{
+		AppendRelInfo   *appinfo = lfirst(lc);
+
+		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+	}
+
+	/* Recurse if immediate parent is not the top parent. */
+	if (!bms_equal(parent_relids, top_parent_relids))
+	{
+		clauses = build_child_clauses_multilevel(root, clauses, parent_relids,
+												  top_parent_relids);
+		tmp_result = clauses;
+	}
+
+	result = build_child_clauses(root, clauses, appinfos);
+
+	/* Free memory consumed by any itermediate list. */
+	if (tmp_result)
+		list_free(tmp_result);
+
+	bms_free(parent_relids);
+	list_free(appinfos);
+
+	return result;
+}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index f5010e4..2fa0023 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3403,7 +3403,6 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 	Path	   *new_path;
 	ParamPathInfo   *new_ppi;
 	ParamPathInfo   *old_ppi;
-	List	   *child_aris;
 	Relids		required_outer;
 
 	/*
@@ -3446,6 +3445,11 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 			memcpy(new_path, path, sizeof(AppendPath));
 			break;
 
+		case T_PartitionJoinPath:
+			new_path = (Path *) makeNode(PartitionJoinPath);
+			memcpy(new_path, path, sizeof(PartitionJoinPath));
+			break;
+
 		/*
 		 * TODO:
 		 * If this method of translation is fine add more path types here.
@@ -3456,16 +3460,12 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 			return NULL;
 	}
 
-	/*
-	 * Gather AppendRelInfos of the base partition relations in the outer child
-	 * relation. We need those for translating parent path to that of child by
-	 * substituting parent Var nodes and relids with those of children.
-	 */
-	child_aris = find_appinfos_by_relids(root, child_rel->relids);
-
 	/* Adjust the parameterization information. */
 	old_ppi = new_path->param_info;
-	required_outer = adjust_child_relids(old_ppi->ppi_req_outer, child_aris);
+	required_outer = adjust_child_relids_multilevel(root,
+													old_ppi->ppi_req_outer,
+													child_rel->relids,
+												 child_rel->top_parent_relids);
 
 	/* If we already have a PPI for this parameterization, just return it */
 	new_ppi = find_param_path_info(new_path->parent, required_outer);
@@ -3476,8 +3476,10 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 		new_ppi = makeNode(ParamPathInfo);
 		new_ppi->ppi_req_outer = required_outer;
 		new_ppi->ppi_rows = old_ppi->ppi_rows;
-		new_ppi->ppi_clauses = build_child_clauses(root, old_ppi->ppi_clauses,
-												   child_aris);
+		new_ppi->ppi_clauses = build_child_clauses_multilevel(root,
+														  old_ppi->ppi_clauses,
+															 child_rel->relids,
+												 child_rel->top_parent_relids);
 		new_path->parent->ppilist = lappend(new_path->parent->ppilist, new_ppi);
 	}
 	else
@@ -3493,6 +3495,7 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 	if (bms_overlap(path->parent->lateral_relids, child_rel->top_parent_relids))
 	{
 		MemoryContext	old_context;
+		List	   *exprs;
 
 		/*
 		 * Allocate the target in planner's context, since they are copies as
@@ -3500,9 +3503,12 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 		 */
 		old_context = MemoryContextSwitchTo(root->planner_cxt);
 		new_path->pathtarget = copy_pathtarget(new_path->pathtarget);
-		new_path->pathtarget->exprs = (List *) adjust_appendrel_attrs(root,
-											(Node *) new_path->pathtarget->exprs,
-																	child_aris);
+		exprs = new_path->pathtarget->exprs;
+		exprs = (List *) adjust_appendrel_attrs_multilevel(root,
+														   (Node *) exprs,
+														   child_rel);
+		new_path->pathtarget->exprs = exprs;
+
 		MemoryContextSwitchTo(old_context);
 	}
 
@@ -3524,9 +3530,10 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 				jpath->innerjoinpath = reparameterize_path_by_child(root,
 														 jpath->innerjoinpath,
 														 child_rel);
-				jpath->joinrestrictinfo = build_child_clauses(root,
-															  jpath->joinrestrictinfo,
-															  child_aris);
+				jpath->joinrestrictinfo = build_child_clauses_multilevel(root,
+													  jpath->joinrestrictinfo,
+															child_rel->relids,
+												child_rel->top_parent_relids);
 			}
 			break;
 
@@ -3543,16 +3550,38 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 																	child_rel));
 				apath->subpaths = subpaths;
 			}
+			break;
 
 		case T_IndexPath:
 			{
 				IndexPath *ipath = (IndexPath *)new_path;
 
-				ipath->indexclauses = build_child_clauses(root, ipath->indexclauses,
-														  child_aris);
-				ipath->indexquals = build_child_clauses(root, ipath->indexquals,
-														child_aris);
+				ipath->indexclauses = build_child_clauses_multilevel(root,
+														   ipath->indexclauses,
+															 child_rel->relids,
+												 child_rel->top_parent_relids);
+
+				ipath->indexquals = build_child_clauses_multilevel(root,
+															 ipath->indexquals,
+															 child_rel->relids,
+												 child_rel->top_parent_relids);
 			}
+			break;
+
+		case T_PartitionJoinPath:
+			{
+				PartitionJoinPath *pjpath = (PartitionJoinPath *)new_path;	
+
+				/*
+				 * The paths for the child-joins covered by PartitionJoinPath will
+				 * be created later. If this PartitionJoinPath was reparameterized
+				 * by child of another relations, we will need that relation to
+				 * reparamterize the child-join paths.
+				 */
+				pjpath->old_param = PATH_REQ_OUTER(path); 
+				pjpath->reparamterized_by = child_rel;
+			}
+			break;
 
 		default:
 			/* Nothing to do. */
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 88e66e4..83074e0 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1335,8 +1335,13 @@ relation_excluded_by_constraints(PlannerInfo *root,
 	if (predicate_refuted_by(safe_restrictions, safe_restrictions))
 		return true;
 
-	/* Only plain relations have constraints */
-	if (rte->rtekind != RTE_RELATION || rte->inh)
+	/*
+	 * Only plain relations have constraints.  We represent a partitioned
+	 * table append member as its own append relation and hence would have
+	 * set rte->inh in that case.
+	 */
+	if (rte->rtekind != RTE_RELATION ||
+		(rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE))
 		return false;
 
 	/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index df5b60f..6bac09d 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1515,6 +1515,12 @@ typedef struct LimitPath
 typedef struct PartitionJoinPath
 {
 	Path		path;
+
+	/* If this path is result of reparameterization by child. */
+	Relids		old_param;			/* Older parameterization. */
+	RelOptInfo *reparamterized_by;	/* Child relation by which this paths was
+									 * reparamterized.
+									 */
 } PartitionJoinPath;
 
 /*
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 5d7bcd9..361c081 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -55,6 +55,8 @@ extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
 extern void generate_gather_paths(PlannerInfo *root, RelOptInfo *rel);
 extern void generate_partition_wise_join_paths(PlannerInfo *root,
 											   RelOptInfo *rel);
+extern Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
+									   RelOptInfo *rel, Relids required_outer);
 
 #ifdef OPTIMIZER_DEBUG
 extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
@@ -225,5 +227,8 @@ extern PathKey *make_canonical_pathkey(PlannerInfo *root,
 					   int strategy, bool nulls_first);
 
 extern Relids adjust_child_relids(Relids relids, List *append_rel_infos);
+extern Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
+											 Relids child_relids,
+											 Relids top_parent_relids);
 
 #endif   /* PATHS_H */
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index 2483303..51c9057 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -69,5 +69,7 @@ extern RestrictInfo *build_child_restrictinfo(PlannerInfo *root,
 								 RestrictInfo *rinfo, List *append_rel_infos);
 extern List *build_child_clauses(PlannerInfo *root, List *clauses,
 								 List *append_rel_infos);
+extern List *build_child_clauses_multilevel(PlannerInfo *root, List *clauses,
+								Relids child_relids, Relids top_parent_relids);
 
 #endif   /* PREP_H */
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 38ea8e8..3e6dd49 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1645,15 +1645,15 @@ explain (costs off) select * from range_list_parted;
  Append
    ->  Seq Scan on range_list_parted
    ->  Seq Scan on part_1_10
-   ->  Seq Scan on part_10_20
-   ->  Seq Scan on part_21_30
-   ->  Seq Scan on part_40_inf
    ->  Seq Scan on part_1_10_ab
    ->  Seq Scan on part_1_10_cd
+   ->  Seq Scan on part_10_20
    ->  Seq Scan on part_10_20_ab
    ->  Seq Scan on part_10_20_cd
+   ->  Seq Scan on part_21_30
    ->  Seq Scan on part_21_30_ab
    ->  Seq Scan on part_21_30_cd
+   ->  Seq Scan on part_40_inf
    ->  Seq Scan on part_40_inf_ab
    ->  Seq Scan on part_40_inf_cd
    ->  Seq Scan on part_40_inf_null
@@ -1681,18 +1681,18 @@ explain (costs off) select * from range_list_parted where b = 'ab';
          Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_1_10
          Filter: (b = 'ab'::bpchar)
-   ->  Seq Scan on part_10_20
-         Filter: (b = 'ab'::bpchar)
-   ->  Seq Scan on part_21_30
-         Filter: (b = 'ab'::bpchar)
-   ->  Seq Scan on part_40_inf
-         Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_1_10_ab
          Filter: (b = 'ab'::bpchar)
+   ->  Seq Scan on part_10_20
+         Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_10_20_ab
          Filter: (b = 'ab'::bpchar)
+   ->  Seq Scan on part_21_30
+         Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_21_30_ab
          Filter: (b = 'ab'::bpchar)
+   ->  Seq Scan on part_40_inf
+         Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_40_inf_ab
          Filter: (b = 'ab'::bpchar)
 (19 rows)
@@ -1705,14 +1705,14 @@ explain (costs off) select * from range_list_parted where a between 3 and 23 and
          Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
    ->  Seq Scan on part_1_10
          Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-   ->  Seq Scan on part_10_20
-         Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-   ->  Seq Scan on part_21_30
-         Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
    ->  Seq Scan on part_1_10_ab
          Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
+   ->  Seq Scan on part_10_20
+         Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
    ->  Seq Scan on part_10_20_ab
          Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
+   ->  Seq Scan on part_21_30
+         Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
    ->  Seq Scan on part_21_30_ab
          Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
 (15 rows)
@@ -1752,24 +1752,24 @@ explain (costs off) select * from range_list_parted where a is not null and a <
          Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_1_10
          Filter: ((a IS NOT NULL) AND (a < 67))
-   ->  Seq Scan on part_10_20
-         Filter: ((a IS NOT NULL) AND (a < 67))
-   ->  Seq Scan on part_21_30
-         Filter: ((a IS NOT NULL) AND (a < 67))
-   ->  Seq Scan on part_40_inf
-         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_1_10_ab
          Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_1_10_cd
          Filter: ((a IS NOT NULL) AND (a < 67))
+   ->  Seq Scan on part_10_20
+         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_10_20_ab
          Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_10_20_cd
          Filter: ((a IS NOT NULL) AND (a < 67))
+   ->  Seq Scan on part_21_30
+         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_21_30_ab
          Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_21_30_cd
          Filter: ((a IS NOT NULL) AND (a < 67))
+   ->  Seq Scan on part_40_inf
+         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_40_inf_ab
          Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_40_inf_cd
diff --git a/src/test/regress/expected/multi_level_partition_join.out b/src/test/regress/expected/multi_level_partition_join.out
index d40ae55..97b1e79 100644
--- a/src/test/regress/expected/multi_level_partition_join.out
+++ b/src/test/regress/expected/multi_level_partition_join.out
@@ -1,21 +1,19 @@
+-- Encourage partition-wise join plans.
+SET partition_wise_plan_weight TO 0.1;
 --
 -- multi-leveled partitions
 --
 CREATE TABLE prt1_l (a int, b int, c varchar) PARTITION BY RANGE(a);
-CREATE TABLE prt1_l_p1 PARTITION OF prt1_l FOR VALUES FROM (0) TO (250) PARTITION BY RANGE (b);
-CREATE TABLE prt1_l_p1_p1 PARTITION OF prt1_l_p1 FOR VALUES FROM (0) TO (100);
-CREATE TABLE prt1_l_p1_p2 PARTITION OF prt1_l_p1 FOR VALUES FROM (100) TO (250);
+CREATE TABLE prt1_l_p1 PARTITION OF prt1_l FOR VALUES FROM (0) TO (250);
 CREATE TABLE prt1_l_p2 PARTITION OF prt1_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
 CREATE TABLE prt1_l_p2_p1 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0250') TO ('0400');
 CREATE TABLE prt1_l_p2_p2 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0400') TO ('0500');
-CREATE TABLE prt1_l_p3 PARTITION OF prt1_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE ((b + a));
-CREATE TABLE prt1_l_p3_p1 PARTITION OF prt1_l_p3 FOR VALUES FROM (1000) TO (1100);
-CREATE TABLE prt1_l_p3_p2 PARTITION OF prt1_l_p3 FOR VALUES FROM (1100) TO (1200);
+CREATE TABLE prt1_l_p3 PARTITION OF prt1_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (b);
+CREATE TABLE prt1_l_p3_p1 PARTITION OF prt1_l_p3 FOR VALUES FROM (500) TO (550);
+CREATE TABLE prt1_l_p3_p2 PARTITION OF prt1_l_p3 FOR VALUES FROM (550) TO (600);
 INSERT INTO prt1_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
 ANALYZE prt1_l;
 ANALYZE prt1_l_p1;
-ANALYZE prt1_l_p1_p1;
-ANALYZE prt1_l_p1_p2;
 ANALYZE prt1_l_p2;
 ANALYZE prt1_l_p2_p1;
 ANALYZE prt1_l_p2_p2;
@@ -26,20 +24,16 @@ ANALYZE prt1_l_p3_p2;
 -- results are tested.
 CREATE TABLE uprt1_l AS SELECT * FROM prt1_l;
 CREATE TABLE prt2_l (a int, b int, c varchar) PARTITION BY RANGE(b);
-CREATE TABLE prt2_l_p1 PARTITION OF prt2_l FOR VALUES FROM (0) TO (250) PARTITION BY RANGE (a);
-CREATE TABLE prt2_l_p1_p1 PARTITION OF prt2_l_p1 FOR VALUES FROM (0) TO (100);
-CREATE TABLE prt2_l_p1_p2 PARTITION OF prt2_l_p1 FOR VALUES FROM (100) TO (250);
+CREATE TABLE prt2_l_p1 PARTITION OF prt2_l FOR VALUES FROM (0) TO (250);
 CREATE TABLE prt2_l_p2 PARTITION OF prt2_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
 CREATE TABLE prt2_l_p2_p1 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0250') TO ('0400');
 CREATE TABLE prt2_l_p2_p2 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0400') TO ('0500');
-CREATE TABLE prt2_l_p3 PARTITION OF prt2_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE ((a + b));
-CREATE TABLE prt2_l_p3_p1 PARTITION OF prt2_l_p3 FOR VALUES FROM (1000) TO (1100);
-CREATE TABLE prt2_l_p3_p2 PARTITION OF prt2_l_p3 FOR VALUES FROM (1100) TO (1200);
+CREATE TABLE prt2_l_p3 PARTITION OF prt2_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (a);
+CREATE TABLE prt2_l_p3_p1 PARTITION OF prt2_l_p3 FOR VALUES FROM (500) TO (525);
+CREATE TABLE prt2_l_p3_p2 PARTITION OF prt2_l_p3 FOR VALUES FROM (525) TO (600);
 INSERT INTO prt2_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
 ANALYZE prt2_l;
 ANALYZE prt2_l_p1;
-ANALYZE prt2_l_p1_p1;
-ANALYZE prt2_l_p1_p2;
 ANALYZE prt2_l_p2;
 ANALYZE prt2_l_p2_p1;
 ANALYZE prt2_l_p2_p2;
@@ -49,77 +43,70 @@ ANALYZE prt2_l_p3_p2;
 -- TODO: This table is created only for testing the results. Remove once
 -- results are tested.
 CREATE TABLE uprt2_l AS SELECT * FROM prt2_l;
+-- inner join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
-                                                                      QUERY PLAN                                                                      
-------------------------------------------------------------------------------------------------------------------------------------------------------
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
  Sort
    Output: t1.a, t1.c, t2.b, t2.c
    Sort Key: t1.a
    ->  Append
          ->  Hash Join
                Output: t1.a, t1.c, t2.b, t2.c
-               Hash Cond: ((t2.b = t1.a) AND (t2.a = t1.b) AND ((t2.c)::text = (t1.c)::text) AND ((t2.a + t2.b) = (t1.b + t1.a)))
-               ->  Seq Scan on public.prt2_l_p1_p1 t2
-                     Output: t2.b, t2.c, t2.a
+               Hash Cond: ((t2.b = t1.a) AND ((t2.c)::text = (t1.c)::text))
+               ->  Seq Scan on public.prt2_l_p1 t2
+                     Output: t2.b, t2.c
                ->  Hash
-                     Output: t1.a, t1.c, t1.b
-                     ->  Seq Scan on public.prt1_l_p1_p1 t1
-                           Output: t1.a, t1.c, t1.b
+                     Output: t1.a, t1.c
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.c
                            Filter: ((t1.a % 25) = 0)
          ->  Hash Join
                Output: t1_1.a, t1_1.c, t2_1.b, t2_1.c
-               Hash Cond: ((t2_1.b = t1_1.a) AND (t2_1.a = t1_1.b) AND ((t2_1.c)::text = (t1_1.c)::text) AND ((t2_1.a + t2_1.b) = (t1_1.b + t1_1.a)))
-               ->  Seq Scan on public.prt2_l_p1_p2 t2_1
-                     Output: t2_1.b, t2_1.c, t2_1.a
+               Hash Cond: ((t2_1.b = t1_1.a) AND ((t2_1.c)::text = (t1_1.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p1 t2_1
+                     Output: t2_1.b, t2_1.c
                ->  Hash
-                     Output: t1_1.a, t1_1.c, t1_1.b
-                     ->  Seq Scan on public.prt1_l_p1_p2 t1_1
-                           Output: t1_1.a, t1_1.c, t1_1.b
+                     Output: t1_1.a, t1_1.c
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.c
                            Filter: ((t1_1.a % 25) = 0)
          ->  Hash Join
                Output: t1_2.a, t1_2.c, t2_2.b, t2_2.c
-               Hash Cond: ((t2_2.b = t1_2.a) AND (t2_2.a = t1_2.b) AND ((t2_2.c)::text = (t1_2.c)::text) AND ((t2_2.a + t2_2.b) = (t1_2.b + t1_2.a)))
-               ->  Seq Scan on public.prt2_l_p2_p1 t2_2
-                     Output: t2_2.b, t2_2.c, t2_2.a
+               Hash Cond: ((t2_2.b = t1_2.a) AND ((t2_2.c)::text = (t1_2.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p2 t2_2
+                     Output: t2_2.b, t2_2.c
                ->  Hash
-                     Output: t1_2.a, t1_2.c, t1_2.b
-                     ->  Seq Scan on public.prt1_l_p2_p1 t1_2
-                           Output: t1_2.a, t1_2.c, t1_2.b
+                     Output: t1_2.a, t1_2.c
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.c
                            Filter: ((t1_2.a % 25) = 0)
          ->  Hash Join
                Output: t1_3.a, t1_3.c, t2_3.b, t2_3.c
-               Hash Cond: ((t2_3.b = t1_3.a) AND (t2_3.a = t1_3.b) AND ((t2_3.c)::text = (t1_3.c)::text) AND ((t2_3.a + t2_3.b) = (t1_3.b + t1_3.a)))
-               ->  Seq Scan on public.prt2_l_p2_p2 t2_3
-                     Output: t2_3.b, t2_3.c, t2_3.a
+               Hash Cond: ((t2_3.b = t1_3.a) AND ((t2_3.c)::text = (t1_3.c)::text))
+               ->  Append
+                     ->  Seq Scan on public.prt2_l_p3 t2_3
+                           Output: t2_3.b, t2_3.c
+                     ->  Seq Scan on public.prt2_l_p3_p1 t2_4
+                           Output: t2_4.b, t2_4.c
+                     ->  Seq Scan on public.prt2_l_p3_p2 t2_5
+                           Output: t2_5.b, t2_5.c
                ->  Hash
-                     Output: t1_3.a, t1_3.c, t1_3.b
-                     ->  Seq Scan on public.prt1_l_p2_p2 t1_3
-                           Output: t1_3.a, t1_3.c, t1_3.b
-                           Filter: ((t1_3.a % 25) = 0)
-         ->  Hash Join
-               Output: t1_4.a, t1_4.c, t2_4.b, t2_4.c
-               Hash Cond: ((t2_4.b = t1_4.a) AND (t2_4.a = t1_4.b) AND ((t2_4.c)::text = (t1_4.c)::text) AND ((t2_4.a + t2_4.b) = (t1_4.b + t1_4.a)))
-               ->  Seq Scan on public.prt2_l_p3_p1 t2_4
-                     Output: t2_4.b, t2_4.c, t2_4.a
-               ->  Hash
-                     Output: t1_4.a, t1_4.c, t1_4.b
-                     ->  Seq Scan on public.prt1_l_p3_p1 t1_4
-                           Output: t1_4.a, t1_4.c, t1_4.b
-                           Filter: ((t1_4.a % 25) = 0)
-         ->  Hash Join
-               Output: t1_5.a, t1_5.c, t2_5.b, t2_5.c
-               Hash Cond: ((t2_5.b = t1_5.a) AND (t2_5.a = t1_5.b) AND ((t2_5.c)::text = (t1_5.c)::text) AND ((t2_5.a + t2_5.b) = (t1_5.b + t1_5.a)))
-               ->  Seq Scan on public.prt2_l_p3_p2 t2_5
-                     Output: t2_5.b, t2_5.c, t2_5.a
-               ->  Hash
-                     Output: t1_5.a, t1_5.c, t1_5.b
-                     ->  Seq Scan on public.prt1_l_p3_p2 t1_5
-                           Output: t1_5.a, t1_5.c, t1_5.b
-                           Filter: ((t1_5.a % 25) = 0)
-(64 rows)
+                     Output: t1_3.a, t1_3.c
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.c
+                                 Filter: ((t1_3.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.c
+                                 Filter: ((t1_4.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.c
+                                 Filter: ((t1_5.a % 25) = 0)
+(56 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -128,7 +115,7 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1
  450 | 0450 | 450 | 0450
 (4 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1, uprt2_l t2 WHERE t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1, uprt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -137,77 +124,70 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1, uprt2_l t2 WHERE t1.a = t2.b AND
  450 | 0450 | 450 | 0450
 (4 rows)
 
+-- left join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
-                                                                      QUERY PLAN                                                                      
-------------------------------------------------------------------------------------------------------------------------------------------------------
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
  Sort
    Output: t1.a, t1.c, t2.b, t2.c
    Sort Key: t1.a, t2.b
    ->  Append
          ->  Hash Right Join
                Output: t1.a, t1.c, t2.b, t2.c
-               Hash Cond: ((t2.b = t1.a) AND (t2.a = t1.b) AND ((t2.c)::text = (t1.c)::text) AND ((t2.a + t2.b) = (t1.b + t1.a)))
-               ->  Seq Scan on public.prt2_l_p1_p1 t2
-                     Output: t2.b, t2.c, t2.a
+               Hash Cond: ((t2.b = t1.a) AND ((t2.c)::text = (t1.c)::text))
+               ->  Seq Scan on public.prt2_l_p1 t2
+                     Output: t2.b, t2.c
                ->  Hash
-                     Output: t1.a, t1.c, t1.b
-                     ->  Seq Scan on public.prt1_l_p1_p1 t1
-                           Output: t1.a, t1.c, t1.b
+                     Output: t1.a, t1.c
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.c
                            Filter: ((t1.a % 25) = 0)
          ->  Hash Right Join
                Output: t1_1.a, t1_1.c, t2_1.b, t2_1.c
-               Hash Cond: ((t2_1.b = t1_1.a) AND (t2_1.a = t1_1.b) AND ((t2_1.c)::text = (t1_1.c)::text) AND ((t2_1.a + t2_1.b) = (t1_1.b + t1_1.a)))
-               ->  Seq Scan on public.prt2_l_p1_p2 t2_1
-                     Output: t2_1.b, t2_1.c, t2_1.a
+               Hash Cond: ((t2_1.b = t1_1.a) AND ((t2_1.c)::text = (t1_1.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p1 t2_1
+                     Output: t2_1.b, t2_1.c
                ->  Hash
-                     Output: t1_1.a, t1_1.c, t1_1.b
-                     ->  Seq Scan on public.prt1_l_p1_p2 t1_1
-                           Output: t1_1.a, t1_1.c, t1_1.b
+                     Output: t1_1.a, t1_1.c
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.c
                            Filter: ((t1_1.a % 25) = 0)
          ->  Hash Right Join
                Output: t1_2.a, t1_2.c, t2_2.b, t2_2.c
-               Hash Cond: ((t2_2.b = t1_2.a) AND (t2_2.a = t1_2.b) AND ((t2_2.c)::text = (t1_2.c)::text) AND ((t2_2.a + t2_2.b) = (t1_2.b + t1_2.a)))
-               ->  Seq Scan on public.prt2_l_p2_p1 t2_2
-                     Output: t2_2.b, t2_2.c, t2_2.a
+               Hash Cond: ((t2_2.b = t1_2.a) AND ((t2_2.c)::text = (t1_2.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p2 t2_2
+                     Output: t2_2.b, t2_2.c
                ->  Hash
-                     Output: t1_2.a, t1_2.c, t1_2.b
-                     ->  Seq Scan on public.prt1_l_p2_p1 t1_2
-                           Output: t1_2.a, t1_2.c, t1_2.b
+                     Output: t1_2.a, t1_2.c
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.c
                            Filter: ((t1_2.a % 25) = 0)
          ->  Hash Right Join
                Output: t1_3.a, t1_3.c, t2_3.b, t2_3.c
-               Hash Cond: ((t2_3.b = t1_3.a) AND (t2_3.a = t1_3.b) AND ((t2_3.c)::text = (t1_3.c)::text) AND ((t2_3.a + t2_3.b) = (t1_3.b + t1_3.a)))
-               ->  Seq Scan on public.prt2_l_p2_p2 t2_3
-                     Output: t2_3.b, t2_3.c, t2_3.a
-               ->  Hash
-                     Output: t1_3.a, t1_3.c, t1_3.b
-                     ->  Seq Scan on public.prt1_l_p2_p2 t1_3
-                           Output: t1_3.a, t1_3.c, t1_3.b
-                           Filter: ((t1_3.a % 25) = 0)
-         ->  Hash Right Join
-               Output: t1_4.a, t1_4.c, t2_4.b, t2_4.c
-               Hash Cond: ((t2_4.b = t1_4.a) AND (t2_4.a = t1_4.b) AND ((t2_4.c)::text = (t1_4.c)::text) AND ((t2_4.a + t2_4.b) = (t1_4.b + t1_4.a)))
-               ->  Seq Scan on public.prt2_l_p3_p1 t2_4
-                     Output: t2_4.b, t2_4.c, t2_4.a
+               Hash Cond: ((t2_3.b = t1_3.a) AND ((t2_3.c)::text = (t1_3.c)::text))
+               ->  Append
+                     ->  Seq Scan on public.prt2_l_p3 t2_3
+                           Output: t2_3.b, t2_3.c
+                     ->  Seq Scan on public.prt2_l_p3_p1 t2_4
+                           Output: t2_4.b, t2_4.c
+                     ->  Seq Scan on public.prt2_l_p3_p2 t2_5
+                           Output: t2_5.b, t2_5.c
                ->  Hash
-                     Output: t1_4.a, t1_4.c, t1_4.b
-                     ->  Seq Scan on public.prt1_l_p3_p1 t1_4
-                           Output: t1_4.a, t1_4.c, t1_4.b
-                           Filter: ((t1_4.a % 25) = 0)
-         ->  Hash Right Join
-               Output: t1_5.a, t1_5.c, t2_5.b, t2_5.c
-               Hash Cond: ((t2_5.b = t1_5.a) AND (t2_5.a = t1_5.b) AND ((t2_5.c)::text = (t1_5.c)::text) AND ((t2_5.a + t2_5.b) = (t1_5.b + t1_5.a)))
-               ->  Seq Scan on public.prt2_l_p3_p2 t2_5
-                     Output: t2_5.b, t2_5.c, t2_5.a
-               ->  Hash
-                     Output: t1_5.a, t1_5.c, t1_5.b
-                     ->  Seq Scan on public.prt1_l_p3_p2 t1_5
-                           Output: t1_5.a, t1_5.c, t1_5.b
-                           Filter: ((t1_5.a % 25) = 0)
-(64 rows)
+                     Output: t1_3.a, t1_3.c
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.c
+                                 Filter: ((t1_3.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.c
+                                 Filter: ((t1_4.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.c
+                                 Filter: ((t1_5.a % 25) = 0)
+(56 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -224,7 +204,7 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b
  550 | 0550 |     | 
 (12 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 LEFT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 LEFT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -241,10 +221,11 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 LEFT JOIN uprt2_l t2 ON t1.a = t2.
  550 | 0550 |     | 
 (12 rows)
 
+-- right join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
-                                                                         QUERY PLAN                                                                         
-------------------------------------------------------------------------------------------------------------------------------------------------------------
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+                                        QUERY PLAN                                        
+------------------------------------------------------------------------------------------
  Sort
    Output: t1.a, t1.c, t2.b, t2.c
    Sort Key: t1.a, t2.b
@@ -253,67 +234,59 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b
          ->  Append
                ->  Hash Right Join
                      Output: t2.b, t2.c, t1.a, t1.c
-                     Hash Cond: ((t1.a = t2.b) AND (t1.b = t2.a) AND ((t1.c)::text = (t2.c)::text) AND ((t1.b + t1.a) = (t2.a + t2.b)))
-                     ->  Seq Scan on public.prt1_l_p1_p1 t1
-                           Output: t1.a, t1.c, t1.b
+                     Hash Cond: ((t1.a = t2.b) AND ((t1.c)::text = (t2.c)::text))
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.c
                      ->  Hash
-                           Output: t2.b, t2.c, t2.a
-                           ->  Seq Scan on public.prt2_l_p1_p1 t2
-                                 Output: t2.b, t2.c, t2.a
+                           Output: t2.b, t2.c
+                           ->  Seq Scan on public.prt2_l_p1 t2
+                                 Output: t2.b, t2.c
                                  Filter: ((t2.b % 25) = 0)
                ->  Hash Right Join
                      Output: t2_1.b, t2_1.c, t1_1.a, t1_1.c
-                     Hash Cond: ((t1_1.a = t2_1.b) AND (t1_1.b = t2_1.a) AND ((t1_1.c)::text = (t2_1.c)::text) AND ((t1_1.b + t1_1.a) = (t2_1.a + t2_1.b)))
-                     ->  Seq Scan on public.prt1_l_p1_p2 t1_1
-                           Output: t1_1.a, t1_1.c, t1_1.b
+                     Hash Cond: ((t1_1.a = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text))
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.c
                      ->  Hash
-                           Output: t2_1.b, t2_1.c, t2_1.a
-                           ->  Seq Scan on public.prt2_l_p1_p2 t2_1
-                                 Output: t2_1.b, t2_1.c, t2_1.a
+                           Output: t2_1.b, t2_1.c
+                           ->  Seq Scan on public.prt2_l_p2_p1 t2_1
+                                 Output: t2_1.b, t2_1.c
                                  Filter: ((t2_1.b % 25) = 0)
                ->  Hash Right Join
                      Output: t2_2.b, t2_2.c, t1_2.a, t1_2.c
-                     Hash Cond: ((t1_2.a = t2_2.b) AND (t1_2.b = t2_2.a) AND ((t1_2.c)::text = (t2_2.c)::text) AND ((t1_2.b + t1_2.a) = (t2_2.a + t2_2.b)))
-                     ->  Seq Scan on public.prt1_l_p2_p1 t1_2
-                           Output: t1_2.a, t1_2.c, t1_2.b
+                     Hash Cond: ((t1_2.a = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text))
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.c
                      ->  Hash
-                           Output: t2_2.b, t2_2.c, t2_2.a
-                           ->  Seq Scan on public.prt2_l_p2_p1 t2_2
-                                 Output: t2_2.b, t2_2.c, t2_2.a
+                           Output: t2_2.b, t2_2.c
+                           ->  Seq Scan on public.prt2_l_p2_p2 t2_2
+                                 Output: t2_2.b, t2_2.c
                                  Filter: ((t2_2.b % 25) = 0)
                ->  Hash Right Join
                      Output: t2_3.b, t2_3.c, t1_3.a, t1_3.c
-                     Hash Cond: ((t1_3.a = t2_3.b) AND (t1_3.b = t2_3.a) AND ((t1_3.c)::text = (t2_3.c)::text) AND ((t1_3.b + t1_3.a) = (t2_3.a + t2_3.b)))
-                     ->  Seq Scan on public.prt1_l_p2_p2 t1_3
-                           Output: t1_3.a, t1_3.c, t1_3.b
-                     ->  Hash
-                           Output: t2_3.b, t2_3.c, t2_3.a
-                           ->  Seq Scan on public.prt2_l_p2_p2 t2_3
-                                 Output: t2_3.b, t2_3.c, t2_3.a
-                                 Filter: ((t2_3.b % 25) = 0)
-               ->  Hash Right Join
-                     Output: t2_4.b, t2_4.c, t1_4.a, t1_4.c
-                     Hash Cond: ((t1_4.a = t2_4.b) AND (t1_4.b = t2_4.a) AND ((t1_4.c)::text = (t2_4.c)::text) AND ((t1_4.b + t1_4.a) = (t2_4.a + t2_4.b)))
-                     ->  Seq Scan on public.prt1_l_p3_p1 t1_4
-                           Output: t1_4.a, t1_4.c, t1_4.b
-                     ->  Hash
-                           Output: t2_4.b, t2_4.c, t2_4.a
-                           ->  Seq Scan on public.prt2_l_p3_p1 t2_4
-                                 Output: t2_4.b, t2_4.c, t2_4.a
-                                 Filter: ((t2_4.b % 25) = 0)
-               ->  Hash Right Join
-                     Output: t2_5.b, t2_5.c, t1_5.a, t1_5.c
-                     Hash Cond: ((t1_5.a = t2_5.b) AND (t1_5.b = t2_5.a) AND ((t1_5.c)::text = (t2_5.c)::text) AND ((t1_5.b + t1_5.a) = (t2_5.a + t2_5.b)))
-                     ->  Seq Scan on public.prt1_l_p3_p2 t1_5
-                           Output: t1_5.a, t1_5.c, t1_5.b
+                     Hash Cond: ((t1_3.a = t2_3.b) AND ((t1_3.c)::text = (t2_3.c)::text))
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.c
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.c
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.c
                      ->  Hash
-                           Output: t2_5.b, t2_5.c, t2_5.a
-                           ->  Seq Scan on public.prt2_l_p3_p2 t2_5
-                                 Output: t2_5.b, t2_5.c, t2_5.a
-                                 Filter: ((t2_5.b % 25) = 0)
-(66 rows)
+                           Output: t2_3.b, t2_3.c
+                           ->  Append
+                                 ->  Seq Scan on public.prt2_l_p3 t2_3
+                                       Output: t2_3.b, t2_3.c
+                                       Filter: ((t2_3.b % 25) = 0)
+                                 ->  Seq Scan on public.prt2_l_p3_p1 t2_4
+                                       Output: t2_4.b, t2_4.c
+                                       Filter: ((t2_4.b % 25) = 0)
+                                 ->  Seq Scan on public.prt2_l_p3_p2 t2_5
+                                       Output: t2_5.b, t2_5.c
+                                       Filter: ((t2_5.b % 25) = 0)
+(58 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -326,7 +299,7 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b
      |      | 525 | 0525
 (8 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 RIGHT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 RIGHT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -339,83 +312,76 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 RIGHT JOIN uprt2_l t2 ON t1.a = t2
      |      | 525 | 0525
 (8 rows)
 
+-- full join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b) ORDER BY t1.a, t2.b;
-                                                                                                              QUERY PLAN                                                                                                              
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+                                                     QUERY PLAN                                                     
+--------------------------------------------------------------------------------------------------------------------
  Sort
-   Output: prt1_l_p1_p1.a, prt1_l_p1_p1.c, prt2_l_p1_p1.b, prt2_l_p1_p1.c
-   Sort Key: prt1_l_p1_p1.a, prt2_l_p1_p1.b
+   Output: prt1_l_p1.a, prt1_l_p1.c, prt2_l_p1.b, prt2_l_p1.c
+   Sort Key: prt1_l_p1.a, prt2_l_p1.b
    ->  Append
          ->  Hash Full Join
-               Output: prt1_l_p1_p1.a, prt1_l_p1_p1.c, prt2_l_p1_p1.b, prt2_l_p1_p1.c
-               Hash Cond: ((prt1_l_p1_p1.a = prt2_l_p1_p1.b) AND (prt1_l_p1_p1.b = prt2_l_p1_p1.a) AND ((prt1_l_p1_p1.c)::text = (prt2_l_p1_p1.c)::text) AND ((prt1_l_p1_p1.b + prt1_l_p1_p1.a) = (prt2_l_p1_p1.a + prt2_l_p1_p1.b)))
-               ->  Seq Scan on public.prt1_l_p1_p1
-                     Output: prt1_l_p1_p1.a, prt1_l_p1_p1.c, prt1_l_p1_p1.b
-                     Filter: ((prt1_l_p1_p1.a % 25) = 0)
-               ->  Hash
-                     Output: prt2_l_p1_p1.b, prt2_l_p1_p1.c, prt2_l_p1_p1.a
-                     ->  Seq Scan on public.prt2_l_p1_p1
-                           Output: prt2_l_p1_p1.b, prt2_l_p1_p1.c, prt2_l_p1_p1.a
-                           Filter: ((prt2_l_p1_p1.b % 25) = 0)
-         ->  Hash Full Join
-               Output: prt1_l_p1_p2.a, prt1_l_p1_p2.c, prt2_l_p1_p2.b, prt2_l_p1_p2.c
-               Hash Cond: ((prt1_l_p1_p2.a = prt2_l_p1_p2.b) AND (prt1_l_p1_p2.b = prt2_l_p1_p2.a) AND ((prt1_l_p1_p2.c)::text = (prt2_l_p1_p2.c)::text) AND ((prt1_l_p1_p2.b + prt1_l_p1_p2.a) = (prt2_l_p1_p2.a + prt2_l_p1_p2.b)))
-               ->  Seq Scan on public.prt1_l_p1_p2
-                     Output: prt1_l_p1_p2.a, prt1_l_p1_p2.c, prt1_l_p1_p2.b
-                     Filter: ((prt1_l_p1_p2.a % 25) = 0)
+               Output: prt1_l_p1.a, prt1_l_p1.c, prt2_l_p1.b, prt2_l_p1.c
+               Hash Cond: ((prt1_l_p1.a = prt2_l_p1.b) AND ((prt1_l_p1.c)::text = (prt2_l_p1.c)::text))
+               ->  Seq Scan on public.prt1_l_p1
+                     Output: prt1_l_p1.a, prt1_l_p1.c
+                     Filter: ((prt1_l_p1.a % 25) = 0)
                ->  Hash
-                     Output: prt2_l_p1_p2.b, prt2_l_p1_p2.c, prt2_l_p1_p2.a
-                     ->  Seq Scan on public.prt2_l_p1_p2
-                           Output: prt2_l_p1_p2.b, prt2_l_p1_p2.c, prt2_l_p1_p2.a
-                           Filter: ((prt2_l_p1_p2.b % 25) = 0)
+                     Output: prt2_l_p1.b, prt2_l_p1.c
+                     ->  Seq Scan on public.prt2_l_p1
+                           Output: prt2_l_p1.b, prt2_l_p1.c
+                           Filter: ((prt2_l_p1.b % 25) = 0)
          ->  Hash Full Join
                Output: prt1_l_p2_p1.a, prt1_l_p2_p1.c, prt2_l_p2_p1.b, prt2_l_p2_p1.c
-               Hash Cond: ((prt1_l_p2_p1.a = prt2_l_p2_p1.b) AND (prt1_l_p2_p1.b = prt2_l_p2_p1.a) AND ((prt1_l_p2_p1.c)::text = (prt2_l_p2_p1.c)::text) AND ((prt1_l_p2_p1.b + prt1_l_p2_p1.a) = (prt2_l_p2_p1.a + prt2_l_p2_p1.b)))
+               Hash Cond: ((prt1_l_p2_p1.a = prt2_l_p2_p1.b) AND ((prt1_l_p2_p1.c)::text = (prt2_l_p2_p1.c)::text))
                ->  Seq Scan on public.prt1_l_p2_p1
-                     Output: prt1_l_p2_p1.a, prt1_l_p2_p1.c, prt1_l_p2_p1.b
+                     Output: prt1_l_p2_p1.a, prt1_l_p2_p1.c
                      Filter: ((prt1_l_p2_p1.a % 25) = 0)
                ->  Hash
-                     Output: prt2_l_p2_p1.b, prt2_l_p2_p1.c, prt2_l_p2_p1.a
+                     Output: prt2_l_p2_p1.b, prt2_l_p2_p1.c
                      ->  Seq Scan on public.prt2_l_p2_p1
-                           Output: prt2_l_p2_p1.b, prt2_l_p2_p1.c, prt2_l_p2_p1.a
+                           Output: prt2_l_p2_p1.b, prt2_l_p2_p1.c
                            Filter: ((prt2_l_p2_p1.b % 25) = 0)
          ->  Hash Full Join
                Output: prt1_l_p2_p2.a, prt1_l_p2_p2.c, prt2_l_p2_p2.b, prt2_l_p2_p2.c
-               Hash Cond: ((prt1_l_p2_p2.a = prt2_l_p2_p2.b) AND (prt1_l_p2_p2.b = prt2_l_p2_p2.a) AND ((prt1_l_p2_p2.c)::text = (prt2_l_p2_p2.c)::text) AND ((prt1_l_p2_p2.b + prt1_l_p2_p2.a) = (prt2_l_p2_p2.a + prt2_l_p2_p2.b)))
+               Hash Cond: ((prt1_l_p2_p2.a = prt2_l_p2_p2.b) AND ((prt1_l_p2_p2.c)::text = (prt2_l_p2_p2.c)::text))
                ->  Seq Scan on public.prt1_l_p2_p2
-                     Output: prt1_l_p2_p2.a, prt1_l_p2_p2.c, prt1_l_p2_p2.b
+                     Output: prt1_l_p2_p2.a, prt1_l_p2_p2.c
                      Filter: ((prt1_l_p2_p2.a % 25) = 0)
                ->  Hash
-                     Output: prt2_l_p2_p2.b, prt2_l_p2_p2.c, prt2_l_p2_p2.a
+                     Output: prt2_l_p2_p2.b, prt2_l_p2_p2.c
                      ->  Seq Scan on public.prt2_l_p2_p2
-                           Output: prt2_l_p2_p2.b, prt2_l_p2_p2.c, prt2_l_p2_p2.a
+                           Output: prt2_l_p2_p2.b, prt2_l_p2_p2.c
                            Filter: ((prt2_l_p2_p2.b % 25) = 0)
          ->  Hash Full Join
-               Output: prt1_l_p3_p1.a, prt1_l_p3_p1.c, prt2_l_p3_p1.b, prt2_l_p3_p1.c
-               Hash Cond: ((prt1_l_p3_p1.a = prt2_l_p3_p1.b) AND (prt1_l_p3_p1.b = prt2_l_p3_p1.a) AND ((prt1_l_p3_p1.c)::text = (prt2_l_p3_p1.c)::text) AND ((prt1_l_p3_p1.b + prt1_l_p3_p1.a) = (prt2_l_p3_p1.a + prt2_l_p3_p1.b)))
-               ->  Seq Scan on public.prt1_l_p3_p1
-                     Output: prt1_l_p3_p1.a, prt1_l_p3_p1.c, prt1_l_p3_p1.b
-                     Filter: ((prt1_l_p3_p1.a % 25) = 0)
+               Output: prt1_l_p3.a, prt1_l_p3.c, prt2_l_p3.b, prt2_l_p3.c
+               Hash Cond: ((prt1_l_p3.a = prt2_l_p3.b) AND ((prt1_l_p3.c)::text = (prt2_l_p3.c)::text))
+               ->  Append
+                     ->  Seq Scan on public.prt1_l_p3
+                           Output: prt1_l_p3.a, prt1_l_p3.c
+                           Filter: ((prt1_l_p3.a % 25) = 0)
+                     ->  Seq Scan on public.prt1_l_p3_p1
+                           Output: prt1_l_p3_p1.a, prt1_l_p3_p1.c
+                           Filter: ((prt1_l_p3_p1.a % 25) = 0)
+                     ->  Seq Scan on public.prt1_l_p3_p2
+                           Output: prt1_l_p3_p2.a, prt1_l_p3_p2.c
+                           Filter: ((prt1_l_p3_p2.a % 25) = 0)
                ->  Hash
-                     Output: prt2_l_p3_p1.b, prt2_l_p3_p1.c, prt2_l_p3_p1.a
-                     ->  Seq Scan on public.prt2_l_p3_p1
-                           Output: prt2_l_p3_p1.b, prt2_l_p3_p1.c, prt2_l_p3_p1.a
-                           Filter: ((prt2_l_p3_p1.b % 25) = 0)
-         ->  Hash Full Join
-               Output: prt1_l_p3_p2.a, prt1_l_p3_p2.c, prt2_l_p3_p2.b, prt2_l_p3_p2.c
-               Hash Cond: ((prt1_l_p3_p2.a = prt2_l_p3_p2.b) AND (prt1_l_p3_p2.b = prt2_l_p3_p2.a) AND ((prt1_l_p3_p2.c)::text = (prt2_l_p3_p2.c)::text) AND ((prt1_l_p3_p2.b + prt1_l_p3_p2.a) = (prt2_l_p3_p2.a + prt2_l_p3_p2.b)))
-               ->  Seq Scan on public.prt1_l_p3_p2
-                     Output: prt1_l_p3_p2.a, prt1_l_p3_p2.c, prt1_l_p3_p2.b
-                     Filter: ((prt1_l_p3_p2.a % 25) = 0)
-               ->  Hash
-                     Output: prt2_l_p3_p2.b, prt2_l_p3_p2.c, prt2_l_p3_p2.a
-                     ->  Seq Scan on public.prt2_l_p3_p2
-                           Output: prt2_l_p3_p2.b, prt2_l_p3_p2.c, prt2_l_p3_p2.a
-                           Filter: ((prt2_l_p3_p2.b % 25) = 0)
-(70 rows)
+                     Output: prt2_l_p3.b, prt2_l_p3.c
+                     ->  Append
+                           ->  Seq Scan on public.prt2_l_p3
+                                 Output: prt2_l_p3.b, prt2_l_p3.c
+                                 Filter: ((prt2_l_p3.b % 25) = 0)
+                           ->  Seq Scan on public.prt2_l_p3_p1
+                                 Output: prt2_l_p3_p1.b, prt2_l_p3_p1.c
+                                 Filter: ((prt2_l_p3_p1.b % 25) = 0)
+                           ->  Seq Scan on public.prt2_l_p3_p2
+                                 Output: prt2_l_p3_p2.b, prt2_l_p3_p2.c
+                                 Filter: ((prt2_l_p3_p2.b % 25) = 0)
+(62 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -436,7 +402,7 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0
      |      | 525 | 0525
 (16 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_l t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_l t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_l WHERE uprt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_l WHERE uprt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
 -----+------+-----+------
    0 | 0000 |   0 | 0000
@@ -456,3 +422,266 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_l t1 WHERE t1.a % 25 = 0
      |      | 375 | 0375
      |      | 525 | 0525
 (16 rows)
+
+-- lateral partition-wise join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                                     QUERY PLAN                                                      
+---------------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+   Sort Key: t1.a
+   ->  Result
+         Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+         ->  Append
+               ->  Nested Loop Left Join
+                     Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a))
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.b, t1.c
+                           Filter: ((t1.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2.a, t2.c, t2.b, t3.a, LEAST(t1.a, t2.a, t3.a)
+                           Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text))
+                           ->  Seq Scan on public.prt2_l_p1 t3
+                                 Output: t3.a, t3.b, t3.c
+                           ->  Hash
+                                 Output: t2.a, t2.c, t2.b
+                                 ->  Seq Scan on public.prt1_l_p1 t2
+                                       Output: t2.a, t2.c, t2.b
+                                       Filter: ((t1.a = t2.a) AND ((t1.c)::text = (t2.c)::text))
+               ->  Nested Loop Left Join
+                     Output: t1_1.a, t1_1.b, t1_1.c, t2_1.a, t2_1.c, t2_1.b, t3_1.a, (LEAST(t1_1.a, t2_1.a, t3_1.a))
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.b, t1_1.c
+                           Filter: ((t1_1.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2_1.a, t2_1.c, t2_1.b, t3_1.a, LEAST(t1_1.a, t2_1.a, t3_1.a)
+                           Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text))
+                           ->  Seq Scan on public.prt2_l_p2_p1 t3_1
+                                 Output: t3_1.a, t3_1.b, t3_1.c
+                           ->  Hash
+                                 Output: t2_1.a, t2_1.c, t2_1.b
+                                 ->  Seq Scan on public.prt1_l_p2_p1 t2_1
+                                       Output: t2_1.a, t2_1.c, t2_1.b
+                                       Filter: ((t1_1.a = t2_1.a) AND ((t1_1.c)::text = (t2_1.c)::text))
+               ->  Nested Loop Left Join
+                     Output: t1_2.a, t1_2.b, t1_2.c, t2_2.a, t2_2.c, t2_2.b, t3_2.a, (LEAST(t1_2.a, t2_2.a, t3_2.a))
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.b, t1_2.c
+                           Filter: ((t1_2.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2_2.a, t2_2.c, t2_2.b, t3_2.a, LEAST(t1_2.a, t2_2.a, t3_2.a)
+                           Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text))
+                           ->  Seq Scan on public.prt2_l_p2_p2 t3_2
+                                 Output: t3_2.a, t3_2.b, t3_2.c
+                           ->  Hash
+                                 Output: t2_2.a, t2_2.c, t2_2.b
+                                 ->  Seq Scan on public.prt1_l_p2_p2 t2_2
+                                       Output: t2_2.a, t2_2.c, t2_2.b
+                                       Filter: ((t1_2.a = t2_2.a) AND ((t1_2.c)::text = (t2_2.c)::text))
+               ->  Nested Loop Left Join
+                     Output: t1_3.a, t1_3.b, t1_3.c, t2_3.a, t2_3.c, t2_3.b, t3_3.a, (LEAST(t1_3.a, t2_3.a, t3_3.a))
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.b, t1_3.c
+                                 Filter: ((t1_3.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.b, t1_4.c
+                                 Filter: ((t1_4.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.b, t1_5.c
+                                 Filter: ((t1_5.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2_3.a, t2_3.c, t2_3.b, t3_3.a, LEAST(t1_3.a, t2_3.a, t3_3.a)
+                           Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
+                           ->  Append
+                                 ->  Seq Scan on public.prt2_l_p3 t3_3
+                                       Output: t3_3.a, t3_3.b, t3_3.c
+                                 ->  Seq Scan on public.prt2_l_p3_p1 t3_4
+                                       Output: t3_4.a, t3_4.b, t3_4.c
+                                 ->  Seq Scan on public.prt2_l_p3_p2 t3_5
+                                       Output: t3_5.a, t3_5.b, t3_5.c
+                           ->  Hash
+                                 Output: t2_3.a, t2_3.c, t2_3.b
+                                 ->  Append
+                                       ->  Seq Scan on public.prt1_l_p3 t2_3
+                                             Output: t2_3.a, t2_3.c, t2_3.b
+                                             Filter: ((t1_3.a = t2_3.a) AND ((t1_3.c)::text = (t2_3.c)::text))
+                                       ->  Seq Scan on public.prt1_l_p3_p1 t2_4
+                                             Output: t2_4.a, t2_4.c, t2_4.b
+                                             Filter: ((t1_3.a = t2_4.a) AND ((t1_3.c)::text = (t2_4.c)::text))
+                                       ->  Seq Scan on public.prt1_l_p3_p2 t2_5
+                                             Output: t2_5.a, t2_5.c, t2_5.b
+                                             Filter: ((t1_3.a = t2_5.a) AND ((t1_3.c)::text = (t2_5.c)::text))
+(85 rows)
+
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
+-- lateral references with clauses without equi-join on partition key
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                             QUERY PLAN                                              
+-----------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+   Sort Key: t1.a
+   ->  Nested Loop Left Join
+         Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+         ->  Append
+               ->  Seq Scan on public.prt1_l t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p1 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p2 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p2_p1 t1_3
+                     Output: t1_3.a, t1_3.b, t1_3.c
+                     Filter: ((t1_3.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p2_p2 t1_4
+                     Output: t1_4.a, t1_4.b, t1_4.c
+                     Filter: ((t1_4.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p3 t1_5
+                     Output: t1_5.a, t1_5.b, t1_5.c
+                     Filter: ((t1_5.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p3_p1 t1_6
+                     Output: t1_6.a, t1_6.b, t1_6.c
+                     Filter: ((t1_6.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p3_p2 t1_7
+                     Output: t1_7.a, t1_7.b, t1_7.c
+                     Filter: ((t1_7.a % 25) = 0)
+         ->  Append
+               ->  Hash Join
+                     Output: t2.a, t2.c, t2.b, t3.a, LEAST(t1.a, t2.a, t3.a)
+                     Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text))
+                     ->  Seq Scan on public.prt2_l_p1 t3
+                           Output: t3.a, t3.b, t3.c
+                     ->  Hash
+                           Output: t2.a, t2.c, t2.b
+                           ->  Seq Scan on public.prt1_l_p1 t2
+                                 Output: t2.a, t2.c, t2.b
+                                 Filter: ((t1.b = t2.a) AND ((t1.c)::text = (t2.c)::text))
+               ->  Hash Join
+                     Output: t2_1.a, t2_1.c, t2_1.b, t3_1.a, LEAST(t1.a, t2_1.a, t3_1.a)
+                     Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text))
+                     ->  Seq Scan on public.prt2_l_p2_p1 t3_1
+                           Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash
+                           Output: t2_1.a, t2_1.c, t2_1.b
+                           ->  Seq Scan on public.prt1_l_p2_p1 t2_1
+                                 Output: t2_1.a, t2_1.c, t2_1.b
+                                 Filter: ((t1.b = t2_1.a) AND ((t1.c)::text = (t2_1.c)::text))
+               ->  Hash Join
+                     Output: t2_2.a, t2_2.c, t2_2.b, t3_2.a, LEAST(t1.a, t2_2.a, t3_2.a)
+                     Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text))
+                     ->  Seq Scan on public.prt2_l_p2_p2 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                     ->  Hash
+                           Output: t2_2.a, t2_2.c, t2_2.b
+                           ->  Seq Scan on public.prt1_l_p2_p2 t2_2
+                                 Output: t2_2.a, t2_2.c, t2_2.b
+                                 Filter: ((t1.b = t2_2.a) AND ((t1.c)::text = (t2_2.c)::text))
+               ->  Hash Join
+                     Output: t2_3.a, t2_3.c, t2_3.b, t3_3.a, LEAST(t1.a, t2_3.a, t3_3.a)
+                     Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
+                     ->  Append
+                           ->  Seq Scan on public.prt2_l_p3 t3_3
+                                 Output: t3_3.a, t3_3.b, t3_3.c
+                           ->  Seq Scan on public.prt2_l_p3_p1 t3_4
+                                 Output: t3_4.a, t3_4.b, t3_4.c
+                           ->  Seq Scan on public.prt2_l_p3_p2 t3_5
+                                 Output: t3_5.a, t3_5.b, t3_5.c
+                     ->  Hash
+                           Output: t2_3.a, t2_3.c, t2_3.b
+                           ->  Append
+                                 ->  Seq Scan on public.prt1_l_p3 t2_3
+                                       Output: t2_3.a, t2_3.c, t2_3.b
+                                       Filter: ((t1.b = t2_3.a) AND ((t1.c)::text = (t2_3.c)::text))
+                                 ->  Seq Scan on public.prt1_l_p3_p1 t2_4
+                                       Output: t2_4.a, t2_4.c, t2_4.b
+                                       Filter: ((t1.b = t2_4.a) AND ((t1.c)::text = (t2_4.c)::text))
+                                 ->  Seq Scan on public.prt1_l_p3_p2 t2_5
+                                       Output: t2_5.a, t2_5.c, t2_5.b
+                                       Filter: ((t1.b = t2_5.a) AND ((t1.c)::text = (t2_5.c)::text))
+(83 rows)
+
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
diff --git a/src/test/regress/sql/multi_level_partition_join.sql b/src/test/regress/sql/multi_level_partition_join.sql
index 31f0281..821c095 100644
--- a/src/test/regress/sql/multi_level_partition_join.sql
+++ b/src/test/regress/sql/multi_level_partition_join.sql
@@ -1,21 +1,20 @@
+-- Encourage partition-wise join plans.
+SET partition_wise_plan_weight TO 0.1;
+
 --
 -- multi-leveled partitions
 --
 CREATE TABLE prt1_l (a int, b int, c varchar) PARTITION BY RANGE(a);
-CREATE TABLE prt1_l_p1 PARTITION OF prt1_l FOR VALUES FROM (0) TO (250) PARTITION BY RANGE (b);
-CREATE TABLE prt1_l_p1_p1 PARTITION OF prt1_l_p1 FOR VALUES FROM (0) TO (100);
-CREATE TABLE prt1_l_p1_p2 PARTITION OF prt1_l_p1 FOR VALUES FROM (100) TO (250);
+CREATE TABLE prt1_l_p1 PARTITION OF prt1_l FOR VALUES FROM (0) TO (250);
 CREATE TABLE prt1_l_p2 PARTITION OF prt1_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
 CREATE TABLE prt1_l_p2_p1 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0250') TO ('0400');
 CREATE TABLE prt1_l_p2_p2 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0400') TO ('0500');
-CREATE TABLE prt1_l_p3 PARTITION OF prt1_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE ((b + a));
-CREATE TABLE prt1_l_p3_p1 PARTITION OF prt1_l_p3 FOR VALUES FROM (1000) TO (1100);
-CREATE TABLE prt1_l_p3_p2 PARTITION OF prt1_l_p3 FOR VALUES FROM (1100) TO (1200);
+CREATE TABLE prt1_l_p3 PARTITION OF prt1_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (b);
+CREATE TABLE prt1_l_p3_p1 PARTITION OF prt1_l_p3 FOR VALUES FROM (500) TO (550);
+CREATE TABLE prt1_l_p3_p2 PARTITION OF prt1_l_p3 FOR VALUES FROM (550) TO (600);
 INSERT INTO prt1_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
 ANALYZE prt1_l;
 ANALYZE prt1_l_p1;
-ANALYZE prt1_l_p1_p1;
-ANALYZE prt1_l_p1_p2;
 ANALYZE prt1_l_p2;
 ANALYZE prt1_l_p2_p1;
 ANALYZE prt1_l_p2_p2;
@@ -27,20 +26,16 @@ ANALYZE prt1_l_p3_p2;
 CREATE TABLE uprt1_l AS SELECT * FROM prt1_l;
 
 CREATE TABLE prt2_l (a int, b int, c varchar) PARTITION BY RANGE(b);
-CREATE TABLE prt2_l_p1 PARTITION OF prt2_l FOR VALUES FROM (0) TO (250) PARTITION BY RANGE (a);
-CREATE TABLE prt2_l_p1_p1 PARTITION OF prt2_l_p1 FOR VALUES FROM (0) TO (100);
-CREATE TABLE prt2_l_p1_p2 PARTITION OF prt2_l_p1 FOR VALUES FROM (100) TO (250);
+CREATE TABLE prt2_l_p1 PARTITION OF prt2_l FOR VALUES FROM (0) TO (250);
 CREATE TABLE prt2_l_p2 PARTITION OF prt2_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
 CREATE TABLE prt2_l_p2_p1 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0250') TO ('0400');
 CREATE TABLE prt2_l_p2_p2 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0400') TO ('0500');
-CREATE TABLE prt2_l_p3 PARTITION OF prt2_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE ((a + b));
-CREATE TABLE prt2_l_p3_p1 PARTITION OF prt2_l_p3 FOR VALUES FROM (1000) TO (1100);
-CREATE TABLE prt2_l_p3_p2 PARTITION OF prt2_l_p3 FOR VALUES FROM (1100) TO (1200);
+CREATE TABLE prt2_l_p3 PARTITION OF prt2_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (a);
+CREATE TABLE prt2_l_p3_p1 PARTITION OF prt2_l_p3 FOR VALUES FROM (500) TO (525);
+CREATE TABLE prt2_l_p3_p2 PARTITION OF prt2_l_p3 FOR VALUES FROM (525) TO (600);
 INSERT INTO prt2_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
 ANALYZE prt2_l;
 ANALYZE prt2_l_p1;
-ANALYZE prt2_l_p1_p1;
-ANALYZE prt2_l_p1_p2;
 ANALYZE prt2_l_p2;
 ANALYZE prt2_l_p2_p1;
 ANALYZE prt2_l_p2_p2;
@@ -51,45 +46,50 @@ ANALYZE prt2_l_p3_p2;
 -- results are tested.
 CREATE TABLE uprt2_l AS SELECT * FROM prt2_l;
 
+-- inner join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1, uprt2_l t2 WHERE t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1, uprt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
 
+-- left join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 LEFT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 LEFT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
 
+-- right join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 RIGHT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 RIGHT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
 
+-- full join
 EXPLAIN (VERBOSE, COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b) ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b) ORDER BY t1.a, t2.b;
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_l t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_l t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c AND t1.b + t1.a = t2.a + t2.b) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_l WHERE uprt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_l WHERE uprt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
 
--- lateral reference
+-- lateral partition-wise join
 EXPLAIN (VERBOSE, COSTS OFF)
 SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
-			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.b = t3.a AND t2.c = t3.c AND t2.b + t2.a = t3.a + t3.b)) ss
-			  ON t1.a = ss.t2a AND t1.b = ss.t2a AND t1.c = ss.t2c AND t1.b + t1.a = ss.t2a + ss.t2b WHERE t1.a % 25 = 0 ORDER BY t1.a;
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
 SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
-			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.b = t3.a AND t2.c = t3.c AND t2.b + t2.a = t3.a + t3.b)) ss
-			  ON t1.a = ss.t2a AND t1.b = ss.t2a AND t1.c = ss.t2c AND t1.b + t1.a = ss.t2a + ss.t2b WHERE t1.a % 25 = 0 ORDER BY t1.a;
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
 SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
-			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.b = t3.a AND t2.c = t3.c AND t2.b + t2.a = t3.a + t3.b)) ss
-			  ON t1.a = ss.t2a AND t1.b = ss.t2a AND t1.c = ss.t2c AND t1.b + t1.a = ss.t2a + ss.t2b WHERE t1.a % 25 = 0 ORDER BY t1.a;
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
 
+-- lateral references with clauses without equi-join on partition key
 EXPLAIN (VERBOSE, COSTS OFF)
 SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
-			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.b = t3.a AND t2.c = t3.c AND t2.b + t2.a = t3.a + t3.b)) ss
-			  ON t1.b = ss.t2a AND t1.b = ss.t2a AND t1.c = ss.t2c AND t1.b + t1.a = ss.t2a + ss.t2b WHERE t1.a % 25 = 0 ORDER BY t1.a;
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
 SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
-			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.b = t3.a AND t2.c = t3.c AND t2.b + t2.a = t3.a + t3.b)) ss
-			  ON t1.b = ss.t2a AND t1.b = ss.t2a AND t1.c = ss.t2c AND t1.b + t1.a = ss.t2a + ss.t2b WHERE t1.a % 25 = 0 ORDER BY t1.a;
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
 SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
-			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.b = t3.a AND t2.c = t3.c AND t2.b + t2.a = t3.a + t3.b)) ss
-			  ON t1.b = ss.t2a AND t1.b = ss.t2a AND t1.c = ss.t2c AND t1.b + t1.a = ss.t2a + ss.t2b WHERE t1.a % 25 = 0 ORDER BY t1.a;
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
