FrankChen021 commented on code in PR #20093:
URL: https://github.com/apache/druid/pull/20093#discussion_r4026120338


##########
sql/src/main/java/org/apache/druid/sql/calcite/aggregation/builtin/SumZeroSqlAggregator.java:
##########
@@ -29,4 +37,42 @@ public SqlAggFunction calciteFunction()
   {
     return SqlStdOperatorTable.SUM0;
   }
-}
+
+  @Override
+  Aggregation getAggregation(
+      final String name,
+      final AggregateCall aggregateCall,
+      final ExprMacroTable macroTable,
+      final String fieldName
+  )
+  {
+    final ColumnType valueType = 
Calcites.getColumnTypeForRelDataType(aggregateCall.getType());
+    if (valueType == null) {
+      return null;
+    }
+
+    if (aggregateCall.filterArg >= 0) {
+      // SQL SUM0 semantics require 0 when the filter matches nothing, but the 
native
+      // FilteredAggregatorFactory chain outputs null for empty input. Wrap 
the sum in
+      // an expression post-aggregator that replaces null with 0. This keeps 
the
+      // D1 rewrite of DruidAggregateCaseToFilterRule semantically consistent 
with the
+      // original SUM(CASE WHEN ... THEN ... ELSE 0 END).
+      // Unfiltered SUM0 keeps the plain factory path to avoid widening this 
fix.
+      final String innerName = name + ":sum";
+      final AggregatorFactory innerFactory =
+          createSumAggregatorFactory(valueType, innerName, fieldName, 
macroTable);
+      return Aggregation.create(
+          ImmutableList.of(innerFactory),
+          new ExpressionPostAggregator(
+              name,
+              "nvl(\"" + innerName + "\", 0)",

Review Comment:
   [P2] Do not coalesce all-null matching values
   
   **Finding:** When every row passes the D1 filter but the input value is NULL 
for every such row, the original SUM(CASE WHEN ... THEN value ELSE 0 END) 
evaluates to NULL. The filtered native sum is also NULL, but this unconditional 
nvl converts it to 0, so enabling extendedFilteredSumRewrite changes a 
legitimate SQL result and cannot distinguish no matching rows from matching 
rows whose values are all NULL.
   
   **Suggestion:** Preserve the original nullable result for the 
all-matching/all-null case while still returning zero for an actually empty 
filter, and add a regression case covering both states.



##########
sql/src/main/java/org/apache/druid/sql/calcite/aggregation/builtin/SumZeroSqlAggregator.java:
##########
@@ -29,4 +37,42 @@ public SqlAggFunction calciteFunction()
   {
     return SqlStdOperatorTable.SUM0;
   }
-}
+
+  @Override
+  Aggregation getAggregation(
+      final String name,
+      final AggregateCall aggregateCall,
+      final ExprMacroTable macroTable,
+      final String fieldName
+  )
+  {
+    final ColumnType valueType = 
Calcites.getColumnTypeForRelDataType(aggregateCall.getType());
+    if (valueType == null) {
+      return null;
+    }
+
+    if (aggregateCall.filterArg >= 0) {

Review Comment:
   [P2] Keep filtered SUM0 usable in window aggregates
   
   **Finding:** This branch now gives every filtered SUM0 an 
ExpressionPostAggregator. Windowing.fromCalciteStuff explicitly rejects any 
translated aggregation with a post-aggregator, so SUM0(x) FILTER (WHERE ...) 
OVER (...)—a SUM0 operator exposed by DruidOperatorTable and previously 
translated to one filtered factory—now fails planning instead of executing.
   
   **Suggestion:** Limit the post-aggregation workaround to query shapes that 
support post-aggregators or add equivalent null-to-zero handling in the window 
frame processor, with a filtered SUM0 window regression test.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to