chunweilei commented on code in PR #2800: URL: https://github.com/apache/calcite/pull/2800#discussion_r869794897
########## core/src/main/java/org/apache/calcite/rel/rules/JoinDeriveIsNotNullFilterRule.java: ########## @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.rel.rules; + +import org.apache.calcite.plan.RelOptPredicateList; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelRule; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Join; +import org.apache.calcite.rel.core.JoinInfo; +import org.apache.calcite.rel.core.JoinRelType; +import org.apache.calcite.rel.logical.LogicalJoin; +import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.apache.calcite.rex.RexBuilder; +import org.apache.calcite.rex.RexExecutor; +import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexSimplify; +import org.apache.calcite.rex.RexUtil; +import org.apache.calcite.sql.fun.SqlStdOperatorTable; +import org.apache.calcite.tools.RelBuilder; +import org.apache.calcite.util.ImmutableIntList; +import org.apache.calcite.util.Util; + +import org.immutables.value.Value; + +import java.util.ArrayList; +import java.util.List; + +/** + * Planner rule that derives is not null filter from inner join. + */ [email protected] +public class JoinDeriveIsNotNullFilterRule + extends RelRule<JoinDeriveIsNotNullFilterRule.Config> implements TransformationRule { + + public JoinDeriveIsNotNullFilterRule(Config config) { + super(config); + } + + @Override public void onMatch(RelOptRuleCall call) { + final Join join = call.rel(0); + final RelBuilder relBuilder = call.builder(); + final RelMetadataQuery mq = call.getMetadataQuery(); + JoinInfo joinInfo = join.analyzeCondition(); + RelNode newLeftNode = createIsNotNullFilter(join.getLeft(), joinInfo.leftKeys, + relBuilder, mq); + RelNode newRightNode = createIsNotNullFilter(join.getRight(), joinInfo.rightKeys, + relBuilder, mq); + + if (newLeftNode != join.getLeft() || newRightNode != join.getRight()) { + List<RelNode> inputs = new ArrayList<>(); + inputs.add(newLeftNode); + inputs.add(newRightNode); + RelNode newJoin = join.copy(join.getTraitSet(), inputs); + call.transformTo(newJoin); + } + } + + private RelNode createIsNotNullFilter(RelNode input, ImmutableIntList keys, + RelBuilder relBuilder, RelMetadataQuery mq) { + final RelOptPredicateList relOptPredicateList = mq.getPulledUpPredicates(input); + final RexExecutor executor = + Util.first(input.getCluster().getPlanner().getExecutor(), RexUtil.EXECUTOR); + final RexBuilder rexBuilder = input.getCluster().getRexBuilder(); + final RexSimplify simplify = new RexSimplify(rexBuilder, relOptPredicateList, executor); + List<RexNode> nodes = new ArrayList<>(); + keys.forEach(i -> { + final RexNode expr = relBuilder + .call(SqlStdOperatorTable.IS_NOT_NULL, rexBuilder.makeInputRef(input, i)); + RexNode simplified = simplify.simplify(expr); + if (!simplified.isAlwaysTrue()) { + nodes.add(expr); + } + }); Review Comment: I prefer the current implementation~~. ########## core/src/main/java/org/apache/calcite/rel/rules/JoinDeriveIsNotNullFilterRule.java: ########## @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.rel.rules; + +import org.apache.calcite.plan.RelOptPredicateList; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelRule; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Join; +import org.apache.calcite.rel.core.JoinInfo; +import org.apache.calcite.rel.core.JoinRelType; +import org.apache.calcite.rel.logical.LogicalJoin; +import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.apache.calcite.rex.RexBuilder; +import org.apache.calcite.rex.RexExecutor; +import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexSimplify; +import org.apache.calcite.rex.RexUtil; +import org.apache.calcite.sql.fun.SqlStdOperatorTable; +import org.apache.calcite.tools.RelBuilder; +import org.apache.calcite.util.ImmutableIntList; +import org.apache.calcite.util.Util; + +import org.immutables.value.Value; + +import java.util.ArrayList; +import java.util.List; + +/** + * Planner rule that derives is not null filter from inner join. + */ [email protected] +public class JoinDeriveIsNotNullFilterRule + extends RelRule<JoinDeriveIsNotNullFilterRule.Config> implements TransformationRule { + + public JoinDeriveIsNotNullFilterRule(Config config) { + super(config); + } + + @Override public void onMatch(RelOptRuleCall call) { + final Join join = call.rel(0); + final RelBuilder relBuilder = call.builder(); + final RelMetadataQuery mq = call.getMetadataQuery(); + JoinInfo joinInfo = join.analyzeCondition(); + RelNode newLeftNode = createIsNotNullFilter(join.getLeft(), joinInfo.leftKeys, + relBuilder, mq); + RelNode newRightNode = createIsNotNullFilter(join.getRight(), joinInfo.rightKeys, + relBuilder, mq); + + if (newLeftNode != join.getLeft() || newRightNode != join.getRight()) { + List<RelNode> inputs = new ArrayList<>(); + inputs.add(newLeftNode); + inputs.add(newRightNode); + RelNode newJoin = join.copy(join.getTraitSet(), inputs); + call.transformTo(newJoin); + } + } + + private RelNode createIsNotNullFilter(RelNode input, ImmutableIntList keys, Review Comment: Simplify is used to avoid creating redundant IS NOT NULL filter. Otherwise, it would create a new IS NOT NULL filter every time the rule applies. ########## core/src/main/java/org/apache/calcite/rel/rules/JoinDeriveIsNotNullFilterRule.java: ########## @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.rel.rules; + +import org.apache.calcite.plan.RelOptPredicateList; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelRule; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Join; +import org.apache.calcite.rel.core.JoinInfo; +import org.apache.calcite.rel.core.JoinRelType; +import org.apache.calcite.rel.logical.LogicalJoin; +import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.apache.calcite.rex.RexBuilder; +import org.apache.calcite.rex.RexExecutor; +import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexSimplify; +import org.apache.calcite.rex.RexUtil; +import org.apache.calcite.sql.fun.SqlStdOperatorTable; +import org.apache.calcite.tools.RelBuilder; +import org.apache.calcite.util.ImmutableIntList; +import org.apache.calcite.util.Util; + +import org.immutables.value.Value; + +import java.util.ArrayList; +import java.util.List; + +/** + * Planner rule that derives is not null filter from inner join. + */ [email protected] +public class JoinDeriveIsNotNullFilterRule + extends RelRule<JoinDeriveIsNotNullFilterRule.Config> implements TransformationRule { + + public JoinDeriveIsNotNullFilterRule(Config config) { + super(config); + } + + @Override public void onMatch(RelOptRuleCall call) { + final Join join = call.rel(0); + final RelBuilder relBuilder = call.builder(); + final RelMetadataQuery mq = call.getMetadataQuery(); + JoinInfo joinInfo = join.analyzeCondition(); + RelNode newLeftNode = createIsNotNullFilter(join.getLeft(), joinInfo.leftKeys, Review Comment: Nice catch. ########## core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java: ########## @@ -411,6 +411,37 @@ private static boolean skipItem(RexNode expr) { sql(sql).withRule(CoreRules.JOIN_ADD_REDUNDANT_SEMI_JOIN).check(); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-3890">[CALCITE-3890] + * Derive IS NOT NULL filter from inner join</a>. */ + @Test void testJoinDeriveIsNotNullFilterRule1() { + final String sql = "select t1.deptno from emp t1 inner join emp t2 on t1.mgr = t2.mgr"; + sql(sql).withRule(CoreRules.JOIN_DERIVE_IS_NOT_NULL_FILTER_RULE).check(); + } + + /** As {@link #testJoinDeriveIsNotNullFilterRule1()}; + * should create is not null filter in the right input of join. */ + @Test void testJoinDeriveIsNotNullFilterRule2() { + final String sql = "select t1.deptno from (select * from emp where mgr is not null) t1 " + + "join emp t2 on t1.mgr = t2.mgr"; + sql(sql).withRule(CoreRules.JOIN_DERIVE_IS_NOT_NULL_FILTER_RULE).check(); + } + + /** As {@link #testJoinDeriveIsNotNullFilterRule1()}; + * should not create is not null filter in both sides since it is full join. */ + @Test void testJoinDeriveIsNotNullFilterRule3() { Review Comment: That's true. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
