This is an automated email from the ASF dual-hosted git repository.
mbudiu 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 a44373782f [CALCITE-7368] The validator accepts CAST(INT TO BINARY),
but the runtime does not implement them
a44373782f is described below
commit a44373782fc4609f5da81a3c24725fd1af34ae8d
Author: Mihai Budiu <[email protected]>
AuthorDate: Tue Feb 17 17:27:33 2026 -0800
[CALCITE-7368] The validator accepts CAST(INT TO BINARY), but the runtime
does not implement them
Signed-off-by: Mihai Budiu <[email protected]>
---
.../adapter/enumerable/RexToLixTranslator.java | 14 +++++
.../org/apache/calcite/runtime/SqlFunctions.java | 61 ++++++++++++++++++++++
.../org/apache/calcite/util/BuiltInMethod.java | 1 +
.../org/apache/calcite/test/SqlOperatorTest.java | 25 +++++++++
4 files changed, 101 insertions(+)
diff --git
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index e7b8657bf5..f88170b1b5 100644
---
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -387,6 +387,7 @@ private Expression getConvertExpression(
case VARBINARY:
case BINARY:
+ int binaryPrecision = targetType.getPrecision();
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
@@ -394,6 +395,19 @@ private Expression getConvertExpression(
new ConstantExpression(Charset.class, sourceType.getCharset()));
case UUID:
return Expressions.call(BuiltInMethod.UUID_TO_BINARY.method, operand);
+ case BIGINT:
+ case INTEGER:
+ case SMALLINT:
+ case TINYINT:
+ case UBIGINT:
+ case UINTEGER:
+ case USMALLINT:
+ case UTINYINT:
+ return Expressions.call(
+ BuiltInMethod.INT_TO_BINARY.method,
+ operand,
+ Expressions.constant(binaryPrecision),
+ Expressions.constant(targetType.getSqlTypeName() ==
SqlTypeName.BINARY));
default:
return defaultExpression.get();
}
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index f9a74cec9a..a729d34916 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -89,6 +89,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
@@ -1272,6 +1273,66 @@ public static String formatNumber(BigDecimal value, int
decimalVal) {
return numberFormat.format(value);
}
+ /** Implements casts from integer to binary values.
+ *
+ * @param value Value converted; an integer or unsigned value.
+ * @param resultSize Size of result in bytes; negative if unspecified.
+ * @param fixed True if the result type is BINARY; false for VARBINARY.
+ * @return A ByteString containing the conversion result.
+ *
+ * <p>Most SQL dialects which support this feature seem to convert integers
to big endian values,
+ * and then truncate or pad on the left when the size of the target BINARY
does not exactly
+ * match the integer's size.
+ */
+ public static ByteString intToBinary(Object value, int resultSize, boolean
fixed) {
+ ByteBuffer buffer;
+ if (value instanceof Byte) {
+ buffer = ByteBuffer.allocate(1)
+ .order(ByteOrder.BIG_ENDIAN)
+ .put((byte) value);
+ } else if (value instanceof Short) {
+ buffer = ByteBuffer.allocate(2)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putShort((short) value);
+ } else if (value instanceof Integer) {
+ buffer = ByteBuffer.allocate(4)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putInt((Integer) value);
+ } else if (value instanceof Long) {
+ buffer = ByteBuffer.allocate(8)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putLong((Long) value);
+ } else if (value instanceof UByte) {
+ buffer = ByteBuffer.allocate(1)
+ .order(ByteOrder.BIG_ENDIAN)
+ .put(((UByte) value).byteValue());
+ } else if (value instanceof UShort) {
+ buffer = ByteBuffer.allocate(2)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putShort(((UShort) value).shortValue());
+ } else if (value instanceof UInteger) {
+ buffer = ByteBuffer.allocate(4)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putInt(((UInteger) value).intValue());
+ } else if (value instanceof ULong) {
+ buffer = ByteBuffer.allocate(8)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putLong(((ULong) value).longValue());
+ } else {
+ throw new IllegalArgumentException("Unexpected argument type " + value);
+ }
+ ByteString result = new ByteString(buffer.array());
+ if (resultSize >= 0) {
+ if (resultSize < result.length()) {
+ result = SqlFunctions.right(result, resultSize);
+ } else if (fixed && resultSize > result.length()) {
+ // pad on left
+ result = new ByteString(new byte[resultSize -
result.length()]).concat(result);
+ }
+ }
+ return result;
+ }
+
public static String formatNumber(long value, String format) {
DecimalFormat numberFormat = getNumberFormat(format);
return numberFormat.format(value);
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index 465a89347e..7ff2995282 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -534,6 +534,7 @@ public enum BuiltInMethod {
UUID_FROM_STRING(UUID.class, "fromString", String.class),
UUID_TO_STRING(SqlFunctions.class, "uuidToString", UUID.class),
UUID_TO_BINARY(SqlFunctions.class, "uuidToBinary", UUID.class),
+ INT_TO_BINARY(SqlFunctions.class, "intToBinary", Object.class, int.class,
boolean.class),
BINARY_TO_UUID(SqlFunctions.class, "binaryToUuid", ByteString.class),
INITCAP(SqlFunctions.class, "initcap", String.class),
SUBSTRING(SqlFunctions.class, "substring", String.class, int.class,
diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
index 5fb37c5812..b3de8a3c51 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -4056,6 +4056,31 @@ void checkIsNull(SqlOperatorFixture f, SqlOperator
operator) {
f.setFor(SqlStdOperatorTable.EXISTS, VM_EXPAND);
}
+ /** Test cases for <a
href="https://issues.apache.org/jira/browse/CALCITE-7368">[CALCITE-7368]
+ * The validator accepts CAST(INT TO BINARY), but the runtime does not
implement them</a>. */
+ @Test void testCastIntToBinary() {
+ final SqlOperatorFixture f = fixture();
+ f.checkNull("cast(CAST(NULL AS INT) AS VARBINARY)");
+ f.checkScalar("cast(10 as BINARY(4))", "0000000a", "BINARY(4) NOT NULL");
+ f.checkScalar("cast(10 AS BINARY(2))", "000a", "BINARY(2) NOT NULL");
+ f.checkScalar("cast(10 as VARBINARY(4))", "0000000a", "VARBINARY(4) NOT
NULL");
+ f.checkScalar("cast(10 as VARBINARY(2))", "000a", "VARBINARY(2) NOT NULL");
+ f.checkScalar("cast(cast(10 AS INT UNSIGNED) AS BINARY(4))", "0000000a",
"BINARY(4) NOT NULL");
+ f.checkScalar("cast(-1 AS BINARY(4))", "ffffffff", "BINARY(4) NOT NULL");
+ f.checkScalar("cast(-1 AS VARBINARY(8))", "ffffffff", "VARBINARY(8) NOT
NULL");
+ f.checkScalar("cast(10 AS VARBINARY)", "0000000a", "VARBINARY NOT NULL");
+ f.checkScalar("cast(cast(10 AS TINYINT) AS VARBINARY)", "0a", "VARBINARY
NOT NULL");
+ f.checkScalar("cast(cast(-1 AS TINYINT) AS VARBINARY)", "ff", "VARBINARY
NOT NULL");
+ f.checkScalar("cast(cast(-1 AS TINYINT) AS BINARY(4))", "000000ff",
"BINARY(4) NOT NULL");
+ f.checkScalar("cast(cast(10 AS BIGINT) AS VARBINARY(16))",
"000000000000000a",
+ "VARBINARY(16) NOT NULL");
+ f.checkScalar("cast(cast(10 AS BIGINT) AS VARBINARY(8))",
"000000000000000a",
+ "VARBINARY(8) NOT NULL");
+ f.checkScalar("cast(cast(10 AS BIGINT) AS VARBINARY(6))", "00000000000a",
+ "VARBINARY(6) NOT NULL");
+ f.checkScalar("cast(cast(10 AS BIGINT) AS VARBINARY(4))", "0000000a",
"VARBINARY(4) NOT NULL");
+ }
+
@Test void testNotOperator() {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.NOT, VmName.EXPAND);