]> granicus.if.org Git - postgresql/blob - src/backend/parser/parse_agg.c
Implement feature of new FE/BE protocol whereby RowDescription identifies
[postgresql] / src / backend / parser / parse_agg.c
1 /*-------------------------------------------------------------------------
2  *
3  * parse_agg.c
4  *        handle aggregates in parser
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.52 2003/04/03 18:04:09 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "optimizer/clauses.h"
18 #include "optimizer/tlist.h"
19 #include "optimizer/var.h"
20 #include "parser/parse_agg.h"
21 #include "parser/parsetree.h"
22
23
24 typedef struct
25 {
26         ParseState *pstate;
27         List       *groupClauses;
28         bool            have_non_var_grouping;
29         int                     sublevels_up;
30 } check_ungrouped_columns_context;
31
32 static void check_ungrouped_columns(Node *node, ParseState *pstate,
33                                                 List *groupClauses, bool have_non_var_grouping);
34 static bool check_ungrouped_columns_walker(Node *node,
35                                                            check_ungrouped_columns_context *context);
36
37 /*
38  * check_ungrouped_columns -
39  *        Scan the given expression tree for ungrouped variables (variables
40  *        that are not listed in the groupClauses list and are not within
41  *        the arguments of aggregate functions).  Emit a suitable error message
42  *        if any are found.
43  *
44  * NOTE: we assume that the given clause has been transformed suitably for
45  * parser output.  This means we can use expression_tree_walker.
46  *
47  * NOTE: we recognize grouping expressions in the main query, but only
48  * grouping Vars in subqueries.  For example, this will be rejected,
49  * although it could be allowed:
50  *              SELECT
51  *                      (SELECT x FROM bar where y = (foo.a + foo.b))
52  *              FROM foo
53  *              GROUP BY a + b;
54  * The difficulty is the need to account for different sublevels_up.
55  * This appears to require a whole custom version of equal(), which is
56  * way more pain than the feature seems worth.
57  */
58 static void
59 check_ungrouped_columns(Node *node, ParseState *pstate,
60                                                 List *groupClauses, bool have_non_var_grouping)
61 {
62         check_ungrouped_columns_context context;
63
64         context.pstate = pstate;
65         context.groupClauses = groupClauses;
66         context.have_non_var_grouping = have_non_var_grouping;
67         context.sublevels_up = 0;
68         check_ungrouped_columns_walker(node, &context);
69 }
70
71 static bool
72 check_ungrouped_columns_walker(Node *node,
73                                                            check_ungrouped_columns_context *context)
74 {
75         List       *gl;
76
77         if (node == NULL)
78                 return false;
79         if (IsA(node, Const) ||
80                 IsA(node, Param))
81                 return false;                   /* constants are always acceptable */
82
83         /*
84          * If we find an aggregate function, do not recurse into its
85          * arguments; ungrouped vars in the arguments are not an error.
86          */
87         if (IsA(node, Aggref))
88                 return false;
89
90         /*
91          * If we have any GROUP BY items that are not simple Vars,
92          * check to see if subexpression as a whole matches any GROUP BY item.
93          * We need to do this at every recursion level so that we recognize
94          * GROUPed-BY expressions before reaching variables within them.
95          * But this only works at the outer query level, as noted above.
96          */
97         if (context->have_non_var_grouping && context->sublevels_up == 0)
98         {
99                 foreach(gl, context->groupClauses)
100                 {
101                         if (equal(node, lfirst(gl)))
102                                 return false;   /* acceptable, do not descend more */
103                 }
104         }
105
106         /*
107          * If we have an ungrouped Var of the original query level, we have a
108          * failure.  Vars below the original query level are not a problem,
109          * and neither are Vars from above it.  (If such Vars are ungrouped as
110          * far as their own query level is concerned, that's someone else's
111          * problem...)
112          */
113         if (IsA(node, Var))
114         {
115                 Var                *var = (Var *) node;
116                 RangeTblEntry *rte;
117                 char       *attname;
118
119                 if (var->varlevelsup != context->sublevels_up)
120                         return false;           /* it's not local to my query, ignore */
121                 /*
122                  * Check for a match, if we didn't do it above.
123                  */
124                 if (!context->have_non_var_grouping || context->sublevels_up != 0)
125                 {
126                         foreach(gl, context->groupClauses)
127                         {
128                                 Var        *gvar = (Var *) lfirst(gl);
129
130                                 if (IsA(gvar, Var) &&
131                                         gvar->varno == var->varno &&
132                                         gvar->varattno == var->varattno &&
133                                         gvar->varlevelsup == 0)
134                                         return false; /* acceptable, we're okay */
135                         }
136                 }
137
138                 /* Found an ungrouped local variable; generate error message */
139                 Assert(var->varno > 0 &&
140                            (int) var->varno <= length(context->pstate->p_rtable));
141                 rte = rt_fetch(var->varno, context->pstate->p_rtable);
142                 attname = get_rte_attribute_name(rte, var->varattno);
143                 if (context->sublevels_up == 0)
144                         elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
145                                  rte->eref->aliasname, attname);
146                 else
147                         elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
148                                  rte->eref->aliasname, attname);
149
150         }
151
152         if (IsA(node, Query))
153         {
154                 /* Recurse into subselects */
155                 bool            result;
156
157                 context->sublevels_up++;
158                 result = query_tree_walker((Query *) node,
159                                                                    check_ungrouped_columns_walker,
160                                                                    (void *) context,
161                                                                    0);
162                 context->sublevels_up--;
163                 return result;
164         }
165         return expression_tree_walker(node, check_ungrouped_columns_walker,
166                                                                   (void *) context);
167 }
168
169 /*
170  * parseCheckAggregates
171  *      Check for aggregates where they shouldn't be and improper grouping.
172  *
173  *      Ideally this should be done earlier, but it's difficult to distinguish
174  *      aggregates from plain functions at the grammar level.  So instead we
175  *      check here.  This function should be called after the target list and
176  *      qualifications are finalized.
177  */
178 void
179 parseCheckAggregates(ParseState *pstate, Query *qry)
180 {
181         List       *groupClauses = NIL;
182         bool            have_non_var_grouping = false;
183         List       *lst;
184         bool            hasJoinRTEs;
185         Node       *clause;
186
187         /* This should only be called if we found aggregates, GROUP, or HAVING */
188         Assert(pstate->p_hasAggs || qry->groupClause || qry->havingQual);
189
190         /*
191          * Aggregates must never appear in WHERE or JOIN/ON clauses.
192          *
193          * (Note this check should appear first to deliver an appropriate error
194          * message; otherwise we are likely to complain about some innocent
195          * variable in the target list, which is outright misleading if the
196          * problem is in WHERE.)
197          */
198         if (contain_agg_clause(qry->jointree->quals))
199                 elog(ERROR, "Aggregates not allowed in WHERE clause");
200         if (contain_agg_clause((Node *) qry->jointree->fromlist))
201                 elog(ERROR, "Aggregates not allowed in JOIN conditions");
202
203         /*
204          * No aggregates allowed in GROUP BY clauses, either.
205          *
206          * While we are at it, build a list of the acceptable GROUP BY
207          * expressions for use by check_ungrouped_columns() (this avoids
208          * repeated scans of the targetlist within the recursive routine...).
209          * And detect whether any of the expressions aren't simple Vars.
210          */
211         foreach(lst, qry->groupClause)
212         {
213                 GroupClause *grpcl = (GroupClause *) lfirst(lst);
214                 Node       *expr;
215
216                 expr = get_sortgroupclause_expr(grpcl, qry->targetList);
217                 if (expr == NULL)
218                         continue;                       /* probably cannot happen */
219                 if (contain_agg_clause(expr))
220                         elog(ERROR, "Aggregates not allowed in GROUP BY clause");
221                 groupClauses = lcons(expr, groupClauses);
222                 if (!IsA(expr, Var))
223                         have_non_var_grouping = true;
224         }
225
226         /*
227          * If there are join alias vars involved, we have to flatten them
228          * to the underlying vars, so that aliased and unaliased vars will be
229          * correctly taken as equal.  We can skip the expense of doing this
230          * if no rangetable entries are RTE_JOIN kind.
231          */
232         hasJoinRTEs = false;
233         foreach(lst, pstate->p_rtable)
234         {
235                 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lst);
236
237                 if (rte->rtekind == RTE_JOIN)
238                 {
239                         hasJoinRTEs = true;
240                         break;
241                 }
242         }
243
244         if (hasJoinRTEs)
245                 groupClauses = (List *) flatten_join_alias_vars(qry,
246                                                                                                                 (Node *) groupClauses);
247
248         /*
249          * Check the targetlist and HAVING clause for ungrouped variables.
250          */
251         clause = (Node *) qry->targetList;
252         if (hasJoinRTEs)
253                 clause = flatten_join_alias_vars(qry, clause);
254         check_ungrouped_columns(clause, pstate,
255                                                         groupClauses, have_non_var_grouping);
256
257         clause = (Node *) qry->havingQual;
258         if (hasJoinRTEs)
259                 clause = flatten_join_alias_vars(qry, clause);
260         check_ungrouped_columns(clause, pstate,
261                                                         groupClauses, have_non_var_grouping);
262 }