From e5be91deda817cec4752b87555e50b6944a96a00 Mon Sep 17 00:00:00 2001
From: Yuya Watari <watari.yuya@gmail.com>
Date: Mon, 8 Aug 2022 15:50:51 +0900
Subject: [PATCH 2/3] Fix bugs

---
 contrib/postgres_fdw/postgres_fdw.c     |  8 +--
 src/backend/optimizer/path/equivclass.c | 69 +++++++++++++++++--------
 src/backend/optimizer/path/pathkeys.c   |  6 +--
 3 files changed, 54 insertions(+), 29 deletions(-)

diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 5687d0182f..6bbf10d679 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -7455,7 +7455,7 @@ find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec,
 	{
 		Expr	   *expr = (Expr *) lfirst(lc1);
 		Index		sgref = get_pathtarget_sortgroupref(target, i);
-		int			i;
+		int			j;
 
 		/* Ignore non-sort expressions */
 		if (sgref == 0 ||
@@ -7471,10 +7471,10 @@ find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec,
 			expr = ((RelabelType *) expr)->arg;
 
 		/* Locate an EquivalenceClass member matching this expr, if any */
-		i = -1;
-		while ((i = bms_next_member(ec->ec_member_indexes, i)) >= 0)
+		j = -1;
+		while ((j = bms_next_member(ec->ec_member_indexes, j)) >= 0)
 		{
-			EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
+			EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, j);
 			Expr	   *em_expr;
 
 			/* Don't match constants */
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index f0dc77a2a2..90c96de7d8 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -365,7 +365,33 @@ process_equivalence(PlannerInfo *root,
 		 * PathKeys.  We leave it behind with a link so that the merged EC can
 		 * be found.
 		 */
-		ec1->ec_member_indexes = bms_add_members(ec1->ec_member_indexes, ec2->ec_member_indexes);
+		/*
+		 * TODO: "bms_add_members(ec1->ec_member_indexes, ec2->ec_member_indexes)"
+		 * did not work to combine two EquivalenceClasses. This is probably because
+		 * the order of the EquivalenceMembers is different from the previous
+		 * implementation, which added the ec2's EquivalenceMembers to the end of
+		 * the list.
+		 */
+		i = -1;
+		while ((i = bms_next_member(ec2->ec_member_indexes, i)) >= 0)
+		{
+			EquivalenceMember  *em = (EquivalenceMember *) list_nth(root->eq_members, i);
+			int					em_index = list_length(root->eq_members);
+			int					j;
+
+			ec1->ec_member_indexes = bms_add_member(ec1->ec_member_indexes, em_index);
+			root->eq_members = lappend(root->eq_members, em);
+
+			j = -1;
+			while ((j = bms_next_member(em->em_relids, j)) > 0)
+			{
+				RelOptInfo *rel = root->simple_rel_array[j];
+				if (bms_equal(rel->relids, em->em_relids))
+				{
+					rel->eclass_member_indexes = bms_add_member(rel->eclass_member_indexes, em_index);
+				}
+			}
+		}
 		ec1->ec_sources = list_concat(ec1->ec_sources, ec2->ec_sources);
 		ec1->ec_derives = list_concat(ec1->ec_derives, ec2->ec_derives);
 		ec1->ec_relids = bms_join(ec1->ec_relids, ec2->ec_relids);
@@ -585,8 +611,10 @@ add_eq_member(PlannerInfo *root, EquivalenceClass *ec, Expr *expr,
 	while ((i = bms_next_member(relids, i)) > 0)
 	{
 		RelOptInfo *rel = root->simple_rel_array[i];
-
-		rel->eclass_member_indexes = bms_add_member(rel->eclass_member_indexes, em_index);
+		if (bms_equal(rel->relids, relids))
+		{
+			rel->eclass_member_indexes = bms_add_member(rel->eclass_member_indexes, em_index);
+		}
 	}
 
 	return em;
@@ -2366,19 +2394,14 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
 			cur_ec->ec_member_indexes = bms_del_member(cur_ec->ec_member_indexes, coal_idx);
 
 			/* Remove the member from each of the relations */
-			/* XXX check this is right. Is there a neater way? */
-			i = -1;
-			while ((i = bms_next_member(left_relids, i)) > 0)
-			{
-				RelOptInfo *rel = root->simple_rel_array[i];
-				rel->eclass_member_indexes = bms_del_member(rel->eclass_member_indexes, i);
-			}
-
 			i = -1;
-			while ((i = bms_next_member(right_relids, i)) > 0)
+			while ((i = bms_next_member(coal_em->em_relids, i)) > 0)
 			{
 				RelOptInfo *rel = root->simple_rel_array[i];
-				rel->eclass_member_indexes = bms_del_member(rel->eclass_member_indexes, i);
+				if (bms_equal(rel->relids, coal_em->em_relids))
+				{
+					rel->eclass_member_indexes = bms_del_member(rel->eclass_member_indexes, coal_idx);
+				}
 			}
 
 			return true;
@@ -2490,16 +2513,17 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
 															 i);
 		EquivalenceMember *item1_em = NULL;
 		EquivalenceMember *item2_em = NULL;
+		int					j;
 
 		/* Never match to a volatile EC */
 		if (ec->ec_has_volatile)
 			continue;
 		/* Note: it seems okay to match to "broken" eclasses here */
 
-		i = -1;
-		while ((i = bms_next_member(ec->ec_member_indexes, i)) >= 0)
+		j = -1;
+		while ((j = bms_next_member(ec->ec_member_indexes, j)) >= 0)
 		{
-			EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, i);
+			EquivalenceMember *em = (EquivalenceMember *) list_nth(root->eq_members, j);
 			Var		   *var;
 
 			if (em->em_is_child)
@@ -2914,6 +2938,7 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 	{
 		EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
 		EquivalenceMember *cur_em;
+		int					j;
 
 		/* Sanity check eclass_indexes only contain ECs for rel */
 		Assert(is_child_rel || bms_is_subset(rel->relids, cur_ec->ec_relids));
@@ -2937,10 +2962,10 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 		 * match.  See also get_eclass_for_sort_expr.)
 		 */
 		cur_em = NULL;
-		i = -1;
-		while ((i = bms_next_member(cur_ec->ec_member_indexes, i)) >= 0)
+		j = -1;
+		while ((j = bms_next_member(cur_ec->ec_member_indexes, j)) >= 0)
 		{
-			cur_em = (EquivalenceMember *) list_nth(root->eq_members, i);
+			cur_em = (EquivalenceMember *) list_nth(root->eq_members, j);
 
 			if (bms_equal(cur_em->em_relids, rel->relids) &&
 				callback(root, rel, cur_ec, cur_em, callback_arg))
@@ -2955,10 +2980,10 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 		 * Found our match.  Scan the other EC members and attempt to generate
 		 * joinclauses.
 		 */
-		i = -1;
-		while ((i = bms_next_member(cur_ec->ec_member_indexes, i)) >= 0)
+		j = -1;
+		while ((j = bms_next_member(cur_ec->ec_member_indexes, j)) >= 0)
 		{
-			EquivalenceMember *other_em = (EquivalenceMember *) list_nth(root->eq_members, i);
+			EquivalenceMember *other_em = (EquivalenceMember *) list_nth(root->eq_members, j);
 			Oid			eq_op;
 			RestrictInfo *rinfo;
 
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 1a38aa57a7..de864023b2 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -1490,11 +1490,11 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
 			 * outer query.
 			 */
 			int			best_score = -1;
-			int			i = -1;
+			int			j = -1;
 
-			while ((i = bms_next_member(sub_eclass->ec_member_indexes, i)) >= 0)
+			while ((j = bms_next_member(sub_eclass->ec_member_indexes, j)) >= 0)
 			{
-				EquivalenceMember *sub_member = (EquivalenceMember *) list_nth(rel->subroot->eq_members, i);
+				EquivalenceMember *sub_member = (EquivalenceMember *) list_nth(rel->subroot->eq_members, j);
 				Expr	   *sub_expr = sub_member->em_expr;
 				Oid			sub_expr_type = sub_member->em_datatype;
 				Oid			sub_expr_coll = sub_eclass->ec_collation;
-- 
2.35.3.windows.1

