diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index a5424c9d24c..6834a3cb4c1 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -1424,6 +1424,37 @@ substitute_grouped_columns_mutator(Node *node, return node; } + /* + * GROUP BY of a Const or Param refers to one targetlist entry. Other + * occurrences of the same value are not that column, so they must not + * be replaced. + */ + if (context->sublevels_up == 0 && + context->have_non_var_grouping && + IsA(node, TargetEntry)) + { + TargetEntry *tle = (TargetEntry *) node; + int attnum = 0; + + foreach(gl, context->groupClauses) + { + TargetEntry *grouptle = (TargetEntry *) lfirst(gl); + + attnum++; + if (tle->ressortgroupref == grouptle->ressortgroupref && + grouptle->ressortgroupref != 0 && + (IsA(grouptle->expr, Const) || IsA(grouptle->expr, Param))) + { + TargetEntry *newtle = copyObject(tle); + + newtle->expr = (Expr *) buildGroupedVar(attnum, + grouptle->ressortgroupref, + context); + return (Node *) newtle; + } + } + } + /* * If we have any GROUP BY items that are not simple Vars, check to see if * subexpression as a whole matches any GROUP BY item. We need to do this @@ -1448,6 +1479,13 @@ substitute_grouped_columns_mutator(Node *node, TargetEntry *tle = (TargetEntry *) lfirst(gl); attnum++; + + /* + * Const and Param items were matched by targetlist entry above. + */ + if (IsA(tle->expr, Const) || IsA(tle->expr, Param)) + continue; + if (equal(node, tle->expr)) { /* acceptable, replace it with a GROUP Var */ @@ -1459,10 +1497,9 @@ substitute_grouped_columns_mutator(Node *node, } /* - * Constants are always acceptable. We have to do this after we checked - * the subexpression as a whole for a match, because it is possible that - * we have GROUP BY items that are constants, and the constants would - * become not so constant after the grouping step. + * Constants are always acceptable. The grouped Const or Param itself + * was replaced with its targetlist entry. Any other constant is still + * constant after grouping. */ if (IsA(node, Const) || IsA(node, Param)) diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out index 08d5ce3156d..93e8c3e7307 100644 --- a/src/test/regress/expected/groupingsets.out +++ b/src/test/regress/expected/groupingsets.out @@ -2762,4 +2762,44 @@ order by 1, 2; 2 | (6 rows) +-- a grouped Const names one targetlist entry, not every equal Const +select ARRAY[]::varchar(500)[] as a +group by cast('true' as boolean); + a +---- + {} +(1 row) + +select ARRAY[]::char(1)[] as a +group by cast(true as boolean); + a +---- + {} +(1 row) + +select ARRAY[]::varchar(500)[] as a +group by cast(500 as int); + a +---- + {} +(1 row) + +select 'ab'::varchar(5) as v, true as t +group by grouping sets ((cast(true as boolean)), ()) +order by t; + v | t +----+--- + ab | t + ab | +(2 rows) + +select ARRAY[]::varchar(5)[] as a, true as t +group by grouping sets ((cast(true as boolean)), ()) +order by t; + a | t +----+--- + {} | t + {} | +(2 rows) + -- end diff --git a/src/test/regress/sql/groupingsets.sql b/src/test/regress/sql/groupingsets.sql index c5d4ed2eb57..4afc20077a8 100644 --- a/src/test/regress/sql/groupingsets.sql +++ b/src/test/regress/sql/groupingsets.sql @@ -803,4 +803,22 @@ from (values (1, 1), (2, 2)) as t (a, b) group by rollup(a, ab) order by 1, 2; +-- a grouped Const names one targetlist entry, not every equal Const +select ARRAY[]::varchar(500)[] as a +group by cast('true' as boolean); + +select ARRAY[]::char(1)[] as a +group by cast(true as boolean); + +select ARRAY[]::varchar(500)[] as a +group by cast(500 as int); + +select 'ab'::varchar(5) as v, true as t +group by grouping sets ((cast(true as boolean)), ()) +order by t; + +select ARRAY[]::varchar(5)[] as a, true as t +group by grouping sets ((cast(true as boolean)), ()) +order by t; + -- end