diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 4cf6a09acfecbcc1b117195d871ba66aaffaf187..cd5d266e07adb9466f543700556047b00312d2e2 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.139 2003/01/15 19:35:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.140 2003/01/17 03:25:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -208,17 +208,6 @@ subquery_planner(Query *parse, double tuple_fraction)
 		/* These are not targetlist items, but close enough... */
 	}
 
-	/*
-	 * Check for ungrouped variables passed to subplans in targetlist and
-	 * HAVING clause (but not in WHERE or JOIN/ON clauses, since those are
-	 * evaluated before grouping).	We can't do this any earlier because
-	 * we must use the preprocessed targetlist for comparisons of grouped
-	 * expressions.
-	 */
-	if (parse->hasSubLinks &&
-		(parse->groupClause != NIL || parse->hasAggs))
-		check_subplans_for_ungrouped_vars(parse);
-
 	/*
 	 * A HAVING clause without aggregates is equivalent to a WHERE clause
 	 * (except it can only refer to grouped fields).  Transfer any
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index d9bdfec54e2cb69852c5bdd1a911a1a4263a9ac4..acd17ba87d29817de0d78bbbdb37694a6ff0e679 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.123 2003/01/17 02:01:16 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.124 2003/01/17 03:25:03 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -20,7 +20,6 @@
 #include "postgres.h"
 
 #include "catalog/pg_language.h"
-#include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "executor/executor.h"
@@ -28,10 +27,8 @@
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
-#include "optimizer/tlist.h"
 #include "optimizer/var.h"
 #include "parser/analyze.h"
-#include "parser/parsetree.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -45,12 +42,6 @@
 #define MAKEBOOLCONST(val,isnull) \
 	((Node *) makeConst(BOOLOID, 1, (Datum) (val), (isnull), true))
 
-typedef struct
-{
-	Query	   *query;
-	List	   *groupClauses;
-} check_subplans_for_ungrouped_vars_context;
-
 typedef struct
 {
 	int			nargs;
@@ -64,8 +55,6 @@ static bool pull_agg_clause_walker(Node *node, List **listptr);
 static bool expression_returns_set_walker(Node *node, void *context);
 static bool contain_subplans_walker(Node *node, void *context);
 static bool pull_subplans_walker(Node *node, List **listptr);
-static bool check_subplans_for_ungrouped_vars_walker(Node *node,
-					 check_subplans_for_ungrouped_vars_context *context);
 static bool contain_mutable_functions_walker(Node *node, void *context);
 static bool contain_volatile_functions_walker(Node *node, void *context);
 static bool contain_nonstrict_functions_walker(Node *node, void *context);
@@ -552,157 +541,6 @@ pull_subplans_walker(Node *node, List **listptr)
 								  (void *) listptr);
 }
 
-/*
- * check_subplans_for_ungrouped_vars
- *		Check for subplans that are being passed ungrouped variables as
- *		parameters; generate an error message if any are found.
- *
- * In most contexts, ungrouped variables will be detected by the parser (see
- * parse_agg.c, check_ungrouped_columns()). But that routine currently does
- * not check subplans, because the necessary info is not computed until the
- * planner runs.  So we do it here, after we have processed sublinks into
- * subplans.  This ought to be cleaned up someday.
- *
- * A deficiency in this scheme is that any outer reference var must be
- * grouped by itself; we don't recognize groupable expressions within
- * subselects.	For example, consider
- *		SELECT
- *			(SELECT x FROM bar where y = (foo.a + foo.b))
- *		FROM foo
- *		GROUP BY a + b;
- * This query will be rejected although it could be allowed.
- */
-void
-check_subplans_for_ungrouped_vars(Query *query)
-{
-	check_subplans_for_ungrouped_vars_context context;
-	List	   *gl;
-
-	context.query = query;
-
-	/*
-	 * Build a list of the acceptable GROUP BY expressions for use in the
-	 * walker (to avoid repeated scans of the targetlist within the
-	 * recursive routine).
-	 */
-	context.groupClauses = NIL;
-	foreach(gl, query->groupClause)
-	{
-		GroupClause *grpcl = lfirst(gl);
-		Node	   *expr;
-
-		expr = get_sortgroupclause_expr(grpcl, query->targetList);
-		context.groupClauses = lcons(expr, context.groupClauses);
-	}
-
-	/*
-	 * Recursively scan the targetlist and the HAVING clause. WHERE and
-	 * JOIN/ON conditions are not examined, since they are evaluated
-	 * before grouping.
-	 */
-	check_subplans_for_ungrouped_vars_walker((Node *) query->targetList,
-											 &context);
-	check_subplans_for_ungrouped_vars_walker(query->havingQual,
-											 &context);
-
-	freeList(context.groupClauses);
-}
-
-static bool
-check_subplans_for_ungrouped_vars_walker(Node *node,
-					  check_subplans_for_ungrouped_vars_context *context)
-{
-	List	   *gl;
-
-	if (node == NULL)
-		return false;
-	if (IsA(node, Const) ||
-		IsA(node, Param))
-		return false;			/* constants are always acceptable */
-
-	/*
-	 * If we find an aggregate function, do not recurse into its
-	 * arguments.  Subplans invoked within aggregate calls are allowed to
-	 * receive ungrouped variables.  (This test and the next one should
-	 * match the logic in parse_agg.c's check_ungrouped_columns().)
-	 */
-	if (IsA(node, Aggref))
-		return false;
-
-	/*
-	 * Check to see if subexpression as a whole matches any GROUP BY item.
-	 * We need to do this at every recursion level so that we recognize
-	 * GROUPed-BY expressions before reaching variables within them.
-	 */
-	foreach(gl, context->groupClauses)
-	{
-		if (equal(node, lfirst(gl)))
-			return false;		/* acceptable, do not descend more */
-	}
-
-	/*
-	 * We can ignore Vars other than in subplan args lists, since the
-	 * parser already checked 'em.
-	 */
-	if (is_subplan(node))
-	{
-		/*
-		 * The args list of the subplan node represents attributes from
-		 * outside passed into the sublink.
-		 */
-		List	   *t;
-
-		foreach(t, ((SubPlan *) node)->args)
-		{
-			Node	   *thisarg = lfirst(t);
-			Var		   *var;
-			bool		contained_in_group_clause;
-
-			/*
-			 * We do not care about args that are not local variables;
-			 * params or outer-level vars are not our responsibility to
-			 * check.  (The outer-level query passing them to us needs to
-			 * worry, instead.)
-			 */
-			if (!IsA(thisarg, Var))
-				continue;
-			var = (Var *) thisarg;
-			if (var->varlevelsup > 0)
-				continue;
-
-			/*
-			 * Else, see if it is a grouping column.
-			 */
-			contained_in_group_clause = false;
-			foreach(gl, context->groupClauses)
-			{
-				if (equal(thisarg, lfirst(gl)))
-				{
-					contained_in_group_clause = true;
-					break;
-				}
-			}
-
-			if (!contained_in_group_clause)
-			{
-				/* Found an ungrouped argument.  Complain. */
-				RangeTblEntry *rte;
-				char	   *attname;
-
-				Assert(var->varno > 0 &&
-					 (int) var->varno <= length(context->query->rtable));
-				rte = rt_fetch(var->varno, context->query->rtable);
-				attname = get_rte_attribute_name(rte, var->varattno);
-				elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
-					 rte->eref->aliasname, attname);
-			}
-		}
-	}
-	return expression_tree_walker(node,
-								check_subplans_for_ungrouped_vars_walker,
-								  (void *) context);
-}
-
 
 /*****************************************************************************
  *		Check clauses for mutable functions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 2609de18f54656f16a85c3175570fe01fc5c27bc..175059b96cff6f4d73f77ba73779a3e000d14c98 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.259 2003/01/02 19:29:22 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.260 2003/01/17 03:25:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -354,7 +354,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
 	qry->hasSubLinks = pstate->p_hasSubLinks;
 	qry->hasAggs = pstate->p_hasAggs;
 	if (pstate->p_hasAggs)
-		parseCheckAggregates(pstate, qry, qual);
+		parseCheckAggregates(pstate, qry);
 
 	return qry;
 }
@@ -575,7 +575,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
 	qry->hasSubLinks = pstate->p_hasSubLinks;
 	qry->hasAggs = pstate->p_hasAggs;
 	if (pstate->p_hasAggs)
-		parseCheckAggregates(pstate, qry, NULL);
+		parseCheckAggregates(pstate, qry);
 
 	return qry;
 }
@@ -1671,13 +1671,13 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 	qry->limitOffset = stmt->limitOffset;
 	qry->limitCount = stmt->limitCount;
 
+	qry->rtable = pstate->p_rtable;
+	qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
+
 	qry->hasSubLinks = pstate->p_hasSubLinks;
 	qry->hasAggs = pstate->p_hasAggs;
 	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
-		parseCheckAggregates(pstate, qry, qual);
-
-	qry->rtable = pstate->p_rtable;
-	qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
+		parseCheckAggregates(pstate, qry);
 
 	if (stmt->forUpdate != NIL)
 		transformForUpdate(qry, stmt->forUpdate);
@@ -1900,13 +1900,13 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 	qry->limitOffset = limitOffset;
 	qry->limitCount = limitCount;
 
+	qry->rtable = pstate->p_rtable;
+	qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
+
 	qry->hasSubLinks = pstate->p_hasSubLinks;
 	qry->hasAggs = pstate->p_hasAggs;
 	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
-		parseCheckAggregates(pstate, qry, NULL);
-
-	qry->rtable = pstate->p_rtable;
-	qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
+		parseCheckAggregates(pstate, qry);
 
 	if (forUpdate != NIL)
 		transformForUpdate(qry, forUpdate);
@@ -2146,7 +2146,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 	qry->hasSubLinks = pstate->p_hasSubLinks;
 	qry->hasAggs = pstate->p_hasAggs;
 	if (pstate->p_hasAggs)
-		parseCheckAggregates(pstate, qry, qual);
+		parseCheckAggregates(pstate, qry);
 
 	/*
 	 * Now we are done with SELECT-like processing, and can get on with
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 127abdc2de8567fa2aeeb93a2d29eab385f52acf..f980d52f2b0e72e2fbee05a4f094227dcc2aa367 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.50 2002/06/20 20:29:32 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.51 2003/01/17 03:25:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,10 +24,12 @@ typedef struct
 {
 	ParseState *pstate;
 	List	   *groupClauses;
+	bool		have_non_var_grouping;
+	int			sublevels_up;
 } check_ungrouped_columns_context;
 
 static void check_ungrouped_columns(Node *node, ParseState *pstate,
-						List *groupClauses);
+						List *groupClauses, bool have_non_var_grouping);
 static bool check_ungrouped_columns_walker(Node *node,
 							   check_ungrouped_columns_context *context);
 
@@ -39,24 +41,29 @@ static bool check_ungrouped_columns_walker(Node *node,
  *	  if any are found.
  *
  * NOTE: we assume that the given clause has been transformed suitably for
- * parser output.  This means we can use the planner's expression_tree_walker.
+ * parser output.  This means we can use expression_tree_walker.
  *
- * NOTE: in the case of a SubLink, expression_tree_walker does not descend
- * into the subquery.  This means we will fail to detect ungrouped columns
- * that appear as outer-level variables within a subquery.	That case seems
- * unreasonably hard to handle here.  Instead, we expect the planner to check
- * for ungrouped columns after it's found all the outer-level references
- * inside the subquery and converted them into a list of parameters for the
- * subquery.
+ * NOTE: we recognize grouping expressions in the main query, but only
+ * grouping Vars in subqueries.  For example, this will be rejected,
+ * although it could be allowed:
+ *		SELECT
+ *			(SELECT x FROM bar where y = (foo.a + foo.b))
+ *		FROM foo
+ *		GROUP BY a + b;
+ * The difficulty is the need to account for different sublevels_up.
+ * This appears to require a whole custom version of equal(), which is
+ * way more pain than the feature seems worth.
  */
 static void
 check_ungrouped_columns(Node *node, ParseState *pstate,
-						List *groupClauses)
+						List *groupClauses, bool have_non_var_grouping)
 {
 	check_ungrouped_columns_context context;
 
 	context.pstate = pstate;
 	context.groupClauses = groupClauses;
+	context.have_non_var_grouping = have_non_var_grouping;
+	context.sublevels_up = 0;
 	check_ungrouped_columns_walker(node, &context);
 }
 
@@ -68,32 +75,38 @@ check_ungrouped_columns_walker(Node *node,
 
 	if (node == NULL)
 		return false;
-	if (IsA(node, Const) ||IsA(node, Param))
+	if (IsA(node, Const) ||
+		IsA(node, Param))
 		return false;			/* constants are always acceptable */
 
 	/*
 	 * If we find an aggregate function, do not recurse into its
-	 * arguments.
+	 * arguments; ungrouped vars in the arguments are not an error.
 	 */
 	if (IsA(node, Aggref))
 		return false;
 
 	/*
-	 * Check to see if subexpression as a whole matches any GROUP BY item.
+	 * If we have any GROUP BY items that are not simple Vars,
+	 * check to see if subexpression as a whole matches any GROUP BY item.
 	 * We need to do this at every recursion level so that we recognize
 	 * GROUPed-BY expressions before reaching variables within them.
+	 * But this only works at the outer query level, as noted above.
 	 */
-	foreach(gl, context->groupClauses)
+	if (context->have_non_var_grouping && context->sublevels_up == 0)
 	{
-		if (equal(node, lfirst(gl)))
-			return false;		/* acceptable, do not descend more */
+		foreach(gl, context->groupClauses)
+		{
+			if (equal(node, lfirst(gl)))
+				return false;	/* acceptable, do not descend more */
+		}
 	}
 
 	/*
-	 * If we have an ungrouped Var, we have a failure --- unless it is an
-	 * outer-level Var.  In that case it's a constant as far as this query
-	 * level is concerned, and we can accept it.  (If it's ungrouped as
-	 * far as the upper query is concerned, that's someone else's
+	 * If we have an ungrouped Var of the original query level, we have a
+	 * failure.  Vars below the original query level are not a problem,
+	 * and neither are Vars from above it.  (If such Vars are ungrouped as
+	 * far as their own query level is concerned, that's someone else's
 	 * problem...)
 	 */
 	if (IsA(node, Var))
@@ -102,17 +115,52 @@ check_ungrouped_columns_walker(Node *node,
 		RangeTblEntry *rte;
 		char	   *attname;
 
-		if (var->varlevelsup > 0)
-			return false;		/* outer-level Var is acceptable */
+		if (var->varlevelsup != context->sublevels_up)
+			return false;		/* it's not local to my query, ignore */
+		/*
+		 * Check for a match, if we didn't do it above.
+		 */
+		if (!context->have_non_var_grouping || context->sublevels_up != 0)
+		{
+			foreach(gl, context->groupClauses)
+			{
+				Var	   *gvar = (Var *) lfirst(gl);
+
+				if (IsA(gvar, Var) &&
+					gvar->varno == var->varno &&
+					gvar->varattno == var->varattno &&
+					gvar->varlevelsup == 0)
+					return false; /* acceptable, we're okay */
+			}
+		}
+
 		/* Found an ungrouped local variable; generate error message */
 		Assert(var->varno > 0 &&
 			   (int) var->varno <= length(context->pstate->p_rtable));
 		rte = rt_fetch(var->varno, context->pstate->p_rtable);
 		attname = get_rte_attribute_name(rte, var->varattno);
-		elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
-			 rte->eref->aliasname, attname);
+		if (context->sublevels_up == 0)
+			elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
+				 rte->eref->aliasname, attname);
+		else
+			elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
+				 rte->eref->aliasname, attname);
+
+	}
+
+	if (IsA(node, Query))
+	{
+		/* Recurse into subselects */
+		bool		result;
+
+		context->sublevels_up++;
+		result = query_tree_walker((Query *) node,
+								   check_ungrouped_columns_walker,
+								   (void *) context,
+								   0);
+		context->sublevels_up--;
+		return result;
 	}
-	/* Otherwise, recurse. */
 	return expression_tree_walker(node, check_ungrouped_columns_walker,
 								  (void *) context);
 }
@@ -124,15 +172,13 @@ check_ungrouped_columns_walker(Node *node,
  *	Ideally this should be done earlier, but it's difficult to distinguish
  *	aggregates from plain functions at the grammar level.  So instead we
  *	check here.  This function should be called after the target list and
- *	qualifications are finalized.  BUT: in some cases we want to call this
- *	routine before we've assembled the joinlist and qual into a FromExpr.
- *	So, rather than looking at qry->jointree, look at pstate->p_joinlist
- *	and the explicitly-passed qual.
+ *	qualifications are finalized.
  */
 void
-parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
+parseCheckAggregates(ParseState *pstate, Query *qry)
 {
 	List	   *groupClauses = NIL;
+	bool		have_non_var_grouping = false;
 	List	   *tl;
 
 	/* This should only be called if we found aggregates, GROUP, or HAVING */
@@ -146,9 +192,9 @@ parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
 	 * variable in the target list, which is outright misleading if the
 	 * problem is in WHERE.)
 	 */
-	if (contain_agg_clause(qual))
+	if (contain_agg_clause(qry->jointree->quals))
 		elog(ERROR, "Aggregates not allowed in WHERE clause");
-	if (contain_agg_clause((Node *) pstate->p_joinlist))
+	if (contain_agg_clause((Node *) qry->jointree->fromlist))
 		elog(ERROR, "Aggregates not allowed in JOIN conditions");
 
 	/*
@@ -156,7 +202,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
 	 *
 	 * While we are at it, build a list of the acceptable GROUP BY
 	 * expressions for use by check_ungrouped_columns() (this avoids
-	 * repeated scans of the targetlist within the recursive routine...)
+	 * repeated scans of the targetlist within the recursive routine...).
+	 * And detect whether any of the expressions aren't simple Vars.
 	 */
 	foreach(tl, qry->groupClause)
 	{
@@ -164,16 +211,22 @@ parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
 		Node	   *expr;
 
 		expr = get_sortgroupclause_expr(grpcl, qry->targetList);
+		if (expr == NULL)
+			continue;			/* probably cannot happen */
 		if (contain_agg_clause(expr))
 			elog(ERROR, "Aggregates not allowed in GROUP BY clause");
 		groupClauses = lcons(expr, groupClauses);
+		if (!IsA(expr, Var))
+			have_non_var_grouping = true;
 	}
 
 	/*
 	 * Check the targetlist and HAVING clause for ungrouped variables.
 	 */
-	check_ungrouped_columns((Node *) qry->targetList, pstate, groupClauses);
-	check_ungrouped_columns((Node *) qry->havingQual, pstate, groupClauses);
+	check_ungrouped_columns((Node *) qry->targetList, pstate,
+							groupClauses, have_non_var_grouping);
+	check_ungrouped_columns((Node *) qry->havingQual, pstate,
+							groupClauses, have_non_var_grouping);
 
 	/* Release the list storage (but not the pointed-to expressions!) */
 	freeList(groupClauses);
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 024c1599a4c77d08dd158138e851a5e4eec10f1c..7ee0f1be2e4b71bcfeb06e3482ea762bf65d55cb 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: clauses.h,v 1.60 2003/01/17 02:01:21 tgl Exp $
+ * $Id: clauses.h,v 1.61 2003/01/17 03:25:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,7 +52,6 @@ extern bool expression_returns_set(Node *clause);
 
 extern bool contain_subplans(Node *clause);
 extern List *pull_subplans(Node *clause);
-extern void check_subplans_for_ungrouped_vars(Query *query);
 
 extern bool contain_mutable_functions(Node *clause);
 extern bool contain_volatile_functions(Node *clause);
diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h
index e836310f82ec527e0ff60952aaa9691e66ff0ca0..111d726bc9c3b8e69ea98afb7ca99ae9d1a642f3 100644
--- a/src/include/parser/parse_agg.h
+++ b/src/include/parser/parse_agg.h
@@ -1,13 +1,12 @@
 /*-------------------------------------------------------------------------
  *
  * parse_agg.h
- *
- *
+ *	  handle aggregates in parser
  *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_agg.h,v 1.24 2002/06/20 20:29:51 momjian Exp $
+ * $Id: parse_agg.h,v 1.25 2003/01/17 03:25:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +15,6 @@
 
 #include "parser/parse_node.h"
 
-extern void parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual);
+extern void parseCheckAggregates(ParseState *pstate, Query *qry);
 
 #endif   /* PARSE_AGG_H */