This is an automated email from the ASF dual-hosted git repository. chunwei 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 ad8cf7e [CALCITE-3845] CASE WHEN expression with nullability CAST is considered as reduced wrongly in ReduceExpressionsRule ad8cf7e is described below commit ad8cf7e0e96137c40103e0e83539b59e43513b17 Author: Chunwei Lei <chunwei.l...@gmail.com> AuthorDate: Fri Mar 6 15:29:27 2020 +0800 [CALCITE-3845] CASE WHEN expression with nullability CAST is considered as reduced wrongly in ReduceExpressionsRule --- .../calcite/rel/rules/ReduceExpressionsRule.java | 7 ++++ .../org/apache/calcite/test/RelOptRulesTest.java | 46 ++++++++++++++++++++++ .../org/apache/calcite/test/RelOptRulesTest.xml | 14 +++++++ 3 files changed, 67 insertions(+) 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 602e955..2fd890d 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 @@ -304,6 +304,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule Lists.newArrayList(project.getProjects()); if (reduceExpressions(project, expList, predicates, false, matchNullability)) { + assert !project.getProjects().equals(expList) + : "Reduced expressions should be different from original expressions"; call.transformTo( call.builder() .push(project.getInput()) @@ -610,6 +612,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule boolean matchNullability) { final RelOptCluster cluster = rel.getCluster(); final RexBuilder rexBuilder = cluster.getRexBuilder(); + final List<RexNode> originExpList = Lists.newArrayList(expList); final RexExecutor executor = Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR); final RexSimplify simplify = @@ -631,6 +634,10 @@ public abstract class ReduceExpressionsRule extends RelOptRule } } + if (reduced && simplified) { + return !originExpList.equals(expList); + } + return reduced || simplified; } 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 728e1fc..2a083f3 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -128,6 +128,7 @@ import org.apache.calcite.rel.rules.UnionToDistinctRule; import org.apache.calcite.rel.rules.ValuesReduceRule; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; +import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexNode; @@ -3480,6 +3481,51 @@ public class RelOptRulesTest extends RelOptTestBase { sql(sql).with(program).check(); } + @Test public void testReduceCaseWhenWithCast() { + final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build()); + final RexBuilder rexBuilder = relBuilder.getRexBuilder(); + final RelDataType type = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BIGINT); + + RelNode left = relBuilder + .values(new String[]{"x", "y"}, 1, 2).build(); + RexNode ref = rexBuilder.makeInputRef(left, 0); + RexNode literal1 = rexBuilder.makeLiteral(1, type, false); + RexNode literal2 = rexBuilder.makeLiteral(2, type, false); + RexNode literal3 = rexBuilder.makeLiteral(3, type, false); + + // CASE WHEN x % 2 = 1 THEN x < 2 + // WHEN x % 3 = 2 THEN x < 1 + // ELSE x < 3 + final RexNode caseRexNode = rexBuilder.makeCall(SqlStdOperatorTable.CASE, + rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, + rexBuilder.makeCall(SqlStdOperatorTable.MOD, ref, literal2), literal1), + rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal2), + rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, + rexBuilder.makeCall(SqlStdOperatorTable.MOD, ref, literal3), literal2), + rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal1), + rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal3)); + + final RexNode castNode = rexBuilder.makeCast(rexBuilder.getTypeFactory(). + createTypeWithNullability(caseRexNode.getType(), true), caseRexNode); + final RelNode root = relBuilder + .push(left) + .project(castNode) + .build(); + + HepProgramBuilder builder = new HepProgramBuilder(); + builder.addRuleClass(ReduceExpressionsRule.class); + + HepPlanner hepPlanner = new HepPlanner(builder.build()); + hepPlanner.addRule(ReduceExpressionsRule.PROJECT_INSTANCE); + hepPlanner.setRoot(root); + + RelNode output = hepPlanner.findBestExp(); + final String planAfter = NL + RelOptUtil.toString(output); + final DiffRepository diffRepos = getDiffRepos(); + diffRepos.assertEquals("planAfter", "${planAfter}", planAfter); + SqlToRelTestBase.assertValid(output); + } + private void basePushAggThroughUnion() throws Exception { HepProgram program = new HepProgramBuilder() .addRuleInstance(ProjectSetOpTransposeRule.INSTANCE) 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 bd22930..9d04144 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -8067,6 +8067,20 @@ LogicalTableModify(table=[[CATALOG, SALES, DEPT]], operation=[INSERT], flattened ]]> </Resource> </TestCase> + <TestCase name="testReduceCaseWhenWithCast"> + <Resource name="planBefore"> + <![CDATA[ +LogicalProject($f0=[CAST(CASE(=(MOD($0, 2:BIGINT), 1), <($0, 2:BIGINT), =(MOD($0, 3:BIGINT), 2), <($0, 1:BIGINT), <($0, 3:BIGINT))):BOOLEAN]) + LogicalValues(tuples=[[{ 1, 2 }]]) +]]> + </Resource> + <Resource name="planAfter"> + <![CDATA[ +LogicalProject($f0=[CAST(CASE(=(MOD($0, 2:BIGINT), 1), <($0, 2:BIGINT), =(MOD($0, 3:BIGINT), 2), <($0, 1:BIGINT), <($0, 3:BIGINT))):BOOLEAN]) + LogicalValues(tuples=[[{ 1, 2 }]]) +]]> + </Resource> + </TestCase> <TestCase name="testReduceConstants3"> <Resource name="sql"> <![CDATA[select e.mgr is not distinct from f.mgr from emp e join emp f on (e.mgr=f.mgr) where e.mgr is null]]>