[CALCITE-978] Enable customizing constant folding rule behavior when a Filter simplifies to false (Jason Altekruse)
For static schema systems, a Filter that is always false or null can be replaced by a Values operator that produces no rows, as the schema information can just be taken from the input Rel. In dynamic schema environments, the filter might have an unknown input type, in these cases they must define a system specific alternative to a Values operator, such as inserting a Limit 0 instead of a Filter on top of the original input. This change enables this behavior to be customized by a subclass of the constant reduction rules. Close apache/calcite#183 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/898fdfc2 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/898fdfc2 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/898fdfc2 Branch: refs/heads/branch-1.6 Commit: 898fdfc2720770ec4752fb702ce0aae1521aa07d Parents: ee283ca Author: Jason Altekruse <[email protected]> Authored: Fri Apr 10 15:39:54 2015 -0700 Committer: Julian Hyde <[email protected]> Committed: Thu Jan 14 13:52:01 2016 -0800 ---------------------------------------------------------------------- .../rel/rules/ReduceExpressionsRule.java | 51 ++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/898fdfc2/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java ---------------------------------------------------------------------- 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 3fce8a6..1036ea4 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 @@ -55,6 +55,7 @@ import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.fun.SqlRowOperator; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.tools.RelBuilder; import org.apache.calcite.tools.RelBuilderFactory; import org.apache.calcite.util.Pair; import org.apache.calcite.util.Stacks; @@ -160,7 +161,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule { filter.getInput()); } else if (newConditionExp instanceof RexLiteral || RexUtil.isNullLiteral(newConditionExp, true)) { - call.transformTo(call.builder().values(filter.getRowType()).build()); + call.transformTo(createEmptyRelOrEquivalent(call, filter)); } else if (reduced) { call.transformTo(call.builder(). push(filter.getInput()).filter(expList.get(0)).build()); @@ -182,6 +183,28 @@ public abstract class ReduceExpressionsRule extends RelOptRule { call.getPlanner().setImportance(filter, 0.0); } + /** + * For static schema systems, a filter that is always false or null can be + * replaced by a values operator that produces no rows, as the schema + * information can just be taken from the input Rel. In dynamic schema + * environments, the filter might have an unknown input type, in these cases + * they must define a system specific alternative to a Values operator, such + * as inserting a limit 0 instead of a filter on top of the original input. + * + * <p>The default implementation of this method is to call + * {@link RelBuilder#empty}, which for the static schema will be optimized + * to an empty + * {@link org.apache.calcite.rel.core.Values}. + * + * @param input rel to replace, assumes caller has already determined + * equivalence to Values operation for 0 records or a + * false filter. + * @return equivalent but less expensive replacement rel + */ + protected RelNode createEmptyRelOrEquivalent(RelOptRuleCall call, Filter input) { + return call.builder().push(input).empty().build(); + } + private void reduceNotNullableFilter( RelOptRuleCall call, Filter filter, @@ -212,7 +235,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule { if (alwaysTrue) { call.transformTo(filter.getInput()); } else { - call.transformTo(call.builder().values(filter.getRowType()).build()); + call.transformTo(createEmptyRelOrEquivalent(call, filter)); } } } @@ -343,7 +366,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule { || RexUtil.isNullLiteral(newConditionExp, true)) { // condition is always NULL or FALSE - replace calc // with empty - call.transformTo(call.builder().values(calc.getRowType()).build()); + call.transformTo(createEmptyRelOrEquivalent(call, calc)); return; } else { builder.addCondition(list.get(conditionIndex)); @@ -363,6 +386,28 @@ public abstract class ReduceExpressionsRule extends RelOptRule { call.getPlanner().setImportance(calc, 0.0); } } + + /** + * For static schema systems, a filter that is always false or null can be + * replaced by a values operator that produces no rows, as the schema + * information can just be taken from the input Rel. In dynamic schema + * environments, the filter might have an unknown input type, in these cases + * they must define a system specific alternative to a Values operator, such + * as inserting a limit 0 instead of a filter on top of the original input. + * + * <p>The default implementation of this method is to call + * {@link RelBuilder#empty}, which for the static schema will be optimized + * to an empty + * {@link org.apache.calcite.rel.core.Values}. + * + * @param input rel to replace, assumes caller has already determined + * equivalence to Values operation for 0 records or a + * false filter. + * @return equivalent but less expensive replacement rel + */ + protected RelNode createEmptyRelOrEquivalent(RelOptRuleCall call, Calc input) { + return call.builder().push(input).empty().build(); + } } //~ Constructors -----------------------------------------------------------
