diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 34c75bc34a5..d5800c46387 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.112.2.4 2008/07/10 01:17:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.112.2.5 2009/04/25 16:45:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -449,13 +449,23 @@ make_subplan(SubLink *slink, Node *testexpr, 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; @@ -806,6 +816,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) @@ -872,6 +888,18 @@ process_sublinks_mutator(Node *node, bool *isTopQual) return make_subplan(sublink, testexpr, *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 74635479e48..06e40791fd1 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -293,6 +293,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 890aa8dea02..71adc93537e 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 --