Remove the RTE_GROUP RTE if we drop the groupClause
authorRichard Guo <[email protected]>
Fri, 25 Oct 2024 00:52:34 +0000 (09:52 +0900)
committerRichard Guo <[email protected]>
Fri, 25 Oct 2024 00:52:34 +0000 (09:52 +0900)
For an EXISTS subquery, the only thing that matters is whether it
returns zero or more than zero rows.  Therefore, we remove certain SQL
features that won't affect that, among them the GROUP BY clauses.

After we drop the groupClause, we'd better remove the RTE_GROUP RTE
and clear the hasGroupRTE flag, as they depend on the groupClause.
Failing to do so could result in a bogus RTE_GROUP entry in the parent
query, leading to an assertion failure on the hasGroupRTE flag.

Reported-by: David Rowley
Author: Richard Guo
Discussion: https://postgr.es/m/CAApHDvp2_yht8uPLyWO-kVGWZhYvx5zjGfSrg4fBQ9fsC13V0g@mail.gmail.com

src/backend/optimizer/plan/subselect.c
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 6d003cc8e5cbef49da0c9fb579986045ac7677d5..09d5f0f571bb3d371c06ab43abf1a455d3035c4a 100644 (file)
@@ -1539,6 +1539,8 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
 static bool
 simplify_EXISTS_query(PlannerInfo *root, Query *query)
 {
+   ListCell   *lc;
+
    /*
     * We don't try to simplify at all if the query uses set operations,
     * aggregates, grouping sets, SRFs, modifying CTEs, HAVING, OFFSET, or FOR
@@ -1607,6 +1609,28 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query)
    query->sortClause = NIL;
    query->hasDistinctOn = false;
 
+   /*
+    * Since we have thrown away the GROUP BY clauses, we'd better remove the
+    * RTE_GROUP RTE and clear the hasGroupRTE flag.
+    */
+   foreach(lc, query->rtable)
+   {
+       RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
+
+       /*
+        * Remove the RTE_GROUP RTE and clear the hasGroupRTE flag.  (Since
+        * we'll exit the foreach loop immediately, we don't bother with
+        * foreach_delete_current.)
+        */
+       if (rte->rtekind == RTE_GROUP)
+       {
+           Assert(query->hasGroupRTE);
+           query->rtable = list_delete_cell(query->rtable, lc);
+           query->hasGroupRTE = false;
+           break;
+       }
+   }
+
    return true;
 }
 
index 5669ed929a7ea0f3c9b35eb147d557fa1662a626..9b2973694ffb285a7f5df7433d4dec0ba792f9d6 100644 (file)
@@ -3182,6 +3182,21 @@ where b.unique2 is null;
          ->  Index Only Scan using tenk1_unique2 on tenk1 b
 (5 rows)
 
+--
+-- regression test for bogus RTE_GROUP entries
+--
+explain (costs off)
+select a.* from tenk1 a
+where exists (select 1 from tenk1 b where a.unique1 = b.unique2 group by b.unique1);
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Hash Semi Join
+   Hash Cond: (a.unique1 = b.unique2)
+   ->  Seq Scan on tenk1 a
+   ->  Hash
+         ->  Index Only Scan using tenk1_unique2 on tenk1 b
+(5 rows)
+
 --
 -- regression test for proper handling of outer joins within antijoins
 --
index 73474bb64f57035f14d95d129d895d90c9550101..4c9c3e9f49be1bb2bf073adc402d9eb04b50c915 100644 (file)
@@ -818,6 +818,14 @@ explain (costs off)
 select a.* from tenk1 a left join tenk1 b on a.unique1 = b.unique2
 where b.unique2 is null;
 
+--
+-- regression test for bogus RTE_GROUP entries
+--
+
+explain (costs off)
+select a.* from tenk1 a
+where exists (select 1 from tenk1 b where a.unique1 = b.unique2 group by b.unique1);
+
 --
 -- regression test for proper handling of outer joins within antijoins
 --