From d8ead6d480e1454e1e18e5797bb6fe18ce09aef4 Mon Sep 17 00:00:00 2001 From: Richard Guo 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