diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index e9dc9d31f05..e6bc7023562 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -1650,8 +1650,6 @@ 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 @@ -1721,25 +1719,27 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query) 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. + * Since we have thrown away the GROUP BY clauses, we'd better get rid of + * the RTE_GROUP RTE and clear the hasGroupRTE flag. To safely get rid of + * the RTE_GROUP RTE without shifting the index of any subsequent RTE in + * the rtable, we convert the RTE to be RTE_RESULT type in-place, and zero + * out RTE_GROUP-specific fields. */ - foreach(lc, query->rtable) + if (query->hasGroupRTE) { - 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) + foreach_node(RangeTblEntry, rte, query->rtable) { - Assert(query->hasGroupRTE); - query->rtable = list_delete_cell(query->rtable, lc); - query->hasGroupRTE = false; - break; + if (rte->rtekind == RTE_GROUP) + { + rte->rtekind = RTE_RESULT; + rte->groupexprs = NIL; + + /* A query should only have one RTE_GROUP, so we can stop. */ + break; + } } + + query->hasGroupRTE = false; } return true;