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

kgyrtkirk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new cecfece  [CALCITE-3887] Filter and Join conditions may not need to 
retain nullability during simplifications
cecfece is described below

commit cecfece459b0f5f155c0498811985e083813aa20
Author: Zoltan Haindrich <[email protected]>
AuthorDate: Mon Mar 23 08:50:28 2020 +0000

    [CALCITE-3887] Filter and Join conditions may not need to retain 
nullability during simplifications
    
    In some cases a combination of rule transformations could lead to new 
filter/join conditions which are not necessarily nullable anymore.
    However the nullable type was retained - with the insertion of a CAST.
---
 .../calcite/rel/rules/ReduceExpressionsRule.java   |  4 +-
 .../java/org/apache/calcite/rex/RexSimplify.java   |  4 ++
 .../org/apache/calcite/test/RelBuilderTest.java    | 37 +++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.java   | 61 ++++++++++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 12 +++++
 5 files changed, 116 insertions(+), 2 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 7b8dcb8..ca5c0be 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -111,7 +111,7 @@ public abstract class ReduceExpressionsRule extends 
RelOptRule
    * {@link org.apache.calcite.rel.logical.LogicalFilter}.
    */
   public static final ReduceExpressionsRule FILTER_INSTANCE =
-      new FilterReduceExpressionsRule(LogicalFilter.class, true,
+      new FilterReduceExpressionsRule(LogicalFilter.class, false,
           RelFactories.LOGICAL_BUILDER);
 
   /**
@@ -127,7 +127,7 @@ public abstract class ReduceExpressionsRule extends 
RelOptRule
    * {@link org.apache.calcite.rel.core.Join}.
    */
   public static final ReduceExpressionsRule JOIN_INSTANCE =
-      new JoinReduceExpressionsRule(Join.class, true,
+      new JoinReduceExpressionsRule(Join.class, false,
           RelFactories.LOGICAL_BUILDER);
 
   /**
diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java 
b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
index c8efd75..41eceb2 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -175,6 +175,10 @@ public class RexSimplify {
     if (e2.getType() == e.getType()) {
       return e2;
     }
+    if (!matchNullability
+        && SqlTypeUtil.equalSansNullability(rexBuilder.typeFactory, 
e2.getType(), e.getType())) {
+      return e2;
+    }
     final RexNode e3 = rexBuilder.makeCast(e.getType(), e2, matchNullability);
     if (e3.equals(e)) {
       return e;
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java 
b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index cbdaecb..cee5808 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -1956,6 +1956,27 @@ public class RelBuilderTest {
     assertThat(root, hasTree(expected));
   }
 
+  /** Checks if simplification is run in {@link 
org.apache.calcite.rex.RexUnknownAs#FALSE} mode for join conditions */
+  @Test void testJoinConditionSimplification() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .scan("DEPT")
+            .join(JoinRelType.INNER,
+                builder.or(builder.literal(null),
+                    builder.and(
+                        builder.equals(builder.field(2, 0, "DEPTNO"), 
builder.literal(1)),
+                        builder.equals(builder.field(2, 0, "DEPTNO"), 
builder.literal(2)),
+                        builder.equals(builder.field(2, 1, "DEPTNO"),
+                            builder.field(2, 0, "DEPTNO")))))
+            .build();
+    assertThat(
+        root, hasTree(
+        "LogicalJoin(condition=[false], joinType=[inner])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n"));
+  }
+
   @Test void testJoinCartesian() {
     // Equivalent SQL:
     //   SELECT * emp CROSS JOIN dept
@@ -3156,6 +3177,22 @@ public class RelBuilderTest {
     assertThat(root, hasTree("LogicalTableScan(table=[[scott, EMP]])\n"));
   }
 
+  /** Checks if simplification is run in {@link 
org.apache.calcite.rex.RexUnknownAs#FALSE} mode for filter conditions */
+  @Test void testFilterSimplification() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.or(
+                     builder.literal(null),
+                     builder.and(
+                         builder.equals(builder.field(2), builder.literal(1)),
+                         builder.equals(builder.field(2), builder.literal(2))
+             )))
+            .build();
+    assertThat(root, hasTree("LogicalValues(tuples=[[]])\n"));
+  }
+
   @Test void testRelBuilderToString() {
     final RelBuilder builder = RelBuilder.create(config().build());
     builder.scan("EMP");
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java 
b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 5197126..468f509 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -557,6 +557,67 @@ class RelOptRulesTest extends RelOptTestBase {
     SqlToRelTestBase.assertValid(output);
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-3887";>[CALCITE-3887]
+   * Filter and Join conditions may not need to retain nullability during 
simplifications</a>. */
+  @Test void testPushSemiJoinConditions() {
+    final RelBuilder relBuilder = 
RelBuilder.create(RelBuilderTest.config().build());
+    RelNode left = relBuilder.scan("EMP")
+        .project(
+            relBuilder.field("DEPTNO"),
+            relBuilder.field("ENAME"))
+        .build();
+    RelNode right = relBuilder.scan("DEPT")
+        .project(
+            relBuilder.field("DEPTNO"),
+            relBuilder.field("DNAME"))
+        .build();
+
+    relBuilder.push(left).push(right);
+
+    RexInputRef ref1 = relBuilder.field(2, 0, "DEPTNO");
+    RexInputRef ref2 = relBuilder.field(2, 1, "DEPTNO");
+    RexInputRef ref3 = relBuilder.field(2, 0, "ENAME");
+    RexInputRef ref4 = relBuilder.field(2, 1, "DNAME");
+
+    // ref1 IS NOT DISTINCT FROM ref2
+    RexCall cond1 = (RexCall) relBuilder.call(
+        SqlStdOperatorTable.OR,
+        relBuilder.call(SqlStdOperatorTable.EQUALS, ref1, ref2),
+        relBuilder.call(SqlStdOperatorTable.AND,
+            relBuilder.call(SqlStdOperatorTable.IS_NULL, ref1),
+            relBuilder.call(SqlStdOperatorTable.IS_NULL, ref2)));
+
+    // ref3 IS NOT DISTINCT FROM ref4
+    RexCall cond2 = (RexCall) relBuilder.call(
+        SqlStdOperatorTable.OR,
+        relBuilder.call(SqlStdOperatorTable.EQUALS, ref3, ref4),
+        relBuilder.call(SqlStdOperatorTable.AND,
+            relBuilder.call(SqlStdOperatorTable.IS_NULL, ref3),
+            relBuilder.call(SqlStdOperatorTable.IS_NULL, ref4)));
+
+    RexNode cond = relBuilder.call(SqlStdOperatorTable.AND, cond1, cond2);
+    RelNode relNode = relBuilder.semiJoin(cond)
+        .project(relBuilder.field(0))
+        .build();
+
+    HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(JoinPushExpressionsRule.INSTANCE)
+        .addRuleInstance(SemiJoinProjectTransposeRule.INSTANCE)
+        .addRuleInstance(ReduceExpressionsRule.JOIN_INSTANCE)
+        .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
+        .build();
+
+    HepPlanner hepPlanner = new HepPlanner(program);
+    hepPlanner.setRoot(relNode);
+    RelNode output = hepPlanner.findBestExp();
+
+    final String planAfter = NL + RelOptUtil.toString(output);
+    final DiffRepository diffRepos = getDiffRepos();
+    diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+    SqlToRelTestBase.assertValid(output);
+  }
+
   @Test void testFullOuterJoinSimplificationToLeftOuter() {
     final String sql = "select 1 from sales.dept d full outer join sales.emp 
e\n"
         + "on d.deptno = e.deptno\n"
diff --git 
a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml 
b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index a99eaf2..4b6d286 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -6773,6 +6773,18 @@ LogicalProject(EMPNO=[$0])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testPushSemiJoinConditions">
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(DEPTNO=[$0])
+  LogicalProject(DEPTNO=[$7], ENAME=[$1])
+    LogicalJoin(condition=[AND(IS NOT DISTINCT FROM($7, $8), IS NOT DISTINCT 
FROM($1, $9))], joinType=[semi])
+      LogicalTableScan(table=[[scott, EMP]])
+      LogicalProject(DEPTNO=[$0], DNAME=[$1])
+        LogicalTableScan(table=[[scott, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testSemiJoinRuleExists">
         <Resource name="sql">
             <![CDATA[select * from dept where exists (

Reply via email to