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 (