summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/nodeFuncs.c2
-rw-r--r--src/backend/optimizer/path/costsize.c6
-rw-r--r--src/backend/optimizer/plan/subselect.c30
-rw-r--r--src/backend/utils/adt/ruleutils.c10
-rw-r--r--src/test/regress/expected/groupingsets.out49
-rw-r--r--src/test/regress/sql/groupingsets.sql9
6 files changed, 92 insertions, 14 deletions
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index ede9dd0d428..43b110d7704 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -697,6 +697,8 @@ expression_returns_set_walker(Node *node, void *context)
/* Avoid recursion for some cases that parser checks not to return a set */
if (IsA(node, Aggref))
return false;
+ if (IsA(node, GroupingFunc))
+ return false;
if (IsA(node, WindowFunc))
return false;
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index eacab3e7854..ef1b6c36b38 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -3596,6 +3596,12 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
*/
return false; /* don't recurse into children */
}
+ else if (IsA(node, GroupingFunc))
+ {
+ /* Treat this as having cost 1 */
+ context->total.per_tuple += cpu_operator_cost;
+ return false; /* don't recurse into children */
+ }
else if (IsA(node, CoerceViaIO))
{
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index e5b5692b5a7..cf0e5de3f43 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -357,15 +357,17 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
Node *arg = pitem->item;
/*
- * The Var, PlaceHolderVar, or Aggref has already been adjusted to
- * have the correct varlevelsup, phlevelsup, or agglevelsup.
+ * The Var, PlaceHolderVar, Aggref or GroupingFunc has already been
+ * adjusted to have the correct varlevelsup, phlevelsup, or
+ * agglevelsup.
*
- * If it's a PlaceHolderVar or Aggref, its arguments might contain
- * SubLinks, which have not yet been processed (see the comments for
- * SS_replace_correlation_vars). Do that now.
+ * If it's a PlaceHolderVar, Aggref or GroupingFunc, its arguments
+ * might contain SubLinks, which have not yet been processed (see the
+ * comments for SS_replace_correlation_vars). Do that now.
*/
if (IsA(arg, PlaceHolderVar) ||
- IsA(arg, Aggref))
+ IsA(arg, Aggref) ||
+ IsA(arg, GroupingFunc))
arg = SS_process_sublinks(root, arg, false);
splan->parParam = lappend_int(splan->parParam, pitem->paramId);
@@ -1705,10 +1707,11 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
}
/*
- * Don't recurse into the arguments of an outer PHV or aggregate here. Any
- * SubLinks in the arguments have to be dealt with at the outer query
- * level; they'll be handled when build_subplan collects the PHV or Aggref
- * into the arguments to be passed down to the current subplan.
+ * Don't recurse into the arguments of an outer PHV, Aggref or
+ * GroupingFunc here. Any SubLinks in the arguments have to be dealt with
+ * at the outer query level; they'll be handled when build_subplan
+ * collects the PHV, Aggref or GroupingFunc into the arguments to be
+ * passed down to the current subplan.
*/
if (IsA(node, PlaceHolderVar))
{
@@ -1720,6 +1723,11 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
if (((Aggref *) node)->agglevelsup > 0)
return node;
}
+ else if (IsA(node, GroupingFunc))
+ {
+ if (((GroupingFunc *) node)->agglevelsup > 0)
+ return node;
+ }
/*
* We should never see a SubPlan expression in the input (since this is
@@ -1832,7 +1840,7 @@ SS_identify_outer_params(PlannerInfo *root)
outer_params = NULL;
for (proot = root->parent_root; proot != NULL; proot = proot->parent_root)
{
- /* Include ordinary Var/PHV/Aggref params */
+ /* Include ordinary Var/PHV/Aggref/GroupingFunc params */
foreach(l, proot->plan_params)
{
PlannerParamItem *pitem = (PlannerParamItem *) lfirst(l);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 4897f271a4b..cc59815615b 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -7280,12 +7280,13 @@ get_parameter(Param *param, deparse_context *context)
context->varprefix = true;
/*
- * A Param's expansion is typically a Var, Aggref, or upper-level
- * Param, which wouldn't need extra parentheses. Otherwise, insert
- * parens to ensure the expression looks atomic.
+ * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
+ * upper-level Param, which wouldn't need extra parentheses.
+ * Otherwise, insert parens to ensure the expression looks atomic.
*/
need_paren = !(IsA(expr, Var) ||
IsA(expr, Aggref) ||
+ IsA(expr, GroupingFunc) ||
IsA(expr, Param));
if (need_paren)
appendStringInfoChar(context->buf, '(');
@@ -7367,6 +7368,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_NextValueExpr:
case T_NullIfExpr:
case T_Aggref:
+ case T_GroupingFunc:
case T_WindowFunc:
case T_FuncExpr:
/* function-like: name(..) or name[..] */
@@ -7483,6 +7485,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_XmlExpr: /* own parentheses */
case T_NullIfExpr: /* other separators */
case T_Aggref: /* own parentheses */
+ case T_GroupingFunc: /* own parentheses */
case T_WindowFunc: /* own parentheses */
case T_CaseExpr: /* other separators */
return true;
@@ -7533,6 +7536,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_XmlExpr: /* own parentheses */
case T_NullIfExpr: /* other separators */
case T_Aggref: /* own parentheses */
+ case T_GroupingFunc: /* own parentheses */
case T_WindowFunc: /* own parentheses */
case T_CaseExpr: /* other separators */
return true;
diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out
index f972dd81bed..077506f58f5 100644
--- a/src/test/regress/expected/groupingsets.out
+++ b/src/test/regress/expected/groupingsets.out
@@ -1610,4 +1610,53 @@ select v||'a', case when grouping(v||'a') = 1 then 1 else 0 end, count(*)
| 1 | 2
(4 rows)
+-- test handling of outer GroupingFunc within subqueries
+explain (costs off)
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by cube(v1);
+ QUERY PLAN
+---------------------------
+ GroupAggregate
+ Group Key: $2
+ Group Key: ()
+ InitPlan 1 (returns $1)
+ -> Result
+ InitPlan 3 (returns $2)
+ -> Result
+ InitPlan 4 (returns $3)
+ -> Result
+ -> Result
+ SubPlan 2
+ -> Result
+(12 rows)
+
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by cube(v1);
+ grouping
+----------
+ 0
+ 1
+(2 rows)
+
+explain (costs off)
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by v1;
+ QUERY PLAN
+---------------------------
+ GroupAggregate
+ Group Key: $2
+ InitPlan 1 (returns $1)
+ -> Result
+ InitPlan 3 (returns $2)
+ -> Result
+ InitPlan 4 (returns $3)
+ -> Result
+ -> Result
+ SubPlan 2
+ -> Result
+(11 rows)
+
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by v1;
+ grouping
+----------
+ 0
+(1 row)
+
-- end
diff --git a/src/test/regress/sql/groupingsets.sql b/src/test/regress/sql/groupingsets.sql
index 16925b79149..e56ac55acc5 100644
--- a/src/test/regress/sql/groupingsets.sql
+++ b/src/test/regress/sql/groupingsets.sql
@@ -445,4 +445,13 @@ select v||'a', case when grouping(v||'a') = 1 then 1 else 0 end, count(*)
from unnest(array[1,1], array['a','b']) u(i,v)
group by rollup(i, v||'a') order by 1,3;
+-- test handling of outer GroupingFunc within subqueries
+explain (costs off)
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by cube(v1);
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by cube(v1);
+
+explain (costs off)
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by v1;
+select (select grouping(v1)) from (values ((select 1))) v(v1) group by v1;
+
-- end