mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 23:56:58 +03:00
Test HAVING condition before computing targetlist of an Aggregate node.
This is required by SQL spec to avoid failures in cases like SELECT sum(win)/sum(lose) FROM ... GROUP BY ... HAVING sum(lose) > 0; AFAICT we have gotten this wrong since day one. Kudos to Holger Jakobs for being the first to notice.
This commit is contained in:
parent
afa035c204
commit
82f755ec80
@ -45,7 +45,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.122 2004/06/06 00:41:26 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.123 2004/07/10 18:39:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -674,7 +674,6 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
AggStatePerGroup pergroup;
|
AggStatePerGroup pergroup;
|
||||||
TupleTableSlot *outerslot;
|
TupleTableSlot *outerslot;
|
||||||
TupleTableSlot *firstSlot;
|
TupleTableSlot *firstSlot;
|
||||||
TupleTableSlot *resultSlot;
|
|
||||||
int aggno;
|
int aggno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -696,11 +695,8 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
* We loop retrieving groups until we find one matching
|
* We loop retrieving groups until we find one matching
|
||||||
* aggstate->ss.ps.qual
|
* aggstate->ss.ps.qual
|
||||||
*/
|
*/
|
||||||
do
|
while (!aggstate->agg_done)
|
||||||
{
|
{
|
||||||
if (aggstate->agg_done)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we don't already have the first tuple of the new group,
|
* If we don't already have the first tuple of the new group,
|
||||||
* fetch it from the outer plan.
|
* fetch it from the outer plan.
|
||||||
@ -815,7 +811,7 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
/*
|
/*
|
||||||
* If we have no first tuple (ie, the outerPlan didn't return
|
* If we have no first tuple (ie, the outerPlan didn't return
|
||||||
* anything), create a dummy all-nulls input tuple for use by
|
* anything), create a dummy all-nulls input tuple for use by
|
||||||
* ExecProject. 99.44% of the time this is a waste of cycles,
|
* ExecQual/ExecProject. 99.44% of the time this is a waste of cycles,
|
||||||
* because ordinarily the projected output tuple's targetlist
|
* because ordinarily the projected output tuple's targetlist
|
||||||
* cannot contain any direct (non-aggregated) references to input
|
* cannot contain any direct (non-aggregated) references to input
|
||||||
* columns, so the dummy tuple will not be referenced. However
|
* columns, so the dummy tuple will not be referenced. However
|
||||||
@ -857,22 +853,28 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Form a projection tuple using the aggregate results and the
|
* Use the representative input tuple for any references to
|
||||||
* representative input tuple. Store it in the result tuple slot.
|
* non-aggregated input columns in the qual and tlist.
|
||||||
* Note we do not support aggregates returning sets ...
|
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_scantuple = firstSlot;
|
econtext->ecxt_scantuple = firstSlot;
|
||||||
resultSlot = ExecProject(projInfo, NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the completed tuple does not match the qualifications, it is
|
* Check the qual (HAVING clause); if the group does not match,
|
||||||
* ignored and we loop back to try to process another group.
|
* ignore it and loop back to try to process another group.
|
||||||
* Otherwise, return the tuple.
|
|
||||||
*/
|
*/
|
||||||
|
if (ExecQual(aggstate->ss.ps.qual, econtext, false))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Form and return a projection tuple using the aggregate results
|
||||||
|
* and the representative input tuple. Note we do not support
|
||||||
|
* aggregates returning sets ...
|
||||||
|
*/
|
||||||
|
return ExecProject(projInfo, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
|
|
||||||
|
|
||||||
return resultSlot;
|
/* No more groups */
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -934,7 +936,6 @@ agg_retrieve_hash_table(AggState *aggstate)
|
|||||||
AggStatePerGroup pergroup;
|
AggStatePerGroup pergroup;
|
||||||
AggHashEntry entry;
|
AggHashEntry entry;
|
||||||
TupleTableSlot *firstSlot;
|
TupleTableSlot *firstSlot;
|
||||||
TupleTableSlot *resultSlot;
|
|
||||||
int aggno;
|
int aggno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -952,11 +953,8 @@ agg_retrieve_hash_table(AggState *aggstate)
|
|||||||
* We loop retrieving groups until we find one satisfying
|
* We loop retrieving groups until we find one satisfying
|
||||||
* aggstate->ss.ps.qual
|
* aggstate->ss.ps.qual
|
||||||
*/
|
*/
|
||||||
do
|
while (!aggstate->agg_done)
|
||||||
{
|
{
|
||||||
if (aggstate->agg_done)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the next entry in the hash table
|
* Find the next entry in the hash table
|
||||||
*/
|
*/
|
||||||
@ -999,22 +997,28 @@ agg_retrieve_hash_table(AggState *aggstate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Form a projection tuple using the aggregate results and the
|
* Use the representative input tuple for any references to
|
||||||
* representative input tuple. Store it in the result tuple slot.
|
* non-aggregated input columns in the qual and tlist.
|
||||||
* Note we do not support aggregates returning sets ...
|
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_scantuple = firstSlot;
|
econtext->ecxt_scantuple = firstSlot;
|
||||||
resultSlot = ExecProject(projInfo, NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the completed tuple does not match the qualifications, it is
|
* Check the qual (HAVING clause); if the group does not match,
|
||||||
* ignored and we loop back to try to process another group.
|
* ignore it and loop back to try to process another group.
|
||||||
* Otherwise, return the tuple.
|
|
||||||
*/
|
*/
|
||||||
|
if (ExecQual(aggstate->ss.ps.qual, econtext, false))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Form and return a projection tuple using the aggregate results
|
||||||
|
* and the representative input tuple. Note we do not support
|
||||||
|
* aggregates returning sets ...
|
||||||
|
*/
|
||||||
|
return ExecProject(projInfo, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
|
|
||||||
|
|
||||||
return resultSlot;
|
/* No more groups */
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------
|
/* -----------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user