Zhen Chen created CALCITE-7863:
----------------------------------

             Summary: AggregateReduceFunctionsOnGroupKeysRule fails for 
constant aggregates on empty input
                 Key: CALCITE-7863
                 URL: https://issues.apache.org/jira/browse/CALCITE-7863
             Project: Calcite
          Issue Type: Bug
          Components: core
    Affects Versions: 1.42.0
            Reporter: Zhen Chen
            Assignee: Zhen Chen


{{AggregateReduceFunctionsOnGroupKeysRule}} incorrectly replaces constant 
aggregate calls with their arguments when the aggregate has no grouping keys.

For a global aggregate, an empty input must still produce one row. {{MIN(1)}} 
and {{MAX(1)}} must return {{NULL}} in that row. Replacing these calls with the 
constant {{1}} does not preserve this behavior.

The issue requires explicitly applying this rule. The query returns the correct 
result with the default planner configuration.

To reproduce in a Quidem test, enable this rule:
{code:java}
!set hep-rules "
+CoreRules.AGGREGATE_REDUCE_FUNCTIONS_ON_GROUP_KEYS"
 {code}
Then execute:
{code:java}
SELECT
    MIN(1) AS min_v,
    MAX(1) AS max_v
FROM (VALUES (7)) AS t(x)
WHERE x < 0; {code}
*Expected result:* One row containing two {{NULL}} values.
{code:java}
+-------+-------+
| MIN_V | MAX_V |
+-------+-------+
|       |       |
+-------+-------+
(1 row) {code}
*Actual behavior before the fix:* Query preparation fails with an 
{{{}AssertionError{}}}:

 

{{java.lang.AssertionError: Cannot add expression of different type to set:
set type is RecordType(INTEGER MIN_V, INTEGER MAX_V) NOT NULL
expression type is RecordType(INTEGER NOT NULL MIN_V, INTEGER NOT NULL MAX_V) 
NOT NULL
expression is LogicalValues(tuples=[[\{ 1, 1 }]])
Type mismatch:
rowtype of original rel: RecordType(INTEGER MIN_V, INTEGER MAX_V) NOT NULL
rowtype of new rel: RecordType(INTEGER NOT NULL MIN_V, INTEGER NOT NULL MAX_V) 
NOT NULL
Difference:
MIN_V: INTEGER -> INTEGER NOT NULL
MAX_V: INTEGER -> INTEGER NOT NULL}}

The rule generates a constant row {{{}(1, 1){}}}. Its non-nullable output types 
differ from the nullable aggregate output types, so the planner rejects the 
transformation. The incorrect row is not returned to the user.

*Cause and proposed fix:*

The rule checks that an expression references only grouping keys. A literal 
references no columns, so it passes this check even when the grouping set is 
empty. The rule then replaces the aggregate call without accounting for 
empty-input semantics.

Skip aggregates with no grouping keys in this rule. Add a regression test in 
{{hep.iq}} that explicitly enables only 
{{AGGREGATE_REDUCE_FUNCTIONS_ON_GROUP_KEYS}} and verifies both the expected 
{{NULL}} results and the execution plan.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to