This is an automated email from the ASF dual-hosted git repository.

zhenchen 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 c3d49bd4f8 [CALCITE-7357] Introduce the implementation of rex operator 
IS DISTINCT FROM
c3d49bd4f8 is described below

commit c3d49bd4f8a5d0c56fc19a5d2dd1255486221a28
Author: Zhen Chen <[email protected]>
AuthorDate: Thu Jan 8 06:51:48 2026 +0800

    [CALCITE-7357] Introduce the implementation of rex operator IS DISTINCT FROM
---
 .../calcite/adapter/enumerable/RexImpTable.java    | 59 ++++++++++++++++------
 .../test/enumerable/EnumerableCalcTest.java        | 22 ++++++++
 2 files changed, 66 insertions(+), 15 deletions(-)

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 103e91919f..42afb720fc 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
@@ -429,6 +429,7 @@
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.INITCAP;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.INTERSECTION;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_A_SET;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_DISTINCT_FROM;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_EMPTY;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_FALSE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_JSON_ARRAY;
@@ -1040,6 +1041,7 @@ void populate2() {
       define(IS_FALSE, new IsFalseImplementor());
       define(IS_NOT_FALSE, new IsNotFalseImplementor());
       define(IS_NOT_DISTINCT_FROM, new IsNotDistinctFromImplementor());
+      define(IS_DISTINCT_FROM, new IsDistinctFromImplementor());
 
       // LIKE, ILIKE, RLIKE and SIMILAR
       defineReflective(LIKE, BuiltInMethod.LIKE.method,
@@ -4796,10 +4798,11 @@ private static class IsNullImplementor extends 
AbstractRexCallImplementor {
     }
   }
 
-  /** Implementor for the {@code IS NOT DISTINCT FROM} SQL operator. */
-  private static class IsNotDistinctFromImplementor extends 
AbstractRexCallImplementor {
-    IsNotDistinctFromImplementor() {
-      super("is_not_distinct_from", NullPolicy.NONE, false);
+  /** Base implementation class for the {@code IS DISTINCT FROM}
+   * and {@code IS NOT DISTINCT FROM} operators. */
+  private abstract static class DistinctFromImplementor extends 
AbstractRexCallImplementor {
+    DistinctFromImplementor(String variableName, NullPolicy nullPolicy, 
boolean harmonize) {
+      super(variableName, nullPolicy, harmonize);
     }
 
     @Override public RexToLixTranslator.Result implement(final 
RexToLixTranslator translator,
@@ -4807,17 +4810,7 @@ private static class IsNotDistinctFromImplementor 
extends AbstractRexCallImpleme
       final RexToLixTranslator.Result left = arguments.get(0);
       final RexToLixTranslator.Result right = arguments.get(1);
 
-      // Generated expression:
-      // left IS NULL ?
-      //   (right IS NULL ? TRUE : FALSE) :  -> when left is null
-      //   (right IS NULL ? FALSE :          -> when left is not null
-      //     left.equals(right))             -> when both are not null, 
compare values
-      final Expression valueExpression =
-          Expressions.condition(left.isNullVariable,
-          Expressions.condition(right.isNullVariable, BOXED_TRUE_EXPR, 
BOXED_FALSE_EXPR),
-          Expressions.condition(right.isNullVariable, BOXED_FALSE_EXPR,
-              Expressions.call(BuiltInMethod.OBJECTS_EQUAL.method,
-                  left.valueVariable, right.valueVariable)));
+      final Expression valueExpression = valueExpression(left, right);
 
       BlockBuilder builder = translator.getBlockBuilder();
       final ParameterExpression valueVariable =
@@ -4835,6 +4828,22 @@ private static class IsNotDistinctFromImplementor 
extends AbstractRexCallImpleme
       return new RexToLixTranslator.Result(isNullVariable, valueVariable);
     }
 
+    protected Expression valueExpression(RexToLixTranslator.Result left,
+        RexToLixTranslator.Result right) {
+      // Generated expression:
+      // left IS NULL ?
+      //   (right IS NULL ? TRUE : FALSE) :  -> when left is null
+      //   (right IS NULL ? FALSE :          -> when left is not null
+      //     left.equals(right))             -> when both are not null, 
compare values
+      return Expressions.condition(left.isNullVariable,
+          Expressions.condition(right.isNullVariable, BOXED_TRUE_EXPR, 
BOXED_FALSE_EXPR),
+          Expressions.condition(right.isNullVariable, BOXED_FALSE_EXPR,
+              Expressions.condition(
+                  Expressions.call(BuiltInMethod.OBJECTS_EQUAL.method,
+                      left.valueVariable, right.valueVariable),
+                  BOXED_TRUE_EXPR, BOXED_FALSE_EXPR)));
+    }
+
     @Override Expression implementSafe(final RexToLixTranslator translator,
         final RexCall call, final List<Expression> argValueList) {
       throw new IllegalStateException("This implementSafe should not be 
called,"
@@ -4842,6 +4851,26 @@ private static class IsNotDistinctFromImplementor 
extends AbstractRexCallImpleme
     }
   }
 
+  /** Implementor for the {@code IS NOT DISTINCT FROM} SQL operator. */
+  private static class IsNotDistinctFromImplementor extends 
DistinctFromImplementor {
+    IsNotDistinctFromImplementor() {
+      super("is_not_distinct_from", NullPolicy.NONE, false);
+    }
+  }
+
+  /** Implementor for the {@code IS DISTINCT FROM} SQL operator. */
+  private static class IsDistinctFromImplementor extends 
DistinctFromImplementor {
+    IsDistinctFromImplementor() {
+      super("is_distinct_from", NullPolicy.NONE, false);
+    }
+
+    @Override protected Expression valueExpression(RexToLixTranslator.Result 
left,
+        RexToLixTranslator.Result right) {
+      return Expressions.condition(super.valueExpression(left, right),
+          BOXED_FALSE_EXPR, BOXED_TRUE_EXPR);
+    }
+  }
+
   /** Implementor for the {@code IS TRUE} SQL operator. */
   private static class IsTrueImplementor extends AbstractRexCallImplementor {
     IsTrueImplementor() {
diff --git 
a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCalcTest.java 
b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCalcTest.java
index 708f077662..4b545b677f 100644
--- 
a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCalcTest.java
+++ 
b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCalcTest.java
@@ -129,4 +129,26 @@ private CalciteAssert.AssertQuery checkPosixRegex(
         .planContains("input_value != null && input_value.isEmpty()")
         .returnsUnordered("$f0=false", "$f0=true");
   }
+
+  /** Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-7357";>[CALCITE-7357]
+   * Introduce the implementation of rex operator IS DISTINCT FROM</a>. */
+  @Test public void testIsDistinctFromImplementationDirectly() {
+    CalciteAssert.that()
+        .withSchema("s", new ReflectiveSchema(new HrSchema()))
+        .withRel(
+            builder -> builder
+                .scan("s", "emps")
+                .project(
+                    builder.field("commission"),
+                    builder.call(
+                        SqlStdOperatorTable.IS_DISTINCT_FROM,
+                        builder.field("commission"),
+                        builder.literal(null)))
+                .build())
+        .returnsUnordered(
+            "commission=1000; $f1=true",
+            "commission=250; $f1=true",
+            "commission=500; $f1=true",
+            "commission=null; $f1=false");
+  }
 }

Reply via email to