diff options
-rw-r--r-- | src/backend/nodes/nodeFuncs.c | 2 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 30 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 10 | ||||
-rw-r--r-- | src/test/regress/expected/groupingsets.out | 45 | ||||
-rw-r--r-- | src/test/regress/sql/groupingsets.sql | 9 |
6 files changed, 88 insertions, 14 deletions
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index ff3dcc7b18b..c172d4cca4a 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -736,6 +736,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 30c8595f761..006f91f0a87 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4492,6 +4492,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 5d0680821b5..cb3dde946f5 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -356,15 +356,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); @@ -1957,10 +1959,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)) { @@ -1972,6 +1975,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 @@ -2084,7 +2092,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 13d32cf6d98..a03fccf1ad8 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -7895,12 +7895,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, '('); @@ -8028,6 +8029,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[..] */ @@ -8144,6 +8146,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; @@ -8194,6 +8197,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 4c467c1b15e..29e6b52a459 100644 --- a/src/test/regress/expected/groupingsets.out +++ b/src/test/regress/expected/groupingsets.out @@ -2040,4 +2040,49 @@ order by a, b, c; | | (11 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 +--------------------------- + MixedAggregate + Hash Key: $2 + Group Key: () + InitPlan 1 (returns $1) + -> Result + InitPlan 3 (returns $2) + -> Result + -> Result + SubPlan 2 + -> Result +(10 rows) + +select (select grouping(v1)) from (values ((select 1))) v(v1) group by cube(v1); + grouping +---------- + 1 + 0 +(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 + -> Result + SubPlan 2 + -> Result +(9 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 39449447044..c0786bbed8b 100644 --- a/src/test/regress/sql/groupingsets.sql +++ b/src/test/regress/sql/groupingsets.sql @@ -555,4 +555,13 @@ from (values (1, 2, 3), (4, null, 6), (7, 8, 9)) as t (a, b, c) group by rollup(a, b), rollup(a, c) order by a, b, c; +-- 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 |