Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/backend/gporca/libgpopt/src/operators/CNormalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "gpopt/base/CUtils.h"
#include "gpopt/operators/CLogical.h"
#include "gpopt/operators/CLogicalConstTableGet.h"
#include "gpopt/operators/CLogicalGbAgg.h"
#include "gpopt/operators/CLogicalInnerJoin.h"
#include "gpopt/operators/CLogicalLeftOuterCorrelatedApply.h"
#include "gpopt/operators/CLogicalLeftOuterJoin.h"
Expand Down Expand Up @@ -126,6 +127,18 @@ CNormalizer::FPushable(CExpression *pexprLogical, CExpression *pexprPred)
return false;
}

// do not push predicates below a scalar (plain) aggregate, i.e. one with
// no grouping columns. A scalar aggregate produces exactly one output row
// regardless of input cardinality, so a predicate above it (HAVING clause)
// must be evaluated against that output row, not the aggregate's input.
// Pushing e.g. "HAVING false" below would leave the agg emitting one row
// (e.g. count = 0) instead of zero rows.
if (COperator::EopLogicalGbAgg == pexprLogical->Pop()->Eopid() &&
0 == CLogicalGbAgg::PopConvert(pexprLogical->Pop())->Pdrgpcr()->Size())
{
return false;
}


CColRefSet *pcrsUsed = pexprPred->DeriveUsedColumns();
CColRefSet *pcrsOutput = pexprLogical->DeriveOutputColumns();
Expand Down
19 changes: 19 additions & 0 deletions src/test/regress/expected/groupingsets.out
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,25 @@ explain (costs off)
Optimizer: Postgres query optimizer
(13 rows)

-- HAVING with constant-false predicate on an empty grouping set must emit
-- zero rows, not the default scalar-aggregate row.
select count(*) from gstest2 group by grouping sets (()) having false;
count
-------
(0 rows)

explain (costs off)
select count(*) from gstest2 group by grouping sets (()) having false;
QUERY PLAN
-------------------------------------
Aggregate
Group Key: ()
Filter: false
-> Result
One-Time Filter: false
Optimizer: Postgres query optimizer
(6 rows)

-- HAVING with GROUPING queries
select ten, grouping(ten) from onek
group by grouping sets(ten) having grouping(ten) >= 0
Expand Down
16 changes: 16 additions & 0 deletions src/test/regress/expected/groupingsets_optimizer.out
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,22 @@ explain (costs off)
Optimizer: GPORCA
(13 rows)

-- HAVING with constant-false predicate on an empty grouping set must emit
-- zero rows, not the default scalar-aggregate row.
select count(*) from gstest2 group by grouping sets (()) having false;
count
-------
(0 rows)

explain (costs off)
select count(*) from gstest2 group by grouping sets (()) having false;
QUERY PLAN
--------------------------
Result
One-Time Filter: false
Optimizer: GPORCA
(3 rows)

-- HAVING with GROUPING queries
select ten, grouping(ten) from onek
group by grouping sets(ten) having grouping(ten) >= 0
Expand Down
6 changes: 6 additions & 0 deletions src/test/regress/sql/groupingsets.sql
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ explain (costs off)
select v.c, (select count(*) from gstest2 group by () having v.c)
from (values (false),(true)) v(c) order by v.c;

-- HAVING with constant-false predicate on an empty grouping set must emit
-- zero rows, not the default scalar-aggregate row.
select count(*) from gstest2 group by grouping sets (()) having false;
explain (costs off)
select count(*) from gstest2 group by grouping sets (()) having false;

-- HAVING with GROUPING queries
select ten, grouping(ten) from onek
group by grouping sets(ten) having grouping(ten) >= 0
Expand Down
Loading