77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.21 1999/05/25 16:10:13 momjian Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.22 1999/06/19 03:48:31 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
3232#include "utils/lsyscache.h"
3333
3434static bool contain_agg_clause (Node * clause );
35- static bool exprIsAggOrGroupCol (Node * expr , List * groupClause , List * tlist );
36- static bool tleIsAggOrGroupCol ( TargetEntry * tle ,List * groupClause ,
37- List * tlist );
35+ static bool contain_agg_clause_walker (Node * node , void * context );
36+ static bool exprIsAggOrGroupCol ( Node * expr ,List * groupClauses );
37+ static bool exprIsAggOrGroupCol_walker ( Node * node , List * groupClauses );
3838
3939/*
4040 * contain_agg_clause
41- * Recursively find aggref nodesfrom a clause.
41+ * Recursively find aggref nodeswithin a clause.
4242 *
4343 * Returns true if any aggregate found.
44+ *
45+ * NOTE: we assume that the given clause has been transformed suitably for
46+ * parser output. This means we can use the planner's expression_tree_walker,
47+ * except that we have to process SubLink nodes specially, since they haven't
48+ * been turned into SubPlan nodes yet.
4449 */
4550static bool
4651contain_agg_clause (Node * clause )
4752{
48- if (clause == NULL )
49- return FALSE;
50- else if (IsA (clause ,Aggref ))
51- return TRUE;
52- else if (IsA (clause ,Iter ))
53- return contain_agg_clause (((Iter * )clause )-> iterexpr );
54- else if (single_node (clause ))
55- return FALSE;
56- else if (or_clause (clause )|| and_clause (clause ))
57- {
58- List * temp ;
59-
60- foreach (temp , ((Expr * )clause )-> args )
61- if (contain_agg_clause (lfirst (temp )))
62- return TRUE;
63- return FALSE;
64- }
65- else if (is_funcclause (clause ))
66- {
67- List * temp ;
53+ return contain_agg_clause_walker (clause ,NULL );
54+ }
6855
69- foreach (temp , ((Expr * )clause )-> args )
70- if (contain_agg_clause (lfirst (temp )))
71- return TRUE;
72- return FALSE;
73- }
74- else if (IsA (clause ,ArrayRef ))
56+ static bool
57+ contain_agg_clause_walker (Node * node ,void * context )
58+ {
59+ if (node == NULL )
60+ return false;
61+ if (IsA (node ,Aggref ))
62+ return true;/* abort the tree traversal and return true */
63+ if (IsA (node ,SubLink ))
7564{
76- List * temp ;
77-
78- foreach (temp , ((ArrayRef * )clause )-> refupperindexpr )
79- if (contain_agg_clause (lfirst (temp )))
80- return TRUE;
81- foreach (temp , ((ArrayRef * )clause )-> reflowerindexpr )
82- if (contain_agg_clause (lfirst (temp )))
83- return TRUE;
84- if (contain_agg_clause (((ArrayRef * )clause )-> refexpr ))
85- return TRUE;
86- if (contain_agg_clause (((ArrayRef * )clause )-> refassgnexpr ))
87- return TRUE;
88- return FALSE;
65+ /* Examine the lefthand side, but not the oper list nor the subquery */
66+ SubLink * sublink = (SubLink * )node ;
67+ return contain_agg_clause_walker ((Node * )sublink -> lefthand ,context );
8968}
90- else if (not_clause (clause ))
91- return contain_agg_clause ((Node * )get_notclausearg ((Expr * )clause ));
92- else if (is_opclause (clause ))
93- return (contain_agg_clause ((Node * )get_leftop ((Expr * )clause ))||
94- contain_agg_clause ((Node * )get_rightop ((Expr * )clause )));
95-
96- return FALSE;
69+ return expression_tree_walker (node ,contain_agg_clause_walker ,context );
9770}
9871
9972/*
10073 * exprIsAggOrGroupCol -
101- * returns true if the expression does not contain non-group columns.
74+ * returns true if the expression does not contain non-group columns,
75+ * other than within the arguments of aggregate functions.
76+ *
77+ * NOTE: we assume that the given clause has been transformed suitably for
78+ * parser output. This means we can use the planner's expression_tree_walker,
79+ * except that we have to process SubLink nodes specially, since they haven't
80+ * been turned into SubPlan nodes yet.
81+ *
82+ * NOTE: in the case of a SubLink, we do not descend into the subquery. This
83+ * means we will fail to detect ungrouped columns that appear as outer-level
84+ * variables within a subquery. That seems unreasonably hard to handle here.
85+ * Instead, we expect the planner to check for ungrouped columns after it's
86+ * found all the outer-level references inside the subquery and converted
87+ * them into a list of parameters for the subquery.
10288 */
10389static bool
104- exprIsAggOrGroupCol (Node * expr ,List * groupClause , List * tlist )
90+ exprIsAggOrGroupCol (Node * expr ,List * groupClauses )
10591{
106- List * gl ;
107-
108- if (expr == NULL || IsA (expr ,Const )||
109- IsA (expr ,Param )|| IsA (expr ,Aggref )||
110- IsA (expr ,SubLink ))/* can't handle currently !!! */
111- return TRUE;
112-
113- foreach (gl ,groupClause )
114- {
115- GroupClause * grpcl = lfirst (gl );
116-
117- if (equal (expr ,get_groupclause_expr (grpcl ,tlist )))
118- return TRUE;
119- }
120-
121- if (IsA (expr ,Expr ))
122- {
123- List * temp ;
124-
125- foreach (temp , ((Expr * )expr )-> args )
126- if (!exprIsAggOrGroupCol (lfirst (temp ),groupClause ,tlist ))
127- return FALSE;
128- return TRUE;
129- }
130-
131- return FALSE;
92+ /* My walker returns TRUE if it finds a subexpression that is NOT
93+ * acceptable (since we can abort the recursion at that point).
94+ * So, invert its result.
95+ */
96+ return !exprIsAggOrGroupCol_walker (expr ,groupClauses );
13297}
13398
134- /*
135- * tleIsAggOrGroupCol -
136- * returns true if the TargetEntry is Agg or GroupCol.
137- */
13899static bool
139- tleIsAggOrGroupCol ( TargetEntry * tle ,List * groupClause , List * tlist )
100+ exprIsAggOrGroupCol_walker ( Node * node ,List * groupClauses )
140101{
141- Node * expr = tle -> expr ;
142102List * gl ;
143103
144- if (expr == NULL || IsA (expr ,Const )|| IsA (expr ,Param ))
145- return TRUE;
146-
147- foreach (gl ,groupClause )
104+ if (node == NULL )
105+ return false;
106+ if (IsA (node ,Aggref ))
107+ return false;/* OK; do not examine argument of aggregate */
108+ if (IsA (node ,Const )|| IsA (node ,Param ))
109+ return false;/* constants are always acceptable */
110+ /* Now check to see if expression as a whole matches any GROUP BY item.
111+ * We need to do this at every recursion level so that we recognize
112+ * GROUPed-BY expressions.
113+ */
114+ foreach (gl ,groupClauses )
148115{
149- GroupClause * grpcl = lfirst (gl );
150-
151- if (tle -> resdom -> resgroupref == grpcl -> tleGroupref )
152- {
153- if (contain_agg_clause ((Node * )expr ))
154- elog (ERROR ,"Aggregates not allowed in GROUP BY clause" );
155- return TRUE;
156- }
116+ if (equal (node ,lfirst (gl )))
117+ return false;/* acceptable, do not descend more */
157118}
158-
159- if (IsA (expr ,Aggref ))
160- return TRUE;
161-
162- if (IsA (expr ,Expr ))
119+ /* If we have an ungrouped Var, we have a failure --- unless it is an
120+ * outer-level Var. In that case it's a constant as far as this query
121+ * level is concerned, and we can accept it. (If it's ungrouped as far
122+ * as the upper query is concerned, that's someone else's problem...)
123+ */
124+ if (IsA (node ,Var ))
163125{
164- List * temp ;
165-
166- foreach (temp , ((Expr * )expr )-> args )
167- if (!exprIsAggOrGroupCol (lfirst (temp ),groupClause ,tlist ))
168- return FALSE;
169- return TRUE;
126+ if (((Var * )node )-> varlevelsup == 0 )
127+ return true;/* found an ungrouped local variable */
128+ return false;/* outer-level Var is acceptable */
170129}
171-
172- return FALSE;
130+ /* Otherwise, recurse. */
131+ if (IsA (node ,SubLink ))
132+ {
133+ /* Examine the lefthand side, but not the oper list nor the subquery */
134+ SubLink * sublink = (SubLink * )node ;
135+ return exprIsAggOrGroupCol_walker ((Node * )sublink -> lefthand ,
136+ groupClauses );
137+ }
138+ return expression_tree_walker (node ,exprIsAggOrGroupCol_walker ,
139+ (void * )groupClauses );
173140}
174141
175142/*
@@ -184,6 +151,7 @@ tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause, List *tlist)
184151void
185152parseCheckAggregates (ParseState * pstate ,Query * qry )
186153{
154+ List * groupClauses = NIL ;
187155List * tl ;
188156
189157/* This should only be called if we found aggregates or grouping */
@@ -199,6 +167,24 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
199167if (contain_agg_clause (qry -> qual ))
200168elog (ERROR ,"Aggregates not allowed in WHERE clause" );
201169
170+ /*
171+ * No aggregates allowed in GROUP BY clauses, either.
172+ *
173+ * While we are at it, build a list of the acceptable GROUP BY expressions
174+ * for use by exprIsAggOrGroupCol() (this avoids repeated scans of the
175+ * targetlist within the recursive routines...)
176+ */
177+ foreach (tl ,qry -> groupClause )
178+ {
179+ GroupClause * grpcl = lfirst (tl );
180+ Node * expr ;
181+
182+ expr = (Node * )get_groupclause_expr (grpcl ,qry -> targetList );
183+ if (contain_agg_clause (expr ))
184+ elog (ERROR ,"Aggregates not allowed in GROUP BY clause" );
185+ groupClauses = lcons (expr ,groupClauses );
186+ }
187+
202188/*
203189 * The target list can only contain aggregates, group columns and
204190 * functions thereof.
@@ -207,19 +193,21 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
207193{
208194TargetEntry * tle = lfirst (tl );
209195
210- if (!tleIsAggOrGroupCol (tle , qry -> groupClause , qry -> targetList ))
196+ if (!exprIsAggOrGroupCol (tle -> expr , groupClauses ))
211197elog (ERROR ,
212198"Illegal use of aggregates or non-group column in target list" );
213199}
214200
215201/*
216- *the expression specified in the HAVING clause has the same
202+ *The expression specified in the HAVING clause has the same
217203 * restriction as those in the target list.
218204 */
219-
220- if (!exprIsAggOrGroupCol (qry -> havingQual ,qry -> groupClause ,qry -> targetList ))
205+ if (!exprIsAggOrGroupCol (qry -> havingQual ,groupClauses ))
221206elog (ERROR ,
222- "Illegal use of aggregates or non-group column in HAVING clause" );
207+ "Illegal use of aggregates or non-group column in HAVING clause" );
208+
209+ /* Release the list storage (but not the pointed-to expressions!) */
210+ freeList (groupClauses );
223211}
224212
225213