You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by mb...@apache.org on 2024/10/04 17:54:30 UTC

(calcite) branch main updated: [CALCITE-3592] Implement BITNOT scalar function

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 547ab35460 [CALCITE-3592] Implement BITNOT scalar function
547ab35460 is described below

commit 547ab35460f370f2ae76216aa374323e9dc7e07e
Author: Norman Jordan <no...@improving.com>
AuthorDate: Thu Sep 26 13:55:18 2024 -0700

    [CALCITE-3592] Implement BITNOT scalar function
    
    * Implemented the BITNOT scalar function as a standard function
    * Supports integer and binary arguments
    * Returns NULL if the argument is NULL
---
 .../calcite/adapter/enumerable/RexImpTable.java    |  3 ++
 .../org/apache/calcite/runtime/SqlFunctions.java   | 15 ++++++++++
 .../main/java/org/apache/calcite/sql/SqlKind.java  |  3 ++
 .../calcite/sql/fun/SqlStdOperatorTable.java       |  8 ++++++
 .../org/apache/calcite/sql/type/ReturnTypes.java   | 10 +++++++
 .../org/apache/calcite/util/BuiltInMethod.java     |  1 +
 site/_docs/reference.md                            |  1 +
 .../org/apache/calcite/test/SqlOperatorTest.java   | 33 ++++++++++++++++++++++
 8 files changed, 74 insertions(+)

diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index ea373aa931..2b21dc3499 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -346,6 +346,7 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ATAN;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ATAN2;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BITAND;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BITCOUNT;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BITNOT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BITOR;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BITXOR;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BIT_AND;
@@ -702,6 +703,8 @@ public class RexImpTable {
           NullPolicy.STRICT);
       defineMethod(BITXOR, BuiltInMethod.BIT_XOR.method,
           NullPolicy.STRICT);
+      defineMethod(BITNOT, BuiltInMethod.BIT_NOT.method,
+          NullPolicy.STRICT);
       define(CONCAT, new ConcatImplementor());
       defineMethod(CONCAT_FUNCTION, BuiltInMethod.MULTI_STRING_CONCAT.method,
           NullPolicy.STRICT);
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 aa12deeac1..09e3a41d65 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -2941,6 +2941,21 @@ public class SqlFunctions {
     return binaryOperator(b0, b1, (x, y) -> (byte) (x ^ y));
   }
 
+  /** Bitwise function <code>BIT_NOT</code> applied to integer values. */
+  public static long bitNot(long b) {
+    return ~b;
+  }
+
+  /** Bitwise function <code>BIT_NOT</code> applied to a binary value. */
+  public static ByteString bitNot(ByteString b) {
+    final byte[] result = new byte[b.length()];
+    for (int i = 0; i < b.length(); i++) {
+      result[i] = (byte) ~b.byteAt(i);
+    }
+
+    return new ByteString(result);
+  }
+
   /**
    * Utility for bitwise function applied to two byteString values.
    *
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index 64f6928301..03a0178f05 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -1116,6 +1116,9 @@ public enum SqlKind {
   /** The {@code BITXOR} scalar function. */
   BITXOR,
 
+  /** The {@code BITNOT} scalar function. */
+  BITNOT,
+
   /** The {@code BIT_AND} aggregate function. */
   BIT_AND,
 
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 2be1800acc..00dd8df9b3 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -1220,6 +1220,14 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
           ReturnTypes.LARGEST_INT_OR_FIRST_NON_NULL,
           OperandTypes.INTEGER_INTEGER.or(OperandTypes.BINARY_BINARY));
 
+  /**
+   * <code>BITNOT</code> scalar function.
+   */
+  public static final SqlFunction BITNOT =
+      SqlBasicFunction.create("BITNOT", SqlKind.BITNOT,
+          ReturnTypes.ARG0_OR_INTEGER,
+          OperandTypes.INTEGER.or(OperandTypes.BINARY));
+
   /**
    * <code>BIT_AND</code> aggregate function.
    */
diff --git a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java
index e2e4c2fb5f..ae8596e01e 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java
@@ -613,6 +613,16 @@ public abstract class ReturnTypes {
   public static final SqlReturnTypeInference ARG0_EXCEPT_INTEGER_NULLABLE =
       ARG0_EXCEPT_INTEGER.andThen(SqlTypeTransforms.TO_NULLABLE);
 
+  public static final SqlReturnTypeInference ARG0_OR_INTEGER =
+      opBinding -> {
+        final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
+        if (SqlTypeName.NULL == opBinding.getOperandType(0).getSqlTypeName()) {
+          return typeFactory.createTypeWithNullability(
+              typeFactory.createSqlType(SqlTypeName.INTEGER), true);
+        }
+        return opBinding.getOperandType(0);
+      };
+
   /**
    * Chooses a type to return.
    * If all arguments are null, return nullable integer type.
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 af8515308f..bedea92211 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -648,6 +648,7 @@ public enum BuiltInMethod {
   BITCOUNT(SqlFunctions.class, "bitCount", BigDecimal.class),
   BIT_OR(SqlFunctions.class, "bitOr", long.class, long.class),
   BIT_XOR(SqlFunctions.class, "bitXor", long.class, long.class),
+  BIT_NOT(SqlFunctions.class, "bitNot", long.class),
   MODIFIABLE_TABLE_GET_MODIFIABLE_COLLECTION(ModifiableTable.class,
       "getModifiableCollection"),
   SCANNABLE_TABLE_SCAN(ScannableTable.class, "scan", DataContext.class),
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 3d855df7fb..c18bf6f691 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2753,6 +2753,7 @@ In the following:
 | * | BITAND(value1, value2)                         | Returns the bitwise AND of *value1* and *value2*. *value1* and *value2* must both be integer or binary values. Binary values must be of the same length.
 | * | BITOR(value1, value2)                          | Returns the bitwise OR of *value1* and *value2*. *value1* and *value2* must both be integer or binary values. Binary values must be of the same length.
 | * | BITXOR(value1, value2)                         | Returns the bitwise XOR of *value1* and *value2*. *value1* and *value2* must both be integer or binary values. Binary values must be of the same length.
+| * | BITNOT(value)                                  | Returns the bitwise NOT of *value*. *value* must be either an integer type or a binary value.
 | f | BITAND_AGG(value)                              | Equivalent to `BIT_AND(value)`
 | f | BITOR_AGG(value)                               | Equivalent to `BIT_OR(value)`
 | * | BITCOUNT(value)                                | Returns the bitwise COUNT of *value* or NULL if *value* is NULL. *value* must be and integer or binary value.
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 e2ff32a7bc..e6df576b6c 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -15771,6 +15771,39 @@ public class SqlOperatorTest {
         true);
   }
 
+  /**
+   * Test cases for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-3592">[CALCITE-3592]
+   * Implement BITNOT scalar function</a>. */
+  @Test void testBitNotScalarFunc() {
+    final SqlOperatorFixture f = fixture();
+    f.setFor(SqlStdOperatorTable.BITNOT, VmName.EXPAND);
+    f.checkFails("bitnot(^*^)", "Unknown identifier '\\*'", false);
+    f.checkScalar("bitnot(2)", Integer.toString(~2), "INTEGER NOT NULL");
+    f.checkScalar("bitnot(-5)", Integer.toString(~-5), "INTEGER NOT NULL");
+    f.checkScalar("bitnot(CAST(-5 AS TINYINT))", Byte.toString((byte) ~-5), "TINYINT NOT NULL");
+    f.checkScalar("bitnot(CAST(2 AS SMALLINT))", Short.toString((short) ~2), "SMALLINT NOT NULL");
+    f.checkScalar("bitnot(CAST(2 AS INTEGER))", Integer.toString(~2), "INTEGER NOT NULL");
+    f.checkScalar("bitnot(CAST(2 AS BIGINT))", Long.toString(~2), "BIGINT NOT NULL");
+    f.checkFails("^bitnot(2.3)^",
+        "Cannot apply 'BITNOT' to arguments of type '"
+            + "BITNOT\\(<DECIMAL\\(2, 1\\)>\\)'. Supported form\\(s\\): '"
+            + "BITNOT\\(<INTEGER>\\)'\n"
+            + "'BITNOT\\(<BINARY>\\)'",
+        false);
+    f.checkScalar("bitnot(CAST(x'0201' AS BINARY(2)))", "fdfe",
+        "BINARY(2) NOT NULL");
+    f.checkScalar("bitnot(CAST(x'0201' AS VARBINARY(2)))", "fdfe",
+        "VARBINARY(2) NOT NULL");
+    f.checkFails("^bitnot()^",
+        "Invalid number of arguments to function 'BITNOT'. Was expecting 1 arguments",
+        false);
+    f.checkFails("^bitnot(1, 2)^",
+        "Invalid number of arguments to function 'BITNOT'. Was expecting 1 arguments",
+        false);
+    f.checkNull("bitnot(NULL)");
+  }
+
   @Test void testBitAndAggFunc() {
     final SqlOperatorFixture f = fixture();
     f.setFor(SqlLibraryOperators.BITAND_AGG, VmName.EXPAND);