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");
+ }
}