From 9984fc3398e8e27626c356cbd9dc13d9d63a13e2 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 27 Jun 2019 14:23:42 +0900
Subject: [PATCH 2/2] Translate multi-relation EC members in a separate pass

It's not correct to translate a given multi-relation EC member when
not all parent-child relation pairs (in the form AppendRelInfos) are
available for translation.

For example, EC expressions that can only be emitted by joinrels
should only be translated if there corresponding child joinrels
are present, that is, only if using partitionwise join.
---
 src/backend/optimizer/path/allpaths.c        |   2 +-
 src/backend/optimizer/path/equivclass.c      |  51 ++++--
 src/backend/optimizer/util/relnode.c         |  14 +-
 src/include/optimizer/paths.h                |   3 +-
 src/test/regress/expected/partition_join.out | 243 ++++++++++++++++++++++++++-
 5 files changed, 285 insertions(+), 28 deletions(-)

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index b7723481b0..0a95e7221d 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1067,7 +1067,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		 * paths that produce those sort orderings).
 		 */
 		if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
-			add_child_rel_equivalences(root, appinfo, rel, childrel);
+			add_child_rel_equivalences(root, &appinfo, 1, rel, childrel);
 		childrel->has_eclass_joins = rel->has_eclass_joins;
 
 		/*
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 688d9b0707..bbeaf5b17e 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -2109,12 +2109,15 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
  * Note that this function won't be called at all unless we have at least some
  * reason to believe that the EC members it generates will be useful.
  *
- * parent_rel and child_rel could be derived from appinfo, but since the
+ * parent_rel and child_rel could be derived from appinfos, but since the
  * caller has already computed them, we might as well just pass them in.
+ * Note that parent_rel and child_rel are either BASEREL and OTHER_MEMBER_REL,
+ * respectively, or JOINREL and OTHER_JOINREL.
  */
 void
 add_child_rel_equivalences(PlannerInfo *root,
-						   AppendRelInfo *appinfo,
+						   AppendRelInfo **appinfos,
+						   int		nappinfos,
 						   RelOptInfo *parent_rel,
 						   RelOptInfo *child_rel)
 {
@@ -2123,6 +2126,7 @@ add_child_rel_equivalences(PlannerInfo *root,
 	foreach(lc1, root->eq_classes)
 	{
 		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
+		EquivalenceMember *first_em;
 		ListCell   *lc2;
 
 		/*
@@ -2133,11 +2137,23 @@ add_child_rel_equivalences(PlannerInfo *root,
 		if (cur_ec->ec_has_volatile)
 			continue;
 
+		first_em = (EquivalenceMember *) linitial(cur_ec->ec_members);
+
+		/*
+		 * Single-relation EC members would already have been translated
+		 * by the time we begin looking for multi-relation EC members, so
+		 * no need to consider those.  Note that looking at the first
+		 * element is enough, because the rest should look the same.
+		 */
+		if (bms_membership(parent_rel->relids) == BMS_MULTIPLE &&
+			bms_membership(first_em->em_relids) == BMS_SINGLETON)
+			continue;
+
 		/*
 		 * No point in searching if child's topmost parent rel is not
 		 * mentioned in eclass.
 		 */
-		if (!bms_is_subset(child_rel->top_parent_relids, cur_ec->ec_relids))
+		if (!bms_overlap(child_rel->top_parent_relids, cur_ec->ec_relids))
 			continue;
 
 		foreach(lc2, cur_ec->ec_members)
@@ -2147,34 +2163,31 @@ add_child_rel_equivalences(PlannerInfo *root,
 			if (cur_em->em_is_const)
 				continue;		/* ignore consts here */
 
-			/*
-			 * We consider only original EC members here, not
-			 * already-transformed child members.  Otherwise, if some original
-			 * member expression references more than one appendrel, we'd get
-			 * an O(N^2) explosion of useless derived expressions for
-			 * combinations of children.
-			 */
-			if (cur_em->em_is_child)
-				continue;		/* ignore children here */
-
 			/* Does this member reference child's topmost parent rel? */
-			if (bms_overlap(cur_em->em_relids, child_rel->top_parent_relids))
+			if (bms_is_subset(cur_em->em_relids, child_rel->top_parent_relids))
 			{
 				/* Yes, generate transformed child version */
 				Expr	   *child_expr;
 				Relids		new_relids;
 				Relids		new_nullable_relids;
 
-				if (parent_rel->reloptkind == RELOPT_BASEREL)
+				/*
+				 * If the parent_rel is itself the topmost parent rel, transform
+				 * directly.
+				 */
+				if (parent_rel->reloptkind == RELOPT_BASEREL ||
+					parent_rel->reloptkind == RELOPT_JOINREL)
 				{
 					/* Simple single-level transformation */
 					child_expr = (Expr *)
 						adjust_appendrel_attrs(root,
 											   (Node *) cur_em->em_expr,
-											   1, &appinfo);
+											   nappinfos, appinfos);
 				}
 				else
 				{
+					Assert(parent_rel->reloptkind == RELOPT_OTHER_MEMBER_REL ||
+						   parent_rel->reloptkind == RELOPT_OTHER_JOINREL);
 					/* Must do multi-level transformation */
 					child_expr = (Expr *)
 						adjust_appendrel_attrs_multilevel(root,
@@ -2210,6 +2223,12 @@ add_child_rel_equivalences(PlannerInfo *root,
 				(void) add_eq_member(cur_ec, child_expr,
 									 new_relids, new_nullable_relids,
 									 true, cur_em->em_datatype);
+
+				/*
+				 * There aren't going to be more expressions to translate in
+				 * the same EC.
+				 */
+				break;
 			}
 		}
 	}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 80de20f13d..ac914f3ae1 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -851,6 +851,16 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 														(Node *) parent_joinrel->joininfo,
 														nappinfos,
 														appinfos);
+
+	/*
+	 * If the parent joinrel has pending equivalence classes, so does the
+	 * child.
+	 */
+	if (parent_joinrel->has_eclass_joins ||
+		has_useful_pathkeys(root, parent_joinrel))
+			add_child_rel_equivalences(root, appinfos, nappinfos,
+									   parent_joinrel, joinrel);
+
 	pfree(appinfos);
 
 	/*
@@ -863,10 +873,6 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	joinrel->direct_lateral_relids = (Relids) bms_copy(parent_joinrel->direct_lateral_relids);
 	joinrel->lateral_relids = (Relids) bms_copy(parent_joinrel->lateral_relids);
 
-	/*
-	 * If the parent joinrel has pending equivalence classes, so does the
-	 * child.
-	 */
 	joinrel->has_eclass_joins = parent_joinrel->has_eclass_joins;
 
 	/* Is the join between partitions itself partitioned? */
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 7345137d1d..832cc84bb4 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -150,7 +150,8 @@ extern EquivalenceClass *match_eclasses_to_foreign_key_col(PlannerInfo *root,
 														   ForeignKeyOptInfo *fkinfo,
 														   int colno);
 extern void add_child_rel_equivalences(PlannerInfo *root,
-									   AppendRelInfo *appinfo,
+									   AppendRelInfo **appinfos,
+									   int		nappinfos,
 									   RelOptInfo *parent_rel,
 									   RelOptInfo *child_rel);
 extern List *generate_implied_equalities_for_column(PlannerInfo *root,
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 885f754f10..a952d059c5 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -2190,16 +2190,247 @@ SELECT * FROM prt1_n t1 INNER JOIN prt1_n t2 USING (c) FULL JOIN prt1_n t3 USING
 SET enable_hashjoin TO off;
 EXPLAIN (COSTS OFF)
 SELECT * FROM prt1_n t1 FULL JOIN prt1_n t2 USING (c) FULL JOIN prt1_n t3 USING (c) FULL JOIN prt1_n t4 USING (c) ORDER BY c LIMIT 5;
-ERROR:  could not find pathkey item to sort
+                                               QUERY PLAN                                                
+---------------------------------------------------------------------------------------------------------
+ Limit
+   ->  Sort
+         Sort Key: (COALESCE(COALESCE(COALESCE(t1.c, t2.c), t3.c), t4.c))
+         ->  Append
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(COALESCE(t1.c, t2.c), t3.c))::text) = (t4.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(COALESCE(t1.c, t2.c), t3.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: (((COALESCE(t1.c, t2.c))::text) = (t3.c)::text)
+                                 ->  Sort
+                                       Sort Key: ((COALESCE(t1.c, t2.c))::text)
+                                       ->  Merge Full Join
+                                             Merge Cond: ((t1.c)::text = (t2.c)::text)
+                                             ->  Sort
+                                                   Sort Key: t1.c
+                                                   ->  Seq Scan on prt1_n_p1 t1
+                                             ->  Sort
+                                                   Sort Key: t2.c
+                                                   ->  Seq Scan on prt1_n_p1 t2
+                                 ->  Sort
+                                       Sort Key: t3.c
+                                       ->  Seq Scan on prt1_n_p1 t3
+                     ->  Sort
+                           Sort Key: t4.c
+                           ->  Seq Scan on prt1_n_p1 t4
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(COALESCE(t1_1.c, t2_1.c), t3_1.c))::text) = (t4_1.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(COALESCE(t1_1.c, t2_1.c), t3_1.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: (((COALESCE(t1_1.c, t2_1.c))::text) = (t3_1.c)::text)
+                                 ->  Sort
+                                       Sort Key: ((COALESCE(t1_1.c, t2_1.c))::text)
+                                       ->  Merge Full Join
+                                             Merge Cond: ((t1_1.c)::text = (t2_1.c)::text)
+                                             ->  Sort
+                                                   Sort Key: t1_1.c
+                                                   ->  Seq Scan on prt1_n_p2_1 t1_1
+                                             ->  Sort
+                                                   Sort Key: t2_1.c
+                                                   ->  Seq Scan on prt1_n_p2_1 t2_1
+                                 ->  Sort
+                                       Sort Key: t3_1.c
+                                       ->  Seq Scan on prt1_n_p2_1 t3_1
+                     ->  Sort
+                           Sort Key: t4_1.c
+                           ->  Seq Scan on prt1_n_p2_1 t4_1
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(COALESCE(t1_2.c, t2_2.c), t3_2.c))::text) = (t4_2.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(COALESCE(t1_2.c, t2_2.c), t3_2.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: (((COALESCE(t1_2.c, t2_2.c))::text) = (t3_2.c)::text)
+                                 ->  Sort
+                                       Sort Key: ((COALESCE(t1_2.c, t2_2.c))::text)
+                                       ->  Merge Full Join
+                                             Merge Cond: ((t1_2.c)::text = (t2_2.c)::text)
+                                             ->  Sort
+                                                   Sort Key: t1_2.c
+                                                   ->  Seq Scan on prt1_n_p2_2 t1_2
+                                             ->  Sort
+                                                   Sort Key: t2_2.c
+                                                   ->  Seq Scan on prt1_n_p2_2 t2_2
+                                 ->  Sort
+                                       Sort Key: t3_2.c
+                                       ->  Seq Scan on prt1_n_p2_2 t3_2
+                     ->  Sort
+                           Sort Key: t4_2.c
+                           ->  Seq Scan on prt1_n_p2_2 t4_2
+(70 rows)
+
 SELECT * FROM prt1_n t1 FULL JOIN prt1_n t2 USING (c) FULL JOIN prt1_n t3 USING (c) FULL JOIN prt1_n t4 USING (c) ORDER BY c LIMIT 5;
-ERROR:  could not find pathkey item to sort
+  c   | a | b | a | b | a | b | a | b 
+------+---+---+---+---+---+---+---+---
+ 0000 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 0002 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2
+ 0004 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4
+ 0006 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6
+ 0008 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8
+(5 rows)
+
 EXPLAIN (COSTS OFF)
 SELECT * FROM prt1_n t1 LEFT JOIN prt1_n t2 USING (c) FULL JOIN prt1_n t3 USING (c) FULL JOIN prt1_n t4 USING (c) ORDER BY c LIMIT 5;
-ERROR:  could not find pathkey item to sort
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Limit
+   ->  Sort
+         Sort Key: (COALESCE(COALESCE(t1.c, t3.c), t4.c))
+         ->  Append
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(t1.c, t3.c))::text) = (t4.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(t1.c, t3.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: ((t1.c)::text = (t3.c)::text)
+                                 ->  Merge Left Join
+                                       Merge Cond: ((t1.c)::text = (t2.c)::text)
+                                       ->  Sort
+                                             Sort Key: t1.c
+                                             ->  Seq Scan on prt1_n_p1 t1
+                                       ->  Sort
+                                             Sort Key: t2.c
+                                             ->  Seq Scan on prt1_n_p1 t2
+                                 ->  Sort
+                                       Sort Key: t3.c
+                                       ->  Seq Scan on prt1_n_p1 t3
+                     ->  Sort
+                           Sort Key: t4.c
+                           ->  Seq Scan on prt1_n_p1 t4
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(t1_1.c, t3_1.c))::text) = (t4_1.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(t1_1.c, t3_1.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: ((t1_1.c)::text = (t3_1.c)::text)
+                                 ->  Merge Left Join
+                                       Merge Cond: ((t1_1.c)::text = (t2_1.c)::text)
+                                       ->  Sort
+                                             Sort Key: t1_1.c
+                                             ->  Seq Scan on prt1_n_p2_1 t1_1
+                                       ->  Sort
+                                             Sort Key: t2_1.c
+                                             ->  Seq Scan on prt1_n_p2_1 t2_1
+                                 ->  Sort
+                                       Sort Key: t3_1.c
+                                       ->  Seq Scan on prt1_n_p2_1 t3_1
+                     ->  Sort
+                           Sort Key: t4_1.c
+                           ->  Seq Scan on prt1_n_p2_1 t4_1
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(t1_2.c, t3_2.c))::text) = (t4_2.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(t1_2.c, t3_2.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: ((t1_2.c)::text = (t3_2.c)::text)
+                                 ->  Merge Left Join
+                                       Merge Cond: ((t1_2.c)::text = (t2_2.c)::text)
+                                       ->  Sort
+                                             Sort Key: t1_2.c
+                                             ->  Seq Scan on prt1_n_p2_2 t1_2
+                                       ->  Sort
+                                             Sort Key: t2_2.c
+                                             ->  Seq Scan on prt1_n_p2_2 t2_2
+                                 ->  Sort
+                                       Sort Key: t3_2.c
+                                       ->  Seq Scan on prt1_n_p2_2 t3_2
+                     ->  Sort
+                           Sort Key: t4_2.c
+                           ->  Seq Scan on prt1_n_p2_2 t4_2
+(64 rows)
+
 SELECT * FROM prt1_n t1 LEFT JOIN prt1_n t2 USING (c) FULL JOIN prt1_n t3 USING (c) FULL JOIN prt1_n t4 USING (c) ORDER BY c LIMIT 5;
-ERROR:  could not find pathkey item to sort
+  c   | a | b | a | b | a | b | a | b 
+------+---+---+---+---+---+---+---+---
+ 0000 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 0002 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2
+ 0004 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4
+ 0006 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6
+ 0008 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8
+(5 rows)
+
 EXPLAIN (COSTS OFF)
 SELECT * FROM prt1_n t1 INNER JOIN prt1_n t2 USING (c) FULL JOIN prt1_n t3 USING (c) FULL JOIN prt1_n t4 USING (c) ORDER BY c LIMIT 5;
-ERROR:  could not find pathkey item to sort
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Limit
+   ->  Sort
+         Sort Key: (COALESCE(COALESCE(t1.c, t3.c), t4.c))
+         ->  Append
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(t1.c, t3.c))::text) = (t4.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(t1.c, t3.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: ((t1.c)::text = (t3.c)::text)
+                                 ->  Merge Join
+                                       Merge Cond: ((t1.c)::text = (t2.c)::text)
+                                       ->  Sort
+                                             Sort Key: t1.c
+                                             ->  Seq Scan on prt1_n_p1 t1
+                                       ->  Sort
+                                             Sort Key: t2.c
+                                             ->  Seq Scan on prt1_n_p1 t2
+                                 ->  Sort
+                                       Sort Key: t3.c
+                                       ->  Seq Scan on prt1_n_p1 t3
+                     ->  Sort
+                           Sort Key: t4.c
+                           ->  Seq Scan on prt1_n_p1 t4
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(t1_1.c, t3_1.c))::text) = (t4_1.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(t1_1.c, t3_1.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: ((t1_1.c)::text = (t3_1.c)::text)
+                                 ->  Merge Join
+                                       Merge Cond: ((t1_1.c)::text = (t2_1.c)::text)
+                                       ->  Sort
+                                             Sort Key: t1_1.c
+                                             ->  Seq Scan on prt1_n_p2_1 t1_1
+                                       ->  Sort
+                                             Sort Key: t2_1.c
+                                             ->  Seq Scan on prt1_n_p2_1 t2_1
+                                 ->  Sort
+                                       Sort Key: t3_1.c
+                                       ->  Seq Scan on prt1_n_p2_1 t3_1
+                     ->  Sort
+                           Sort Key: t4_1.c
+                           ->  Seq Scan on prt1_n_p2_1 t4_1
+               ->  Merge Full Join
+                     Merge Cond: (((COALESCE(t1_2.c, t3_2.c))::text) = (t4_2.c)::text)
+                     ->  Sort
+                           Sort Key: ((COALESCE(t1_2.c, t3_2.c))::text)
+                           ->  Merge Full Join
+                                 Merge Cond: ((t1_2.c)::text = (t3_2.c)::text)
+                                 ->  Merge Join
+                                       Merge Cond: ((t1_2.c)::text = (t2_2.c)::text)
+                                       ->  Sort
+                                             Sort Key: t1_2.c
+                                             ->  Seq Scan on prt1_n_p2_2 t1_2
+                                       ->  Sort
+                                             Sort Key: t2_2.c
+                                             ->  Seq Scan on prt1_n_p2_2 t2_2
+                                 ->  Sort
+                                       Sort Key: t3_2.c
+                                       ->  Seq Scan on prt1_n_p2_2 t3_2
+                     ->  Sort
+                           Sort Key: t4_2.c
+                           ->  Seq Scan on prt1_n_p2_2 t4_2
+(64 rows)
+
 SELECT * FROM prt1_n t1 INNER JOIN prt1_n t2 USING (c) FULL JOIN prt1_n t3 USING (c) FULL JOIN prt1_n t4 USING (c) ORDER BY c LIMIT 5;
-ERROR:  could not find pathkey item to sort
+  c   | a | b | a | b | a | b | a | b 
+------+---+---+---+---+---+---+---+---
+ 0000 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 0002 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2
+ 0004 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4
+ 0006 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6
+ 0008 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8
+(5 rows)
+
-- 
2.11.0

