v1-0001-Remove-references-to-the-removed-rel-from-EquivalenceClasses.patch

application/octet-stream

Filename: v1-0001-Remove-references-to-the-removed-rel-from-EquivalenceClasses.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #17976: Inconsistent results of SELECT using CASE WHEN clause

Patch

Format: format-patch
Series: patch v1-0001
Subject: Remove references to the removed rel from EquivalenceClasses
File+
src/backend/optimizer/plan/analyzejoins.c 31 0
src/test/regress/expected/join.out 31 0
src/test/regress/sql/join.sql 23 0
From d8ead6d480e1454e1e18e5797bb6fe18ce09aef4 Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Thu, 15 Jun 2023 14:36:31 +0800
Subject: [PATCH v1] Remove references to the removed rel from
 EquivalenceClasses

---
 src/backend/optimizer/plan/analyzejoins.c | 31 +++++++++++++++++++++++
 src/test/regress/expected/join.out        | 31 +++++++++++++++++++++++
 src/test/regress/sql/join.sql             | 23 +++++++++++++++++
 3 files changed, 85 insertions(+)

diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 6476e55e56..f00e99b077 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -335,6 +335,7 @@ remove_rel_from_query(PlannerInfo *root, int relid, SpecialJoinInfo *sjinfo)
 	List	   *joininfos;
 	Index		rti;
 	ListCell   *l;
+	int			i;
 
 	/* Compute the relid set for the join we are considering */
 	joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
@@ -449,6 +450,36 @@ remove_rel_from_query(PlannerInfo *root, int relid, SpecialJoinInfo *sjinfo)
 		}
 	}
 
+	/*
+	 * Likewise remove references from EquivalenceClasses.
+	 */
+	i = -1;
+	while ((i = bms_next_member(rel->eclass_indexes, i)) >= 0)
+	{
+		EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
+
+		/* Sanity check eclass_indexes only contain ECs for rel */
+		Assert(bms_is_subset(rel->relids, cur_ec->ec_relids));
+
+		cur_ec->ec_relids = bms_del_member(cur_ec->ec_relids, relid);
+		cur_ec->ec_relids = bms_del_member(cur_ec->ec_relids, ojrelid);
+
+		foreach(l, cur_ec->ec_members)
+		{
+			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(l);
+
+			cur_em->em_relids = bms_del_member(cur_em->em_relids, relid);
+			cur_em->em_relids = bms_del_member(cur_em->em_relids, ojrelid);
+		}
+
+		foreach(l, cur_ec->ec_sources)
+		{
+			RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+
+			remove_rel_from_restrictinfo(rinfo, relid, ojrelid);
+		}
+	}
+
 	/*
 	 * Remove any joinquals referencing the rel from the joininfo lists.
 	 *
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 98b2667821..cc4c122fdd 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -5881,6 +5881,37 @@ where ss.stringu2 !~* ss.case1;
  doh!
 (1 row)
 
+rollback;
+-- another join removal bug: we must clean up EquivalenceClasses too
+begin;
+create temp table t (a int unique);
+insert into t values (1);
+explain (costs off)
+select 1
+from t t1
+  left join (select 2 as c
+             from t t2 left join t t3 on t2.a = t3.a) s
+    on true
+where t1.a = s.c;
+          QUERY PLAN          
+------------------------------
+ Nested Loop Left Join
+   Filter: (t1.a = (2))
+   ->  Seq Scan on t t1
+   ->  Materialize
+         ->  Seq Scan on t t2
+(5 rows)
+
+select 1
+from t t1
+  left join (select 2 as c
+             from t t2 left join t t3 on t2.a = t3.a) s
+    on true
+where t1.a = s.c;
+ ?column? 
+----------
+(0 rows)
+
 rollback;
 -- test cases where we can remove a join, but not a PHV computed at it
 begin;
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 7daa390b1d..e77e469570 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -2167,6 +2167,29 @@ where ss.stringu2 !~* ss.case1;
 
 rollback;
 
+-- another join removal bug: we must clean up EquivalenceClasses too
+begin;
+
+create temp table t (a int unique);
+insert into t values (1);
+
+explain (costs off)
+select 1
+from t t1
+  left join (select 2 as c
+             from t t2 left join t t3 on t2.a = t3.a) s
+    on true
+where t1.a = s.c;
+
+select 1
+from t t1
+  left join (select 2 as c
+             from t t2 left join t t3 on t2.a = t3.a) s
+    on true
+where t1.a = s.c;
+
+rollback;
+
 -- test cases where we can remove a join, but not a PHV computed at it
 begin;
 
-- 
2.31.0