1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-03 15:22:11 +03:00

Make the behavior of HAVING without GROUP BY conform to the SQL spec.

Formerly, if such a clause contained no aggregate functions we mistakenly
treated it as equivalent to WHERE.  Per spec it must cause the query to
be treated as a grouped query of a single group, the same as appearance
of aggregate functions would do.  Also, the HAVING filter must execute
after aggregate function computation even if it itself contains no
aggregate functions.
This commit is contained in:
Tom Lane
2005-03-10 23:21:26 +00:00
parent 609e32b929
commit 595ed2a855
20 changed files with 385 additions and 238 deletions

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.147 2004/12/31 22:00:45 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.148 2005/03/10 23:21:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -181,18 +181,6 @@ rewriteRuleAction(Query *parsetree,
}
}
/*
* We copy the qualifications of the parsetree to the action and vice
* versa. So force hasSubLinks if one of them has it. If this is not
* right, the flag will get cleared later, but we mustn't risk having
* it not set when it needs to be. (XXX this should probably be
* handled by AddQual and friends, not here...)
*/
if (parsetree->hasSubLinks)
sub_action->hasSubLinks = TRUE;
else if (sub_action->hasSubLinks)
parsetree->hasSubLinks = TRUE;
/*
* Event Qualification forces copying of parsetree and splitting into
* two queries one w/rule_qual, one w/NOT rule_qual. Also add user
@@ -996,23 +984,6 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
QTW_IGNORE_RT_SUBQUERIES);
/*
* If the query was marked having aggregates, check if this is still
* true after rewriting. Ditto for sublinks. Note there should be no
* aggs in the qual at this point. (Does this code still do anything
* useful? The view-becomes-subselect-in-FROM approach doesn't look
* like it could remove aggs or sublinks...)
*/
if (parsetree->hasAggs)
{
parsetree->hasAggs = checkExprHasAggs((Node *) parsetree);
if (parsetree->hasAggs)
if (checkExprHasAggs((Node *) parsetree->jointree))
elog(ERROR, "failed to remove aggregates from qual");
}
if (parsetree->hasSubLinks)
parsetree->hasSubLinks = checkExprHasSubLink((Node *) parsetree);
return parsetree;
}

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.89 2004/12/31 22:00:46 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.90 2005/03/10 23:21:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,8 +37,7 @@ static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
/*
* checkExprHasAggs -
* Queries marked hasAggs might not have them any longer after
* rewriting. Check it.
* Check if an expression contains an aggregate function call.
*
* The objective of this routine is to detect whether there are aggregates
* belonging to the initial query level. Aggregates belonging to subqueries
@@ -93,8 +92,7 @@ checkExprHasAggs_walker(Node *node, checkExprHasAggs_context *context)
/*
* checkExprHasSubLink -
* Queries marked hasSubLinks might not have them any longer after
* rewriting. Check it.
* Check if an expression contains a SubLink.
*/
bool
checkExprHasSubLink(Node *node)
@@ -756,68 +754,14 @@ AddQual(Query *parsetree, Node *qual)
copy);
/*
* Make sure query is marked correctly if added qual has sublinks or
* aggregates (not sure it can ever have aggs, but sublinks
* definitely). Need not search qual when query is already marked.
* We had better not have stuck an aggregate into the WHERE clause.
*/
if (!parsetree->hasAggs)
parsetree->hasAggs = checkExprHasAggs(copy);
if (!parsetree->hasSubLinks)
parsetree->hasSubLinks = checkExprHasSubLink(copy);
}
/*
* Add the given havingQual to the one already contained in the parsetree
* just as AddQual does for the normal 'where' qual
*/
void
AddHavingQual(Query *parsetree, Node *havingQual)
{
Node *copy;
if (havingQual == NULL)
return;
if (parsetree->commandType == CMD_UTILITY)
{
/*
* There's noplace to put the qual on a utility statement.
*
* See comments in AddQual for motivation.
*/
if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
return;
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("conditional utility statements are not implemented")));
}
if (parsetree->setOperations != NULL)
{
/*
* There's noplace to put the qual on a setop statement, either.
* (This could be fixed, but right now the planner simply ignores
* any qual condition on a setop query.)
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
}
/* INTERSECT want's the original, but we need to copy - Jan */
copy = copyObject(havingQual);
parsetree->havingQual = make_and_qual(parsetree->havingQual,
copy);
Assert(!checkExprHasAggs(copy));
/*
* Make sure query is marked correctly if added qual has sublinks or
* aggregates (not sure it can ever have aggs, but sublinks
* definitely). Need not search qual when query is already marked.
* Make sure query is marked correctly if added qual has sublinks.
* Need not search qual when query is already marked.
*/
if (!parsetree->hasAggs)
parsetree->hasAggs = checkExprHasAggs(copy);
if (!parsetree->hasSubLinks)
parsetree->hasSubLinks = checkExprHasSubLink(copy);
}