xiangfu0 commented on code in PR #19990:
URL: https://github.com/apache/pinot/pull/19990#discussion_r4365218811


##########
pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/AggregationFunctionType.java:
##########
@@ -428,6 +432,54 @@ public static AggregationFunctionType 
getAggregationFunctionType(String function
     }
   }
 
+  /// Accepts `(expr)` and `(expr, 'dataType')`. The data type must be one the 
value argument is read as, since the
+  /// multi-stage engine types the result after the value argument.
+  private static class AnyValueOperandTypeChecker implements 
SqlOperandTypeChecker {
+    private static final SqlOperandTypeChecker DELEGATE =
+        OperandTypes.or(OperandTypes.ANY, 
OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.CHARACTER));
+    // DECIMAL values are read as INT, LONG, DOUBLE or BIG_DECIMAL depending 
on their precision and scale
+    private static final Map<String, Set<SqlTypeName>> SQL_TYPES_BY_DATA_TYPE 
= Map.of(
+        "INT", Set.of(SqlTypeName.TINYINT, SqlTypeName.SMALLINT, 
SqlTypeName.INTEGER, SqlTypeName.UTINYINT,
+            SqlTypeName.USMALLINT, SqlTypeName.DECIMAL),
+        "LONG", Set.of(SqlTypeName.BIGINT, SqlTypeName.UINTEGER, 
SqlTypeName.DECIMAL),
+        "FLOAT", Set.of(SqlTypeName.REAL, SqlTypeName.FLOAT),
+        "DOUBLE", Set.of(SqlTypeName.DOUBLE, SqlTypeName.DECIMAL),
+        "BIG_DECIMAL", Set.of(SqlTypeName.DECIMAL),
+        "BOOLEAN", Set.of(SqlTypeName.BOOLEAN),
+        "TIMESTAMP", Set.of(SqlTypeName.DATE, SqlTypeName.TIME, 
SqlTypeName.TIMESTAMP),
+        "STRING", Set.of(SqlTypeName.CHAR, SqlTypeName.VARCHAR),
+        "BYTES", Set.of(SqlTypeName.BINARY, SqlTypeName.VARBINARY),
+        "UUID", Set.of(SqlTypeName.UUID));
+
+    @Override
+    public boolean checkOperandTypes(SqlCallBinding callBinding, boolean 
throwOnFailure) {
+      if (!DELEGATE.checkOperandTypes(callBinding, throwOnFailure)) {
+        return false;
+      }
+      if (callBinding.getOperandCount() == 2 && 
callBinding.isOperandLiteral(1, false)) {

Review Comment:
   Nit: when the call has 2 operands but the second isn't a literal, this check 
is skipped and the error only surfaces later as an `IllegalArgumentException` 
from the function constructor on the server. Not a correctness problem, but 
rejecting it here would give a cleaner planning-time message.



##########
pinot-core/src/main/java/org/apache/pinot/core/query/reduce/AggregationDataTableReducer.java:
##########
@@ -242,7 +242,10 @@ private ResultTable reduceToResultTable(DataSchema 
dataSchema, Object[] finalRes
     int numColumns = columnDataTypes.length;
     for (Object[] rewrittenRow : rows) {
       for (int j = 0; j < numColumns; j++) {
-        rewrittenRow[j] = columnDataTypes[j].format(rewrittenRow[j]);
+        Object value = rewrittenRow[j];
+        if (value != null) {
+          rewrittenRow[j] = columnDataTypes[j].format(value);

Review Comment:
   This null-guard looks correct and necessary: `format(null)` throws an NPE 
for BIG_DECIMAL/TIMESTAMP/BYTES/UUID, which is exactly the empty-input 
ANY_VALUE case. Just confirming it's intentional and covered by 
`testEmptyInput`.



-- 
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