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]