diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 595ff1d46b..6839e5d99b 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.148 2009/04/05 19:59:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.149 2009/04/25 16:44:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -437,13 +437,24 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, if (pitem->abslevel == root->query_level) { - splan->parParam = lappend_int(splan->parParam, paramid); + Node *arg; + /* * The Var or Aggref has already been adjusted to have the correct * varlevelsup or agglevelsup. We probably don't even need to * copy it again, but be safe. */ - splan->args = lappend(splan->args, copyObject(pitem->item)); + arg = copyObject(pitem->item); + + /* + * If it's an Aggref, its arguments might contain SubLinks, + * which have not yet been processed. Do that now. + */ + if (IsA(arg, Aggref)) + arg = SS_process_sublinks(root, arg, false); + + splan->parParam = lappend_int(splan->parParam, paramid); + splan->args = lappend(splan->args, arg); } } bms_free(tmpset); @@ -1531,6 +1542,12 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect, * so after expanding its sublinks to subplans. And we don't want any steps * in between, else those steps would never get applied to the aggregate * argument expressions, either in the parent or the child level. + * + * Another fairly tricky thing going on here is the handling of SubLinks in + * the arguments of uplevel aggregates. Those are not touched inside the + * intermediate query level, either. Instead, SS_process_sublinks recurses + * on them after copying the Aggref expression into the parent plan level + * (this is actually taken care of in build_subplan). */ Node * SS_replace_correlation_vars(PlannerInfo *root, Node *expr) @@ -1607,6 +1624,18 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context) context->isTopQual); } + /* + * Don't recurse into the arguments of an outer 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 + * Aggref into the arguments to be passed down to the current subplan. + */ + if (IsA(node, Aggref)) + { + if (((Aggref *) node)->agglevelsup > 0) + return node; + } + /* * We should never see a SubPlan expression in the input (since this is * the very routine that creates 'em to begin with). We shouldn't find diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 46f6f18ed0..a48b45007f 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -295,6 +295,16 @@ having exists (select 1 from onek b ERROR: aggregates not allowed in WHERE clause LINE 4: where sum(distinct a.four + b.four) = b.four)... ^ +-- Test handling of sublinks within outer-level aggregates. +-- Per bug report from Daniel Grace. +select + (select max((select i.unique2 from tenk1 i where i.unique1 = o.unique1))) +from tenk1 o; + ?column? +---------- + 9999 +(1 row) + -- -- test for bitwise integer aggregates -- diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index afa997e7ea..39b0187a1e 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -80,6 +80,12 @@ group by ten having exists (select 1 from onek b where sum(distinct a.four + b.four) = b.four); +-- Test handling of sublinks within outer-level aggregates. +-- Per bug report from Daniel Grace. +select + (select max((select i.unique2 from tenk1 i where i.unique1 = o.unique1))) +from tenk1 o; + -- -- test for bitwise integer aggregates --