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);

Reply via email to