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

gortiz 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 08b76f1aa50 Udf improvements (#16431)
08b76f1aa50 is described below

commit 08b76f1aa50ab0bb549ee2648c53f89a0370f6fc
Author: Gonzalo Ortiz Jaureguizar <[email protected]>
AuthorDate: Tue Aug 12 18:28:55 2025 +0200

    Udf improvements (#16431)
---
 .../apache/pinot/common/function/FunctionInfo.java |   8 +
 .../scalar/array/ArrayLengthScalarFunction.java    |   6 +
 .../apache/pinot/core/udf/UdfExampleBuilder.java   |   4 +
 .../pinot/integration/tests/udf/AvroSink.java      |   5 +-
 ...rayConcatDouble.yaml => arrayconcatdouble.yaml} |   0
 ...rayElementAtInt.yaml => arrayelementatint.yaml} |   0
 .../{arrayMax.yaml => arraymax.yaml}               |   0
 .../{isFalse.yaml => isfalse.yaml}                 |   0
 .../{toDateTime.yaml => todatetime.yaml}           |   0
 .../apache/pinot/spi/utils/BigDecimalUtils.java    |   8 +-
 .../org/apache/pinot/udf/test/UdfReporter.java     | 232 ++++++++++++---------
 .../apache/pinot/udf/test/UdfTestFramework.java    |  23 +-
 .../scenarios/IntermediateUdfTestScenario.java     |   2 +-
 13 files changed, 189 insertions(+), 99 deletions(-)

diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionInfo.java 
b/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionInfo.java
index 43373ba162e..6675417739e 100644
--- 
a/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionInfo.java
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionInfo.java
@@ -19,6 +19,7 @@
 package org.apache.pinot.common.function;
 
 import java.lang.reflect.Method;
+import org.apache.pinot.spi.annotations.ScalarFunction;
 
 
 public class FunctionInfo {
@@ -43,4 +44,11 @@ public class FunctionInfo {
   public boolean hasNullableParameters() {
     return _nullableParameters;
   }
+
+  public static FunctionInfo fromMethod(Method method) {
+    ScalarFunction annotation = method.getAnnotation(ScalarFunction.class);
+    boolean nullableParameters = annotation != null && 
annotation.nullableParameters();
+
+    return new FunctionInfo(method, method.getDeclaringClass(), 
nullableParameters);
+  }
 }
diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/array/ArrayLengthScalarFunction.java
 
b/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/array/ArrayLengthScalarFunction.java
index 58dc6ce00c2..45c8319c608 100644
--- 
a/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/array/ArrayLengthScalarFunction.java
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/array/ArrayLengthScalarFunction.java
@@ -20,6 +20,7 @@ package org.apache.pinot.common.function.scalar.array;
 
 import java.util.EnumMap;
 import java.util.Map;
+import java.util.Set;
 import javax.annotation.Nullable;
 import org.apache.pinot.common.function.FunctionInfo;
 import org.apache.pinot.common.function.PinotScalarFunction;
@@ -61,6 +62,11 @@ public class ArrayLengthScalarFunction implements 
PinotScalarFunction {
     return "ARRAYLENGTH";
   }
 
+  @Override
+  public Set<String> getNames() {
+    return Set.of("ARRAYLENGTH", "CARDINALITY");
+  }
+
   @Nullable
   @Override
   public PinotSqlFunction toPinotSqlFunction() {
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/udf/UdfExampleBuilder.java 
b/pinot-core/src/main/java/org/apache/pinot/core/udf/UdfExampleBuilder.java
index 9c39906fed1..2a101b13fd5 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/udf/UdfExampleBuilder.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/udf/UdfExampleBuilder.java
@@ -71,6 +71,10 @@ public interface UdfExampleBuilder {
       Preconditions.checkArgument(example.getInputValues().size() == 
_signature.getArity(),
           "Expected %s input values for signature %s, but got %s",
           _signature.getArity(), _signature, example.getInputValues().size());
+      if (_examples.stream().anyMatch(e -> e.getId().equals(example.getId()))) 
{
+        throw new IllegalArgumentException(
+            "Example with id '" + example.getId() + "' already exists for 
signature " + _signature);
+      }
       _examples.add(example);
       return this;
     }
diff --git 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/udf/AvroSink.java
 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/udf/AvroSink.java
index a97f949edcf..af364db6ab1 100644
--- 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/udf/AvroSink.java
+++ 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/udf/AvroSink.java
@@ -130,8 +130,9 @@ public class AvroSink implements AutoCloseable {
   private static void addType(
       FieldSpec.DataType dataType, Schema scalarSchema, Schema nullSchema) {
     NOT_NULL_SCALAR_MAP.put(dataType, scalarSchema);
-    NULL_SCALAR_MAP.put(dataType, Schema.createUnion(scalarSchema, 
nullSchema));
-    Schema multiValueSchema = Schema.createArray(scalarSchema);
+    Schema nullableSchema = Schema.createUnion(scalarSchema, nullSchema);
+    NULL_SCALAR_MAP.put(dataType, nullableSchema);
+    Schema multiValueSchema = Schema.createArray(nullableSchema);
     NOT_NULL_MULTI_VALUE_MAP.put(dataType, multiValueSchema);
     NULL_MULTI_VALUE_MAP.put(dataType, Schema.createUnion(multiValueSchema, 
nullSchema));
   }
diff --git 
a/pinot-integration-tests/src/test/resources/udf-test-results/arrayConcatDouble.yaml
 
b/pinot-integration-tests/src/test/resources/udf-test-results/arrayconcatdouble.yaml
similarity index 100%
rename from 
pinot-integration-tests/src/test/resources/udf-test-results/arrayConcatDouble.yaml
rename to 
pinot-integration-tests/src/test/resources/udf-test-results/arrayconcatdouble.yaml
diff --git 
a/pinot-integration-tests/src/test/resources/udf-test-results/arrayElementAtInt.yaml
 
b/pinot-integration-tests/src/test/resources/udf-test-results/arrayelementatint.yaml
similarity index 100%
rename from 
pinot-integration-tests/src/test/resources/udf-test-results/arrayElementAtInt.yaml
rename to 
pinot-integration-tests/src/test/resources/udf-test-results/arrayelementatint.yaml
diff --git 
a/pinot-integration-tests/src/test/resources/udf-test-results/arrayMax.yaml 
b/pinot-integration-tests/src/test/resources/udf-test-results/arraymax.yaml
similarity index 100%
rename from 
pinot-integration-tests/src/test/resources/udf-test-results/arrayMax.yaml
rename to 
pinot-integration-tests/src/test/resources/udf-test-results/arraymax.yaml
diff --git 
a/pinot-integration-tests/src/test/resources/udf-test-results/isFalse.yaml 
b/pinot-integration-tests/src/test/resources/udf-test-results/isfalse.yaml
similarity index 100%
rename from 
pinot-integration-tests/src/test/resources/udf-test-results/isFalse.yaml
rename to 
pinot-integration-tests/src/test/resources/udf-test-results/isfalse.yaml
diff --git 
a/pinot-integration-tests/src/test/resources/udf-test-results/toDateTime.yaml 
b/pinot-integration-tests/src/test/resources/udf-test-results/todatetime.yaml
similarity index 100%
rename from 
pinot-integration-tests/src/test/resources/udf-test-results/toDateTime.yaml
rename to 
pinot-integration-tests/src/test/resources/udf-test-results/todatetime.yaml
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/BigDecimalUtils.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/BigDecimalUtils.java
index ef89a2b96f6..23099b2dd97 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/BigDecimalUtils.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/BigDecimalUtils.java
@@ -128,8 +128,12 @@ public class BigDecimalUtils {
     return valueBytes;
   }
 
-  /**
-   * Deserializes a big decimal from a byte array.
+   /**
+    * Deserializes a `BigDecimal` from a byte array.
+    * The expected format is:
+    * - First 2 bytes: scale (big-endian, unsigned short)
+    * - Remaining bytes: unscaled value (big-endian two's complement, as per 
`BigInteger.toByteArray()`)
+    * This matches the serialization format used in `serialize(BigDecimal 
value)`.
    */
   public static BigDecimal deserialize(byte[] bytes) {
     int scale = (short) ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
diff --git 
a/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfReporter.java 
b/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfReporter.java
index bf897bb39a8..dc8eb56dc87 100644
--- a/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfReporter.java
+++ b/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfReporter.java
@@ -74,74 +74,117 @@ public class UdfReporter {
 
   private static void reportScenarios(Udf udf, UdfTestResult.ByScenario 
byScenario, PrintWriter report,
       TreeSet<UdfTestScenario> scenarios) {
-    report.append("### Scenarios\n\n");
 
-    // This is used to create a collapsed section in the markdown report
-    report.append("<details>\n"
-        + "\n"
-        + "<summary>Click to open</summary>\n\n");
+    if (byScenario.getMap().values().stream()
+        .flatMap(bySignature -> bySignature.getMap().values().stream())
+        .noneMatch(UdfReporter::requiresScenarioForSignature)) {
+      return;
+    }
+
+    report.append("### Scenarios\n\n");
 
     for (UdfTestScenario scenario : scenarios) {
       UdfTestResult.BySignature bySignature = 
byScenario.getMap().get(scenario);
 
-      TreeSet<UdfSignature> signatures = new 
TreeSet<>(Comparator.comparing(UdfSignature::toString));
-      signatures.addAll(bySignature.getMap().keySet());
+      if 
(bySignature.getMap().values().stream().noneMatch(UdfReporter::requiresScenarioForSignature))
 {
+        continue;
+      }
 
       report.append("#### ").append(scenario.getTitle()).append("\n\n");
 
-      report.append('\n');
+      TreeSet<UdfSignature> signatures = new 
TreeSet<>(Comparator.comparing(UdfSignature::toString));
+      signatures.addAll(bySignature.getMap().keySet());
 
-      report.append("| Signature | Call | Expected result | Actual result | 
Comparison or Error |\n");
-      
report.append("|-----------|------|-----------------|---------------|---------------------|\n");
+      report.append('\n');
 
-      for (UdfSignature signature : signatures) {
+      if (signatures.size() == 1) {
+        UdfSignature signature = signatures.iterator().next();
         ResultByExample resultByExample = bySignature.getMap().get(signature);
 
-        if (resultByExample instanceof ResultByExample.Partial) {
-          ResultByExample.Partial partial = (ResultByExample.Partial) 
resultByExample;
-          for (Map.Entry<UdfExample, UdfExampleResult> exampleEntry : 
partial.getResultsByExample().entrySet()) {
-            UdfExample example = exampleEntry.getKey();
-            UdfExampleResult testResult = exampleEntry.getValue();
+        reportScenarioForSignature(udf, report, resultByExample);
+      } else {
+        for (UdfSignature signature : signatures) {
+          report.append("##### For 
").append(signature.toString()).append("\n\n");
 
-            // Signature column
-            report.append("| ")
-                .append(signature.toString()).append(" | ");
+          ResultByExample resultByExample = 
bySignature.getMap().get(signature);
+          reportScenarioForSignature(udf, report, resultByExample);
+        }
+      }
+      report.append("\n");
+    }
+  }
 
-            // Call column
-            report.append(asSqlCallWithLiteralArgs(udf, udf.getMainName(), 
example.getInputValues()))
-                .append(" | ");
+  private static boolean requiresScenarioForSignature(ResultByExample 
resultByExample) {
+    if (!(resultByExample instanceof ResultByExample.Partial)) {
+      return true;
+    }
+    ResultByExample.Partial partial = (ResultByExample.Partial) 
resultByExample;
+    for (Map.Entry<UdfExample, UdfExampleResult> exampleEntry : 
partial.getResultsByExample().entrySet()) {
+      UdfExample example = exampleEntry.getKey();
+      String error = partial.getErrorsByExample().get(example);
+      if (error != null) {
+        return true;
+      }
+      UdfTestFramework.EquivalenceLevel comparison = 
partial.getEquivalenceByExample().get(example);
+      if (comparison != UdfTestFramework.EquivalenceLevel.EQUAL) {
+        return true;
+      }
+    }
+    return false;
+  }
 
-            // Expected result
-            Object expected = testResult.getExpectedResult();
-            Object actual = testResult.getActualResult();
-
-            Function<Object, String> valueFormatter = 
getResultFormatter(expected, actual);
-            report.append(valueFormatter.apply(expected)).append(" | ")
-                .append(valueFormatter.apply(actual)).append(" | ");
-
-            // Comparison or Error
-            String error = partial.getErrorsByExample().get(example);
-            if (error != null) {
-              report.append("❌ ").append(error.replace("\n", " ")).append(" 
|\n");
-            } else {
-              UdfTestFramework.EquivalenceLevel comparison = 
partial.getEquivalenceByExample().get(example);
-              report.append(comparison != null ? comparison.name() : 
"").append(" |\n");
-            }
-          }
-        } else if (resultByExample instanceof ResultByExample.Failure) {
-          ResultByExample.Failure failure = (ResultByExample.Failure) 
resultByExample;
-
-          report.append("| ")
-              .append(signature.toString())
-              .append(" | - | - | - | ❌ ")
-              .append(failure.getErrorMessage().replace("\n", " "))
-              .append(" |\n");
+  private static void reportScenarioForSignature(Udf udf, PrintWriter report, 
ResultByExample resultByExample) {
+    report.append("| Example | Call | Expected result | Actual result | Report 
|\n");
+    
report.append("|---------|------|-----------------|---------------|--------|\n");
+
+    if (resultByExample instanceof ResultByExample.Partial) {
+      ResultByExample.Partial partial = (ResultByExample.Partial) 
resultByExample;
+      Set<Map.Entry<UdfExample, UdfExampleResult>> entries = new TreeSet<>(
+          Comparator.comparing(entry -> entry.getKey().getId()));
+      entries.addAll(partial.getResultsByExample().entrySet());
+      for (Map.Entry<UdfExample, UdfExampleResult> exampleEntry : entries) {
+        UdfExample example = exampleEntry.getKey();
+        UdfExampleResult testResult = exampleEntry.getValue();
+
+        // Skip examples whose result is the expected one
+        String error = partial.getErrorsByExample().get(example);
+        UdfTestFramework.EquivalenceLevel comparison = error == null
+            ? partial.getEquivalenceByExample().get(example)
+            : null;
+        if (comparison == UdfTestFramework.EquivalenceLevel.EQUAL) {
+          continue;
+        }
+
+        // Signature column
+        report.append("| ")
+            .append(example.getId()).append(" | ");
+
+        // Call column
+        report.append(asSqlCallWithLiteralArgs(udf, udf.getMainName(), 
example.getInputValues()))
+            .append(" | ");
+
+        // Expected result
+        Object expected = testResult.getExpectedResult();
+        Object actual = testResult.getActualResult();
+
+        Function<Object, String> valueFormatter = getResultFormatter(expected, 
actual);
+        report.append(valueFormatter.apply(expected)).append(" | ")
+            .append(valueFormatter.apply(actual)).append(" | ");
+
+        // Comparison or Error
+        if (error != null) {
+          report.append("❌ ").append(error.replace("\n", " ")).append(" |\n");
+        } else {
+          report.append(comparison != null ? comparison.name() : "").append(" 
|\n");
         }
       }
-      report.append("\n");
+    } else if (resultByExample instanceof ResultByExample.Failure) {
+      ResultByExample.Failure failure = (ResultByExample.Failure) 
resultByExample;
+
+      report.append("| - | - | - | - | ❌ ")
+          .append(failure.getErrorMessage().replace("\n", " "))
+          .append(" |\n");
     }
-    // Close the collapsed section
-    report.append("\n</details>\n\n");
   }
 
   private static void reportSignatures(Udf udf, PrintWriter report) {
@@ -200,14 +243,27 @@ public class UdfReporter {
         .min(Comparator.comparing(UdfSignature::toString))
         .ifPresent(udfSignature -> {
 
-          report.append("|Call | Result (with null handling) | Result (without 
null handling)\n");
-          
report.append("|-----|-----------------------------|------------------------------|\n");
+          report.append("| Call | Result (with null handling) | Result 
(without null handling) | |\n");
+          
report.append("|------|-----------------------------|--------------------------------|-|\n");
 
           for (UdfExample example : udf.getExamples().get(udfSignature)) {
             // Expected result
-            Object withNull = 
example.getResult(UdfExample.NullHandling.DISABLED);
+            Object withNull = 
example.getResult(UdfExample.NullHandling.ENABLED);
             Object withoutNull = 
example.getResult(UdfExample.NullHandling.DISABLED);
 
+            boolean someFail = byScenario.getMap().values().stream()
+                .anyMatch(bySignature ->
+                  bySignature.getMap().values().stream()
+                      .anyMatch(result -> {
+                        if (result instanceof ResultByExample.Failure) {
+                          return true;
+                        }
+                        ResultByExample.Partial partial = 
(ResultByExample.Partial) result;
+                        UdfTestFramework.EquivalenceLevel equivalence = 
partial.getEquivalenceByExample().get(example);
+                        return equivalence != 
UdfTestFramework.EquivalenceLevel.EQUAL;
+                      })
+                );
+
             // Call column
             report.append("| ")
                 .append(asSqlCallWithLiteralArgs(udf, udf.getMainName(), 
example.getInputValues()))
@@ -215,6 +271,8 @@ public class UdfReporter {
                 .append(valueToString(withNull))
                 .append(" | ")
                 .append(valueToString(withoutNull))
+                .append(" | ")
+                .append(someFail ? "⚠" : "✅")
                 .append(" |\n");
           }
           report.append("\n");
@@ -307,46 +365,9 @@ public class UdfReporter {
     }
   }
 
-  private static Function<Object, String> getResultFormatter(Object expected, 
Object actual) {
-    Function<Object, String> valueFormatter;
-    if (expected != null && actual != null && 
expected.getClass().equals(actual.getClass())) {
-      valueFormatter = value -> {
-        if (value.getClass().isArray()) {
-          return Arrays.toString((Object[]) value);
-        }
-        return value.toString();
-      };
-    } else {
-      valueFormatter = value -> {
-        if (value == null) {
-          return "NULL";
-        } else if (value.getClass().isArray()) {
-          String componentTypeName = 
value.getClass().getComponentType().getSimpleName();
-          String valueDesc;
-          switch (componentTypeName) {
-            case "int":
-              valueDesc = Arrays.toString((int[]) value);
-              break;
-            case "long":
-              valueDesc = Arrays.toString((long[]) value);
-              break;
-            case "float":
-              valueDesc = Arrays.toString((float[]) value);
-              break;
-            case "double":
-              valueDesc = Arrays.toString((double[]) value);
-              break;
-            default:
-              valueDesc = Arrays.toString((Object[]) value);
-              break;
-          }
-          return valueDesc + " ( array of " + componentTypeName + ")";
-        } else {
-          return value + " (" + value.getClass().getSimpleName() + ")";
-        }
-      };
-    }
-    return valueFormatter;
+  private static Function<Object, String> getResultFormatter(@Nullable Object 
expected, @Nullable Object actual) {
+    boolean describeType = expected == null || actual == null || 
!expected.getClass().equals(actual.getClass());
+    return value -> describeValue(value, describeType);
   }
 
   private static String asSqlCallWithLiteralArgs(Udf udf, String name, 
List<Object> inputs) {
@@ -355,4 +376,29 @@ public class UdfReporter {
         .collect(Collectors.toList());
     return udf.asSqlCall(name, args);
   }
+
+  private static String describeValue(@Nullable Object value, boolean 
includeType) {
+    if (value == null) {
+      return "NULL";
+    }
+    if (value.getClass().isArray()) {
+      String componentTypeName = 
value.getClass().getComponentType().getSimpleName();
+      switch (componentTypeName) {
+        case "int":
+          return Arrays.toString((int[]) value) + (includeType ? " (array of 
int)" : "");
+        case "long":
+          return Arrays.toString((long[]) value) + (includeType ? " (array of 
long)" : "");
+        case "float":
+          return Arrays.toString((float[]) value) + (includeType ? " (array of 
float)" : "");
+        case "double":
+          return Arrays.toString((double[]) value) + (includeType ? " (array 
of double)" : "");
+        case "byte":
+          return "hexToBytes('" + BytesUtils.toHexString((byte[]) value) + "')"
+              + (includeType ? " (array of byte)" : "");
+        default:
+          return Arrays.toString((Object[]) value) + (includeType ? " (array 
of " + componentTypeName + ")" : "");
+      }
+    }
+    return value + (includeType ? " (" + value.getClass().getSimpleName() + 
")" : "");
+  }
 }
diff --git 
a/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfTestFramework.java 
b/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfTestFramework.java
index 421f7c55449..03437420b03 100644
--- 
a/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfTestFramework.java
+++ 
b/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/UdfTestFramework.java
@@ -19,6 +19,7 @@
 package org.apache.pinot.udf.test;
 
 import com.google.common.collect.Maps;
+import com.google.common.math.DoubleMath;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -180,6 +181,9 @@ public class UdfTestFramework {
       if (e.getCause().getMessage().contains("Unsupported function")) {
         return new ResultByExample.Failure("Unsupported");
       }
+      if (e.getCause().getMessage().contains("Caught exception while doing 
operator")) {
+        return new ResultByExample.Failure("Operator execution error");
+      }
       return new ResultByExample.Failure(e.getCause().getMessage());
     }
   }
@@ -210,6 +214,10 @@ public class UdfTestFramework {
       actual = canonizeObject(actual);
       switch (this) {
         case EQUAL:
+          if (expected instanceof Double && actual instanceof Double
+            && !doubleEquals((Double) expected, (Double) actual)) {
+            throw new AssertionError(describeDiscrepancy(expected, actual));
+          }
           if (!Objects.equals(expected, actual)) {
             throw new AssertionError(describeDiscrepancy(expected, actual));
           }
@@ -233,7 +241,7 @@ public class UdfTestFramework {
                 + "comparison, but got: expected=" + expected + "(of type " + 
expectedClass + ")"
                 + ", actual=" + actual + "(of type " + actualClass + ")");
           }
-          if (Double.compare(((Number) expected).doubleValue(), ((Number) 
actual).doubleValue()) != 0) {
+          if (!doubleEquals(((Number) expected).doubleValue(), ((Number) 
actual).doubleValue())) {
             throw new AssertionError(describeDiscrepancy(expected, actual));
           }
           break;
@@ -278,6 +286,14 @@ public class UdfTestFramework {
             list.add(f);
           }
           return list;
+        } else if (componentType == byte.class) {
+          // Convert byte array to List<Byte> for consistency
+          byte[] byteArray = (byte[]) value;
+          ArrayList<Byte> list = new ArrayList<>(byteArray.length);
+          for (byte b : byteArray) {
+            list.add(b);
+          }
+          return list;
         } else {
           return Arrays.asList((Object[]) value);
         }
@@ -285,4 +301,9 @@ public class UdfTestFramework {
       return value;
     }
   }
+
+  private static boolean doubleEquals(double d1, double d2) {
+    double epsilon = 0.0001d;
+    return DoubleMath.fuzzyEquals(d1, d2, epsilon);
+  }
 }
diff --git 
a/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/scenarios/IntermediateUdfTestScenario.java
 
b/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/scenarios/IntermediateUdfTestScenario.java
index 5dbb090f422..b52e3313a5f 100644
--- 
a/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/scenarios/IntermediateUdfTestScenario.java
+++ 
b/pinot-udf-test/src/main/java/org/apache/pinot/udf/test/scenarios/IntermediateUdfTestScenario.java
@@ -91,7 +91,7 @@ public class IntermediateUdfTestScenario extends 
AbstractUdfTestScenario {
             + "@otherCols\n"
             + "  FROM @table_OFFLINE AS t1 \n"
             + "  JOIN @table_OFFLINE AS t2 \n"
-            + "  ON t1.@testCol = t2.@testCol AND t1.@signatureCol = 
t2.@signatureCol \n"
+            + "  ON t1.@testCol = t2.@testCol AND t1.@signatureCol = 
t2.@signatureCol and t1.udf = t2.udf \n"
             + ")\n"
             + "SELECT \n"
             + "  @testCol as test, \n"


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

Reply via email to