From 76836e6bea42f3fbfc24fa54a3459b8f4aab9a73 Mon Sep 17 00:00:00 2001 From: Lucas Brenner Date: Wed, 25 Jun 2025 16:13:59 -0300 Subject: [PATCH 1/5] Add mapping from ByteString to VARBINARY --- .../apache/calcite/sql/type/JavaToSqlTypeConversionRules.java | 2 ++ 1 file changed, 2 insertions(+) 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 f1941b29fef1..7b4b8a2a8779 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) From a28713c78b0df6ef4e451e31adf41bcc01533502 Mon Sep 17 00:00:00 2001 From: Lucas Brenner Date: Wed, 25 Jun 2025 16:38:39 -0300 Subject: [PATCH 2/5] Add test --- .../java/org/apache/calcite/sql/type/SqlTypeUtilTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java index ac0bda1b87eb..37cd26aca6f9 100644 --- a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java +++ b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.sql.type; +import org.apache.calcite.avatica.util.ByteString; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.sql.SqlBasicTypeNameSpec; @@ -293,4 +294,10 @@ private static void assertCanCast(RelDataType toType, RelDataType fromType) { "Expected to be able to cast from %s to %s without coercion.", fromType, toType), SqlTypeUtil.canCastFrom(toType, fromType, /* coerce= */ defaultRules), is(true)); } + + @Test void testJavaToSqlByteStringMapping() { + SqlTypeName sqlTypeName = JavaToSqlTypeConversionRules.instance().lookup(ByteString.class); + assertThat("ByteString.class should map to SqlTypeName.VARBINARY", + sqlTypeName, is(SqlTypeName.VARBINARY)); + } } From eb3944de946f894288b823770ae018dee28d477b Mon Sep 17 00:00:00 2001 From: Lucas Brenner Date: Thu, 26 Jun 2025 10:45:47 -0300 Subject: [PATCH 3/5] Add user-defined function test --- .../java/org/apache/calcite/test/UdfTest.java | 22 +++++++++++++++++++ .../java/org/apache/calcite/util/Smalls.java | 15 +++++++++++++ 2 files changed, 37 insertions(+) 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 674b1e6c2aad..3f923fae09f4 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" @@ -1075,6 +1081,22 @@ private static CalciteAssert.AssertThat withBadUdf(Class clazz) { } } + /** Test case for + * [CALCITE-7073] + * Tests that the UNBASE64 user-defined function correctly decodes a Base64 string + * and its return type (VARBINARY, mapped from ByteString) is fully + * compatible for direct comparison with SQL VARBINARY literals (X'...') + * within queries. */ + @Test + void testUnbase64DirectComparison() { + final String testHex = "74657374"; // "test" in bytes + final String testBase64 = "dGVzdA=="; // Base64 for "test" + + final String sql = "select \"adhoc\".unbase64(cast('" + testBase64 + "' as varchar)) = x'" + testHex + "' as C\n"; + + withUdf().query(sql).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 963b11590f66..3ffd3efda98d 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; + } + } + } } From 07faed3171ab7bcf6bc92ad8a48e5dbcf42cf74d Mon Sep 17 00:00:00 2001 From: Lucas Brenner Date: Thu, 26 Jun 2025 11:08:49 -0300 Subject: [PATCH 4/5] autostyleApply --- core/src/test/java/org/apache/calcite/test/UdfTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 3f923fae09f4..bc0e9d8d47f1 100644 --- a/core/src/test/java/org/apache/calcite/test/UdfTest.java +++ b/core/src/test/java/org/apache/calcite/test/UdfTest.java @@ -1087,8 +1087,7 @@ private static CalciteAssert.AssertThat withBadUdf(Class clazz) { * and its return type (VARBINARY, mapped from ByteString) is fully * compatible for direct comparison with SQL VARBINARY literals (X'...') * within queries. */ - @Test - void testUnbase64DirectComparison() { + @Test void testUnbase64DirectComparison() { final String testHex = "74657374"; // "test" in bytes final String testBase64 = "dGVzdA=="; // Base64 for "test" From 740344691602d8f67d00c6bcc2c3cfcfbdd10ced Mon Sep 17 00:00:00 2001 From: Lucas Brenner Date: Thu, 26 Jun 2025 11:22:20 -0300 Subject: [PATCH 5/5] Fix line length --- core/src/test/java/org/apache/calcite/test/UdfTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 bc0e9d8d47f1..df70a1d185b1 100644 --- a/core/src/test/java/org/apache/calcite/test/UdfTest.java +++ b/core/src/test/java/org/apache/calcite/test/UdfTest.java @@ -1082,7 +1082,7 @@ private static CalciteAssert.AssertThat withBadUdf(Class clazz) { } /** Test case for - * [CALCITE-7073] + * [CALCITE-7073] * Tests that the UNBASE64 user-defined function correctly decodes a Base64 string * and its return type (VARBINARY, mapped from ByteString) is fully * compatible for direct comparison with SQL VARBINARY literals (X'...') @@ -1091,7 +1091,8 @@ private static CalciteAssert.AssertThat withBadUdf(Class clazz) { final String testHex = "74657374"; // "test" in bytes final String testBase64 = "dGVzdA=="; // Base64 for "test" - final String sql = "select \"adhoc\".unbase64(cast('" + testBase64 + "' as varchar)) = x'" + testHex + "' as C\n"; + final String sql = "select \"adhoc\".unbase64(cast('" + testBase64 + "' as varchar))" + + " = x'" + testHex + "' as C\n"; withUdf().query(sql).returns("C=true\n"); }