Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite786508

Browse files
committed
My first chosen victim for expression_tree_walker conversion
is parse_aggs.c. This fixes its failure to cope with (at least) CaseExprand ArrayRef nodes, which is the reason why both of these fail in 6.5:select coalesce(f1,0) from int4_tbl group by f1;ERROR: Illegal use of aggregates or non-group column in target listselect sentence.words[0] from sentence group by sentence.words[0];ERROR: Illegal use of aggregates or non-group column in target listThe array case still fails, but at least it's not parse_agg's faultanymore ... considering that we now support CASE officially, I thinkit's important to fix the first example ...
1 parent86f3671 commite786508

File tree

1 file changed

+103
-115
lines changed

1 file changed

+103
-115
lines changed

‎src/backend/parser/parse_agg.c

Lines changed: 103 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
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
*/
@@ -32,144 +32,111 @@
3232
#include"utils/lsyscache.h"
3333

3434
staticboolcontain_agg_clause(Node*clause);
35-
staticboolexprIsAggOrGroupCol(Node*expr,List*groupClause,List*tlist);
36-
staticbooltleIsAggOrGroupCol(TargetEntry*tle,List*groupClause,
37-
List*tlist);
35+
staticboolcontain_agg_clause_walker(Node*node,void*context);
36+
staticboolexprIsAggOrGroupCol(Node*expr,List*groupClauses);
37+
staticboolexprIsAggOrGroupCol_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
*/
4550
staticbool
4651
contain_agg_clause(Node*clause)
4752
{
48-
if (clause==NULL)
49-
return FALSE;
50-
elseif (IsA(clause,Aggref))
51-
return TRUE;
52-
elseif (IsA(clause,Iter))
53-
returncontain_agg_clause(((Iter*)clause)->iterexpr);
54-
elseif (single_node(clause))
55-
return FALSE;
56-
elseif (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-
elseif (is_funcclause(clause))
66-
{
67-
List*temp;
53+
returncontain_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-
elseif (IsA(clause,ArrayRef))
56+
staticbool
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+
returncontain_agg_clause_walker((Node*)sublink->lefthand,context);
8968
}
90-
elseif (not_clause(clause))
91-
returncontain_agg_clause((Node*)get_notclausearg((Expr*)clause));
92-
elseif (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+
returnexpression_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
*/
10389
staticbool
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-
*/
13899
staticbool
139-
tleIsAggOrGroupCol(TargetEntry*tle,List*groupClause,List*tlist)
100+
exprIsAggOrGroupCol_walker(Node*node,List*groupClauses)
140101
{
141-
Node*expr=tle->expr;
142102
List*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+
returnexprIsAggOrGroupCol_walker((Node*)sublink->lefthand,
136+
groupClauses);
137+
}
138+
returnexpression_tree_walker(node,exprIsAggOrGroupCol_walker,
139+
(void*)groupClauses);
173140
}
174141

175142
/*
@@ -184,6 +151,7 @@ tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause, List *tlist)
184151
void
185152
parseCheckAggregates(ParseState*pstate,Query*qry)
186153
{
154+
List*groupClauses=NIL;
187155
List*tl;
188156

189157
/* This should only be called if we found aggregates or grouping */
@@ -199,6 +167,24 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
199167
if (contain_agg_clause(qry->qual))
200168
elog(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
{
208194
TargetEntry*tle=lfirst(tl);
209195

210-
if (!tleIsAggOrGroupCol(tle,qry->groupClause,qry->targetList))
196+
if (!exprIsAggOrGroupCol(tle->expr,groupClauses))
211197
elog(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))
221206
elog(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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp