/* * 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.hadoop.hive.ql.optimizer.calcite.rules; import java.math.BigDecimal; import org.apache.calcite.plan.RelOptRule; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; import org.apache.hadoop.hive.ql.optimizer.calcite.HiveCalciteUtil; import org.apache.hadoop.hive.ql.optimizer.calcite.reloperators.HiveSortLimit; /** * This rule will merge two HiveSortLimit operators. * * It is applied when the top match is a pure limit operation (no sorting). * * If the bottom operator is not synthetic and does not contain a limit, * we currently bail out. Thus, we avoid a lot of unnecessary limit operations * in the middle of the execution plan that could create performance regressions. */ public class HiveSortMergeRule extends RelOptRule { public static final HiveSortMergeRule INSTANCE = new HiveSortMergeRule(); //~ Constructors ----------------------------------------------------------- /** * Creates a HiveSortProjectTransposeRule. */ private HiveSortMergeRule() { super( operand( HiveSortLimit.class, operand(HiveSortLimit.class, any()))); } //~ Methods ---------------------------------------------------------------- @Override public boolean matches(RelOptRuleCall call) { final HiveSortLimit topSortLimit = call.rel(0); final HiveSortLimit bottomSortLimit = call.rel(1); // If top operator is not a pure limit, we bail out if (!HiveCalciteUtil.pureLimitRelNode(topSortLimit)) { return false; } // If the bottom operator is not synthetic and it does not contain a limit, // we will bail out; we do not want to end up with limits all over the tree if (topSortLimit.isRuleCreated() && !bottomSortLimit.isRuleCreated() && !HiveCalciteUtil.limitRelNode(bottomSortLimit)) { return false; } return true; } // implement RelOptRule public void onMatch(RelOptRuleCall call) { final HiveSortLimit topSortLimit = call.rel(0); final HiveSortLimit bottomSortLimit = call.rel(1); final RexNode newOffset; final RexNode newLimit; if (HiveCalciteUtil.limitRelNode(bottomSortLimit)) { final RexBuilder rexBuilder = topSortLimit.getCluster().getRexBuilder(); int topOffset = topSortLimit.offset == null ? 0 : RexLiteral.intValue(topSortLimit.offset); int topLimit = RexLiteral.intValue(topSortLimit.fetch); int bottomOffset = bottomSortLimit.offset == null ? 0 : RexLiteral.intValue(bottomSortLimit.offset); int bottomLimit = RexLiteral.intValue(bottomSortLimit.fetch); // Three different cases if (topOffset + topLimit <= bottomLimit) { // 1. Fully contained // topOffset + topLimit <= bottomLimit newOffset = bottomOffset + topOffset == 0 ? null : rexBuilder.makeExactLiteral(BigDecimal.valueOf(bottomOffset + topOffset)); newLimit = topSortLimit.fetch; } else if (topOffset < bottomLimit) { // 2. Partially contained // topOffset + topLimit > bottomLimit && topOffset < bottomLimit newOffset = bottomOffset + topOffset == 0 ? null : rexBuilder.makeExactLiteral(BigDecimal.valueOf(bottomOffset + topOffset)); newLimit = rexBuilder.makeExactLiteral(BigDecimal.valueOf(bottomLimit - topOffset)); } else { // 3. Outside // we need to create a new limit 0 newOffset = null; newLimit = rexBuilder.makeExactLiteral(BigDecimal.valueOf(0)); } } else { // Bottom operator does not contain offset/fetch newOffset = topSortLimit.offset; newLimit = topSortLimit.fetch; } final HiveSortLimit newSort = bottomSortLimit.copy(bottomSortLimit.getTraitSet(), bottomSortLimit.getInput(), bottomSortLimit.collation, newOffset, newLimit); call.transformTo(newSort); } }