[
https://issues.apache.org/jira/browse/CALCITE-7863?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18129837#comment-18129837
]
Julian Hyde commented on CALCITE-7863:
--------------------------------------
>From what I can tell, this rule should be called
>"AggregateReduceFunctionsWithConstantOperandsRule". Constant operands mean
>that the operand has the same value for every row in a group. This occurs when
>the expression consists only of literals, group keys, other constants (e.g.
>CURRENT_DATE), combined using pure deterministic operators.
Supported aggregate functions can map the operand expression to a result
expression.
This case deals with a new scenario, where the aggregate function's input is
known to be empty. This is very different from the case where the operands are
all the same value, and needs a new interface. Most aggregate functions
(including MIN, MAX, AVG, SUM, COLLECT, STRING_AGG, LISTAGG) return null when
their input is empty, and therefore the function in the interface should return
the null RexLiteral.
COUNT, SUM0 return literal 0 (of the appropriate type). LITERAL_AGG returns its
argument.
> 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
> Priority: Major
> Labels: pull-request-available
>
> {{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)