This is an automated email from the ASF dual-hosted git repository.
jhyde pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 2447a2d1cf [CALCITE-7073] If the Java return type of a UDF is
ByteString, Calcite should deduce that the SQL type is VARBINARY
2447a2d1cf is described below
commit 2447a2d1cff183452422a0a33edb036be5c4d918
Author: Lucas Brenner <[email protected]>
AuthorDate: Wed Jun 25 16:13:59 2025 -0300
[CALCITE-7073] If the Java return type of a UDF is ByteString, Calcite
should deduce that the SQL type is VARBINARY
Add UDF type-mapping from ByteString to VARBINARY.
Close apache/calcite#4440
---
.../sql/type/JavaToSqlTypeConversionRules.java | 2 ++
.../test/java/org/apache/calcite/test/UdfTest.java | 36 +++++++++++++++++++---
.../main/java/org/apache/calcite/util/Smalls.java | 15 +++++++++
3 files changed, 48 insertions(+), 5 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/sql/type/JavaToSqlTypeConversionRules.java
b/core/src/main/java/org/apache/calcite/sql/type/JavaToSqlTypeConversionRules.java
index f1941b29fe..7b4b8a2a87 100644
---
a/core/src/main/java/org/apache/calcite/sql/type/JavaToSqlTypeConversionRules.java
+++
b/core/src/main/java/org/apache/calcite/sql/type/JavaToSqlTypeConversionRules.java
@@ -17,6 +17,7 @@
package org.apache.calcite.sql.type;
import org.apache.calcite.avatica.util.ArrayImpl;
+import org.apache.calcite.avatica.util.ByteString;
import com.google.common.collect.ImmutableMap;
@@ -62,6 +63,7 @@ public class JavaToSqlTypeConversionRules {
.put(boolean.class, SqlTypeName.BOOLEAN)
.put(Boolean.class, SqlTypeName.BOOLEAN)
.put(byte[].class, SqlTypeName.VARBINARY)
+ .put(ByteString.class, SqlTypeName.VARBINARY)
.put(String.class, SqlTypeName.VARCHAR)
.put(char[].class, SqlTypeName.VARCHAR)
.put(Character.class, SqlTypeName.CHAR)
diff --git a/core/src/test/java/org/apache/calcite/test/UdfTest.java
b/core/src/test/java/org/apache/calcite/test/UdfTest.java
index 674b1e6c2a..581364fdec 100644
--- a/core/src/test/java/org/apache/calcite/test/UdfTest.java
+++ b/core/src/test/java/org/apache/calcite/test/UdfTest.java
@@ -182,6 +182,12 @@ private CalciteAssert.AssertThat withUdf() {
+ Smalls.AllTypesFunction.class.getName()
+ "',\n"
+ " methodName: '*'\n"
+ + " },\n"
+ + " {\n"
+ + " name: 'UNBASE64',\n"
+ + " className: '"
+ + Smalls.MyUnbase64Function.class.getName()
+ + "'\n"
+ " }\n"
+ " ]\n"
+ " }\n"
@@ -728,7 +734,7 @@ private CalciteAssert.AssertThat withUdf() {
/** Test case for
* <a
href="https://issues.apache.org/jira/browse/CALCITE-1434">[CALCITE-1434]
- * AggregateFunctionImpl doesnt work if the class implements a generic
+ * AggregateFunctionImpl doesn't work if the class implements a generic
* interface</a>. */
@Test void testUserDefinedAggregateFunctionImplementsInterface() {
final String empDept = JdbcTest.EmpDeptTableFactory.class.getName();
@@ -1037,11 +1043,9 @@ private static CalciteAssert.AssertThat
withBadUdf(Class<?> clazz) {
.returnsValue("0");
}
- /**
- * Test case for
+ /** Test case for
* <a
href="https://issues.apache.org/jira/browse/CALCITE-1834">[CALCITE-1834]
- * User-defined function for Arrays</a>.
- */
+ * User-defined function for Arrays</a>. */
@Test void testArrayUserDefinedFunction() throws Exception {
try (Connection connection = DriverManager.getConnection("jdbc:calcite:"))
{
CalciteConnection calciteConnection =
@@ -1075,6 +1079,28 @@ private static CalciteAssert.AssertThat
withBadUdf(Class<?> clazz) {
}
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7073">[CALCITE-7073]
+ * If the UDF's Java return type is ByteString, Calcite should deduce that
the
+ * SQL type is VARBINARY</a>.
+ *
+ * <p>Tests that the {@code UNBASE64} user-defined function correctly decodes
+ * a Base64 string and its return type ({@code VARBINARY}, mapped from
+ * {@link org.apache.calcite.avatica.util.ByteString}) is fully compatible
for
+ * direct comparison with SQL {@code VARBINARY} literals ({@code X'...'})
+ * within queries. */
+ @Test void testUnbase64DirectComparison() {
+ final String testHex = "74657374"; // "test" in bytes
+ final String testBase64 = "dGVzdA=="; // Base64 for "test"
+
+ final String sql = "values \"adhoc\".unbase64('" + testBase64 + "')";
+ withUdf().query(sql).typeIs("[EXPR$0 VARBINARY]");
+
+ final String sql2 = "select \"adhoc\".unbase64(cast('" + testBase64
+ + "' as varchar)) = x'" + testHex + "' as C\n";
+ withUdf().query(sql2).returns("C=true\n");
+ }
+
/**
* Base class for functions that append arrays.
*/
diff --git a/testkit/src/main/java/org/apache/calcite/util/Smalls.java
b/testkit/src/main/java/org/apache/calcite/util/Smalls.java
index 963b11590f..3ffd3efda9 100644
--- a/testkit/src/main/java/org/apache/calcite/util/Smalls.java
+++ b/testkit/src/main/java/org/apache/calcite/util/Smalls.java
@@ -19,6 +19,7 @@
import org.apache.calcite.DataContext;
import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
import org.apache.calcite.adapter.java.AbstractQueryableTable;
+import org.apache.calcite.avatica.util.ByteString;
import org.apache.calcite.config.CalciteConnectionConfig;
import org.apache.calcite.linq4j.AbstractEnumerable;
import org.apache.calcite.linq4j.BaseQueryable;
@@ -1477,4 +1478,18 @@ private Object[] convertRow(Object[] full) {
BuiltInMethod.QUERYABLE_AS_ENUMERABLE.method);
}
}
+
+ /** User-defined function that decodes a Base64 string to bytes. */
+ public static class MyUnbase64Function {
+ public static ByteString eval(String s) {
+ if (s == null) {
+ return null;
+ }
+ try {
+ return ByteString.ofBase64(s);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ }
}