This is an automated email from the ASF dual-hosted git repository.

yashmayya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 005c5ab64b6 Fix Unknown nodes in multi-stage EXPLAIN when asking 
servers (#19766)
005c5ab64b6 is described below

commit 005c5ab64b6b7e09a3dadea4ebeae358081f0a23
Author: Yash Mayya <[email protected]>
AuthorDate: Tue Oct 6 18:11:51 2026 -0700

    Fix Unknown nodes in multi-stage EXPLAIN when asking servers (#19766)
---
 .../planner/logical/PlanNodeToRelConverter.java    |  2 +-
 .../query/planner/logical/RexExpressionUtils.java  | 38 +++++++++++++++-------
 .../planner/logical/RexExpressionUtilsTest.java    | 21 ++++++++++++
 3 files changed, 48 insertions(+), 13 deletions(-)

diff --git 
a/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/PlanNodeToRelConverter.java
 
b/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/PlanNodeToRelConverter.java
index fe16e9ba70d..973d502e7b3 100644
--- 
a/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/PlanNodeToRelConverter.java
+++ 
b/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/PlanNodeToRelConverter.java
@@ -360,7 +360,7 @@ public final class PlanNodeToRelConverter {
 
         List<Window.RexWinAggCall> aggCalls = new ArrayList<>();
         for (RexExpression.FunctionCall funCall : node.getAggCalls()) {
-          SqlAggFunction aggFunction = 
RexExpressionUtils.getAggFunction(funCall, _builder.getCluster());
+          SqlAggFunction aggFunction = 
RexExpressionUtils.getAggFunction(funCall);
           List<RexExpression> functionOperands = funCall.getFunctionOperands();
           List<RexNode> operands = new ArrayList<>(functionOperands.size());
           for (RexExpression functionOperand : functionOperands) {
diff --git 
a/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RexExpressionUtils.java
 
b/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RexExpressionUtils.java
index 73c6ca8bb5f..278e34ac074 100644
--- 
a/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RexExpressionUtils.java
+++ 
b/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RexExpressionUtils.java
@@ -32,7 +32,6 @@ import java.util.Set;
 import java.util.UUID;
 import javax.annotation.Nullable;
 import org.apache.calcite.avatica.util.ByteString;
-import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Window;
 import org.apache.calcite.rex.RexBuilder;
@@ -54,6 +53,7 @@ import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Sarg;
 import org.apache.calcite.util.TimestampString;
 import org.apache.pinot.calcite.rex.PinotSealedSearchOperator;
+import org.apache.pinot.calcite.sql.fun.PinotOperatorTable;
 import org.apache.pinot.common.function.scalar.arithmetic.NegateScalarFunction;
 import org.apache.pinot.common.utils.DataSchema.ColumnDataType;
 import org.apache.pinot.spi.utils.BooleanUtils;
@@ -93,10 +93,7 @@ public class RexExpressionUtils {
       operands.add(toRexNode(builder, functionOperand));
     }
     String functionName = rexExpression.getFunctionName();
-    SqlIdentifier sqlIdentifier = new SqlIdentifier(functionName, 
SqlParserPos.ZERO);
-    ArrayList<SqlOperator> operators = new ArrayList<>();
-    builder.getCluster().getRexBuilder().getOpTab()
-        .lookupOperatorOverloads(sqlIdentifier, null, SqlSyntax.FUNCTION, 
operators, SqlNameMatchers.liberal());
+    List<SqlOperator> operators = lookupOperators(functionName);
 
     if (operators.isEmpty()) {
       throw new IllegalArgumentException("No operator found for function: " + 
functionName);
@@ -105,6 +102,10 @@ public class RexExpressionUtils {
       LOGGER.info("Multiple operators found for function: {}, using the first 
one", functionName);
     }
     SqlOperator operator = operators.get(0);
+    if (operator.kind == SqlKind.IN) {
+      // Calcite creates IN as SEARCH
+      return builder.in(operands.get(0), operands.subList(1, operands.size()));
+    }
 
     return builder.call(operator, operands);
   }
@@ -169,18 +170,14 @@ public class RexExpressionUtils {
     for (RexExpression functionOperand : functionOperands) {
       operands.add(toRexNode(builder, functionOperand));
     }
-    SqlAggFunction sqlAggFunction = getAggFunction(functionCall, 
builder.getCluster());
+    SqlAggFunction sqlAggFunction = getAggFunction(functionCall);
 
     return builder.aggregateCall(sqlAggFunction, operands);
   }
 
-  public static SqlAggFunction getAggFunction(RexExpression.FunctionCall 
functionCall, RelOptCluster cluster) {
-    // TODO: This needs to be improved.
+  public static SqlAggFunction getAggFunction(RexExpression.FunctionCall 
functionCall) {
     String functionName = functionCall.getFunctionName();
-    SqlIdentifier sqlIdentifier = new SqlIdentifier(functionName, 
SqlParserPos.ZERO);
-    ArrayList<SqlOperator> operators = new ArrayList<>();
-    cluster.getRexBuilder().getOpTab()
-        .lookupOperatorOverloads(sqlIdentifier, null, SqlSyntax.FUNCTION, 
operators, SqlNameMatchers.liberal());
+    List<SqlOperator> operators = lookupOperators(functionName);
 
     ArrayList<SqlAggFunction> aggFunctions = new ArrayList<>(operators.size());
     for (SqlOperator operator : operators) {
@@ -197,6 +194,23 @@ public class RexExpressionUtils {
     return aggFunctions.get(0);
   }
 
+  /// Looks up the operators for a function name from [#getFunctionName], 
which uses the [SqlKind] name for most
+  /// standard operators, e.g. `SUM0` for `$SUM0`. Null handling does not 
change how these names resolve.
+  private static List<SqlOperator> lookupOperators(String functionName) {
+    PinotOperatorTable operatorTable = PinotOperatorTable.instance(true);
+    List<SqlOperator> operators = new ArrayList<>();
+    operatorTable.lookupOperatorOverloads(new SqlIdentifier(functionName, 
SqlParserPos.ZERO), null,
+        SqlSyntax.FUNCTION, operators, SqlNameMatchers.liberal());
+    if (operators.isEmpty()) {
+      for (SqlOperator operator : operatorTable.getOperatorList()) {
+        if (operator.kind.name().equals(functionName)) {
+          operators.add(operator);
+        }
+      }
+    }
+    return operators;
+  }
+
   public static RexExpression fromRexNode(RexNode rexNode) {
     if (rexNode instanceof RexInputRef) {
       return fromRexInputRef((RexInputRef) rexNode);
diff --git 
a/pinot-query-planner/src/test/java/org/apache/pinot/query/planner/logical/RexExpressionUtilsTest.java
 
b/pinot-query-planner/src/test/java/org/apache/pinot/query/planner/logical/RexExpressionUtilsTest.java
index 70a7199f479..0d5355c3627 100644
--- 
a/pinot-query-planner/src/test/java/org/apache/pinot/query/planner/logical/RexExpressionUtilsTest.java
+++ 
b/pinot-query-planner/src/test/java/org/apache/pinot/query/planner/logical/RexExpressionUtilsTest.java
@@ -45,6 +45,9 @@ import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
 
 /// Tests for RexExpressionUtils, focusing on the handleSearch method and null 
handling.
 public class RexExpressionUtilsTest {
@@ -71,6 +74,24 @@ public class RexExpressionUtilsTest {
     Assert.assertEquals(roundTrip.getValue(), uuid);
   }
 
+  @Test
+  public void testSqlKindFunctionNames() {
+    // Plan nodes name most standard operators by SqlKind, e.g. DIVIDE for "/" 
and SUM0 for "$SUM0"
+    RelBuilder relBuilder = 
RelBuilder.create(Frameworks.newConfigBuilder().build()).values(new 
String[]{"a"}, 1.0);
+    RexExpression input = new RexExpression.InputRef(0);
+    List<RexExpression> inOperands = List.of(input, new 
RexExpression.Literal(ColumnDataType.DOUBLE, 1.0),
+        new RexExpression.Literal(ColumnDataType.DOUBLE, 2.0));
+    for (RexExpression call : List.of(
+        new RexExpression.FunctionCall(ColumnDataType.DOUBLE, 
SqlKind.DIVIDE.name(), List.of(input, input)),
+        new RexExpression.FunctionCall(ColumnDataType.BOOLEAN, 
SqlKind.IN.name(), inOperands),
+        new RexExpression.FunctionCall(ColumnDataType.BOOLEAN, 
SqlKind.NOT_IN.name(), inOperands))) {
+      
assertEquals(RexExpressionUtils.fromRexNode(RexExpressionUtils.toRexNode(relBuilder,
 call)), call);
+    }
+    RexExpression.FunctionCall sum0 =
+        new RexExpression.FunctionCall(ColumnDataType.DOUBLE, 
SqlKind.SUM0.name(), List.of(input));
+    assertSame(RexExpressionUtils.getAggFunction(sum0), 
SqlStdOperatorTable.SUM0);
+  }
+
   @Test
   public void testHandleSearchNullLiteralInWithNullAsUnknown() {
     // Test: NULL IN (1, 2, 3) (when nullAs = UNKNOWN)


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

Reply via email to