summaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_agg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_agg.c')
-rw-r--r--src/backend/parser/parse_agg.c180
1 files changed, 0 insertions, 180 deletions
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
deleted file mode 100644
index 127abdc2de8..00000000000
--- a/src/backend/parser/parse_agg.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * parse_agg.c
- * handle aggregates in parser
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.50 2002/06/20 20:29:32 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "optimizer/clauses.h"
-#include "optimizer/tlist.h"
-#include "parser/parse_agg.h"
-#include "parser/parsetree.h"
-
-
-typedef struct
-{
- ParseState *pstate;
- List *groupClauses;
-} check_ungrouped_columns_context;
-
-static void check_ungrouped_columns(Node *node, ParseState *pstate,
- List *groupClauses);
-static bool check_ungrouped_columns_walker(Node *node,
- check_ungrouped_columns_context *context);
-
-/*
- * check_ungrouped_columns -
- * Scan the given expression tree for ungrouped variables (variables
- * that are not listed in the groupClauses list and are not within
- * the arguments of aggregate functions). Emit a suitable error message
- * 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.
- *
- * 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.
- */
-static void
-check_ungrouped_columns(Node *node, ParseState *pstate,
- List *groupClauses)
-{
- check_ungrouped_columns_context context;
-
- context.pstate = pstate;
- context.groupClauses = groupClauses;
- check_ungrouped_columns_walker(node, &context);
-}
-
-static bool
-check_ungrouped_columns_walker(Node *node,
- check_ungrouped_columns_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.
- */
- 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 */
- }
-
- /*
- * 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
- * problem...)
- */
- if (IsA(node, Var))
- {
- Var *var = (Var *) node;
- RangeTblEntry *rte;
- char *attname;
-
- if (var->varlevelsup > 0)
- return false; /* outer-level Var is acceptable */
- /* 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);
- }
- /* Otherwise, recurse. */
- return expression_tree_walker(node, check_ungrouped_columns_walker,
- (void *) context);
-}
-
-/*
- * parseCheckAggregates
- * Check for aggregates where they shouldn't be and improper grouping.
- *
- * 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.
- */
-void
-parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
-{
- List *groupClauses = NIL;
- List *tl;
-
- /* This should only be called if we found aggregates, GROUP, or HAVING */
- Assert(pstate->p_hasAggs || qry->groupClause || qry->havingQual);
-
- /*
- * Aggregates must never appear in WHERE or JOIN/ON clauses.
- *
- * (Note this check should appear first to deliver an appropriate error
- * message; otherwise we are likely to complain about some innocent
- * variable in the target list, which is outright misleading if the
- * problem is in WHERE.)
- */
- if (contain_agg_clause(qual))
- elog(ERROR, "Aggregates not allowed in WHERE clause");
- if (contain_agg_clause((Node *) pstate->p_joinlist))
- elog(ERROR, "Aggregates not allowed in JOIN conditions");
-
- /*
- * No aggregates allowed in GROUP BY clauses, either.
- *
- * 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...)
- */
- foreach(tl, qry->groupClause)
- {
- GroupClause *grpcl = lfirst(tl);
- Node *expr;
-
- expr = get_sortgroupclause_expr(grpcl, qry->targetList);
- if (contain_agg_clause(expr))
- elog(ERROR, "Aggregates not allowed in GROUP BY clause");
- groupClauses = lcons(expr, groupClauses);
- }
-
- /*
- * 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);
-
- /* Release the list storage (but not the pointed-to expressions!) */
- freeList(groupClauses);
-}