Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 82f755e

Browse files
committed
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.
1 parent afa035c commit 82f755e

File tree

1 file changed

+34
-30
lines changed

1 file changed

+34
-30
lines changed

src/backend/executor/nodeAgg.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* Portions Copyright (c) 1994, Regents of the University of California
4646
*
4747
* IDENTIFICATION
48-
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.122 2004/06/06 00:41:26 tgl Exp $
48+
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.123 2004/07/10 18:39:23 tgl Exp $
4949
*
5050
*-------------------------------------------------------------------------
5151
*/
@@ -674,7 +674,6 @@ agg_retrieve_direct(AggState *aggstate)
674674
AggStatePerGroup pergroup;
675675
TupleTableSlot *outerslot;
676676
TupleTableSlot *firstSlot;
677-
TupleTableSlot *resultSlot;
678677
int aggno;
679678

680679
/*
@@ -696,11 +695,8 @@ agg_retrieve_direct(AggState *aggstate)
696695
* We loop retrieving groups until we find one matching
697696
* aggstate->ss.ps.qual
698697
*/
699-
do
698+
while (!aggstate->agg_done)
700699
{
701-
if (aggstate->agg_done)
702-
return NULL;
703-
704700
/*
705701
* If we don't already have the first tuple of the new group,
706702
* fetch it from the outer plan.
@@ -815,7 +811,7 @@ agg_retrieve_direct(AggState *aggstate)
815811
/*
816812
* If we have no first tuple (ie, the outerPlan didn't return
817813
* anything), create a dummy all-nulls input tuple for use by
818-
* ExecProject. 99.44% of the time this is a waste of cycles,
814+
* ExecQual/ExecProject. 99.44% of the time this is a waste of cycles,
819815
* because ordinarily the projected output tuple's targetlist
820816
* cannot contain any direct (non-aggregated) references to input
821817
* columns, so the dummy tuple will not be referenced. However
@@ -857,22 +853,28 @@ agg_retrieve_direct(AggState *aggstate)
857853
}
858854

859855
/*
860-
* Form a projection tuple using the aggregate results and the
861-
* representative input tuple. Store it in the result tuple slot.
862-
* Note we do not support aggregates returning sets ...
856+
* Use the representative input tuple for any references to
857+
* non-aggregated input columns in the qual and tlist.
863858
*/
864859
econtext->ecxt_scantuple = firstSlot;
865-
resultSlot = ExecProject(projInfo, NULL);
866860

867861
/*
868-
* If the completed tuple does not match the qualifications, it is
869-
* ignored and we loop back to try to process another group.
870-
* Otherwise, return the tuple.
862+
* Check the qual (HAVING clause); if the group does not match,
863+
* ignore it and loop back to try to process another group.
871864
*/
865+
if (ExecQual(aggstate->ss.ps.qual, econtext, false))
866+
{
867+
/*
868+
* Form and return a projection tuple using the aggregate results
869+
* and the representative input tuple. Note we do not support
870+
* aggregates returning sets ...
871+
*/
872+
return ExecProject(projInfo, NULL);
873+
}
872874
}
873-
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
874875

875-
return resultSlot;
876+
/* No more groups */
877+
return NULL;
876878
}
877879

878880
/*
@@ -934,7 +936,6 @@ agg_retrieve_hash_table(AggState *aggstate)
934936
AggStatePerGroup pergroup;
935937
AggHashEntry entry;
936938
TupleTableSlot *firstSlot;
937-
TupleTableSlot *resultSlot;
938939
int aggno;
939940

940941
/*
@@ -952,11 +953,8 @@ agg_retrieve_hash_table(AggState *aggstate)
952953
* We loop retrieving groups until we find one satisfying
953954
* aggstate->ss.ps.qual
954955
*/
955-
do
956+
while (!aggstate->agg_done)
956957
{
957-
if (aggstate->agg_done)
958-
return NULL;
959-
960958
/*
961959
* Find the next entry in the hash table
962960
*/
@@ -999,22 +997,28 @@ agg_retrieve_hash_table(AggState *aggstate)
999997
}
1000998

1001999
/*
1002-
* Form a projection tuple using the aggregate results and the
1003-
* representative input tuple. Store it in the result tuple slot.
1004-
* Note we do not support aggregates returning sets ...
1000+
* Use the representative input tuple for any references to
1001+
* non-aggregated input columns in the qual and tlist.
10051002
*/
10061003
econtext->ecxt_scantuple = firstSlot;
1007-
resultSlot = ExecProject(projInfo, NULL);
10081004

10091005
/*
1010-
* If the completed tuple does not match the qualifications, it is
1011-
* ignored and we loop back to try to process another group.
1012-
* Otherwise, return the tuple.
1006+
* Check the qual (HAVING clause); if the group does not match,
1007+
* ignore it and loop back to try to process another group.
10131008
*/
1009+
if (ExecQual(aggstate->ss.ps.qual, econtext, false))
1010+
{
1011+
/*
1012+
* Form and return a projection tuple using the aggregate results
1013+
* and the representative input tuple. Note we do not support
1014+
* aggregates returning sets ...
1015+
*/
1016+
return ExecProject(projInfo, NULL);
1017+
}
10141018
}
1015-
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
10161019

1017-
return resultSlot;
1020+
/* No more groups */
1021+
return NULL;
10181022
}
10191023

10201024
/* -----------------

0 commit comments

Comments
 (0)