diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index a77cade1176..70a582533a8 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.100.2.5 2008/07/10 01:17:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.100.2.6 2009/04/25 16:45:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -446,13 +446,23 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual) foreach(l, node->parParam) { PlannerParamItem *pitem = list_nth(PlannerParamList, lfirst_int(l)); + 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. */ - args = lappend(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(arg, false); + + args = lappend(args, arg); } node->args = args; @@ -748,6 +758,12 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink) * 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 make_subplan). */ Node * SS_replace_correlation_vars(Node *expr) @@ -815,6 +831,18 @@ process_sublinks_mutator(Node *node, bool *isTopQual) return make_subplan(sublink, lefthand, *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 make_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 8aed1864034..6313b94770a 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -157,6 +157,16 @@ group by ten having exists (select 1 from onek b where sum(distinct a.four + b.four) = b.four); ERROR: aggregates not allowed in WHERE clause +-- 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 b6aba0d66b7..a79c4367e45 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -63,6 +63,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 --