1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-06 07:49:08 +03:00

Replace generic 'Illegal use of aggregates' error message with one that

shows the specific ungrouped variable being complained of.  Perhaps this
will reduce user confusion...
This commit is contained in:
Tom Lane
1999-12-09 05:58:56 +00:00
parent d65a27f950
commit f7f41c7c8c
6 changed files with 122 additions and 78 deletions

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.55 1999/11/22 17:56:17 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.56 1999/12/09 05:58:53 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -30,6 +30,7 @@
#include "optimizer/tlist.h"
#include "optimizer/var.h"
#include "parser/parse_type.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -40,7 +41,7 @@
(isnull), true, false, false))
typedef struct {
List *groupClause;
Query *query;
List *targetList;
} check_subplans_for_ungrouped_vars_context;
@@ -427,28 +428,30 @@ pull_agg_clause_walker(Node *node, List **listptr)
/*
* check_subplans_for_ungrouped_vars
* Check for subplans that are being passed ungrouped variables as
* parameters; return TRUE if any are found.
* parameters; generate an error message if any are found.
*
* In most contexts, ungrouped variables will be detected by the parser (see
* parse_agg.c, exprIsAggOrGroupCol()). But that routine currently does not
* check subplans, because the necessary info is not computed until the
* 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 the subplan.
* This ought to be cleaned up someday.
*
* 'clause' is the expression tree to be searched for subplans.
* 'groupClause' is the GROUP BY list (a list of GroupClause nodes).
* 'query' provides the GROUP BY list and range table.
* 'targetList' is the target list that the group clauses refer to.
* (Is it really necessary to pass the tlist separately? Couldn't we
* just use the tlist found in the query node?)
*/
bool
void
check_subplans_for_ungrouped_vars(Node *clause,
List *groupClause,
Query *query,
List *targetList)
{
check_subplans_for_ungrouped_vars_context context;
context.groupClause = groupClause;
context.query = query;
context.targetList = targetList;
return check_subplans_for_ungrouped_vars_walker(clause, &context);
check_subplans_for_ungrouped_vars_walker(clause, &context);
}
static bool
@@ -472,10 +475,27 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
foreach(t, ((Expr *) node)->args)
{
Node *thisarg = lfirst(t);
bool contained_in_group_clause = false;
Var *var;
bool contained_in_group_clause;
List *gl;
foreach(gl, context->groupClause)
/*
* 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->query->groupClause)
{
GroupClause *gcl = lfirst(gl);
Node *groupexpr;
@@ -490,7 +510,21 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
}
if (!contained_in_group_clause)
return true; /* found an ungrouped argument */
{
/* Found an ungrouped argument. Complain. */
RangeTblEntry *rte;
char *attname;
Assert(var->varno > 0 &&
var->varno <= length(context->query->rtable));
rte = rt_fetch(var->varno, context->query->rtable);
attname = get_attname(rte->relid, var->varattno);
if (! attname)
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
var->varattno, rte->relid);
elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
rte->refname, attname);
}
}
}
return expression_tree_walker(node,