diff options
Diffstat (limited to 'src/backend/parser/parse_agg.c')
-rw-r--r-- | src/backend/parser/parse_agg.c | 94 |
1 files changed, 24 insertions, 70 deletions
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index a5007822976..5c87d5bc850 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.28 1999/08/21 03:48:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.29 1999/10/07 04:23:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -129,8 +129,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry) List *groupClauses = NIL; List *tl; - /* This should only be called if we found aggregates or grouping */ - Assert(pstate->p_hasAggs || qry->groupClause); + /* 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 clauses. (Note this check @@ -161,6 +161,15 @@ parseCheckAggregates(ParseState *pstate, Query *qry) } /* + * The expression specified in the HAVING clause can only contain + * aggregates, group columns and functions thereof. As with WHERE, + * we want to point the finger at HAVING before the target list. + */ + if (!exprIsAggOrGroupCol(qry->havingQual, groupClauses)) + elog(ERROR, + "Illegal use of aggregates or non-group column in HAVING clause"); + + /* * The target list can only contain aggregates, group columns and * functions thereof. */ @@ -173,14 +182,6 @@ parseCheckAggregates(ParseState *pstate, Query *qry) "Illegal use of aggregates or non-group column in target list"); } - /* - * The expression specified in the HAVING clause has the same - * restriction as those in the target list. - */ - if (!exprIsAggOrGroupCol(qry->havingQual, groupClauses)) - elog(ERROR, - "Illegal use of aggregates or non-group column in HAVING clause"); - /* Release the list storage (but not the pointed-to expressions!) */ freeList(groupClauses); } @@ -190,12 +191,12 @@ Aggref * ParseAgg(ParseState *pstate, char *aggname, Oid basetype, List *target, int precedence) { + HeapTuple theAggTuple; + Form_pg_aggregate aggform; Oid fintype; - Oid vartype; Oid xfn1; - Form_pg_aggregate aggform; + Oid vartype; Aggref *aggref; - HeapTuple theAggTuple; bool usenulls = false; theAggTuple = SearchSysCacheTuple(AGGNAME, @@ -206,66 +207,19 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, elog(ERROR, "Aggregate %s does not exist", aggname); /* - * We do a major hack for count(*) here. - * - * Count(*) poses several problems. First, we need a field that is - * guaranteed to be in the range table, and unique. Using a constant - * causes the optimizer to properly remove the aggragate from any - * elements of the query. Using just 'oid', which can not be null, in - * the parser fails on: + * There used to be a really ugly hack for count(*) here. * - * select count(*) from tab1, tab2 -- oid is not unique select - * count(*) from viewtable -- views don't have real oids + * It's gone. Now, the grammar transforms count(*) into count(1), + * which does the right thing. (It didn't use to do the right thing, + * because the optimizer had the wrong ideas about semantics of queries + * without explicit variables. Fixed as of Oct 1999 --- tgl.) * - * So, for an aggregate with parameter '*', we use the first valid range - * table entry, and pick the first column from the table. We set a - * flag to count nulls, because we could have nulls in that column. - * - * It's an ugly job, but someone has to do it. bjm 1998/1/18 + * Since "1" never evaluates as null, we currently have no need of + * the "usenulls" flag, but it should be kept around; in fact, we should + * extend the pg_aggregate table to let usenulls be specified as an + * attribute of user-defined aggregates. */ - if (nodeTag(lfirst(target)) == T_Const) - { - Const *con = (Const *) lfirst(target); - - if (con->consttype == UNKNOWNOID && VARSIZE(con->constvalue) == VARHDRSZ) - { - Attr *attr = makeNode(Attr); - List *rtable, - *rlist; - RangeTblEntry *first_valid_rte; - - Assert(lnext(target) == NULL); - - if (pstate->p_is_rule) - rtable = lnext(lnext(pstate->p_rtable)); - else - rtable = pstate->p_rtable; - - first_valid_rte = NULL; - foreach(rlist, rtable) - { - RangeTblEntry *rte = lfirst(rlist); - - /* only entries on outer(non-function?) scope */ - if (!rte->inFromCl && rte != pstate->p_target_rangetblentry) - continue; - - first_valid_rte = rte; - break; - } - if (first_valid_rte == NULL) - elog(ERROR, "Can't find column to do aggregate(*) on."); - - attr->relname = first_valid_rte->refname; - attr->attrs = lcons(makeString( - get_attname(first_valid_rte->relid, 1)), NIL); - - lfirst(target) = transformExpr(pstate, (Node *) attr, precedence); - usenulls = true; - } - } - aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple); fintype = aggform->aggfinaltype; xfn1 = aggform->aggtransfn1; |