All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.rel.rules.ValuesReduceRule Maven / Gradle / Ivy

There is a newer version: 5.4.0
Show newest version
/*
 * 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 com.hazelcast.com.liance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.com.hazelcast.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 com.hazelcast.org.apache.calcite.rel.rules;

import com.hazelcast.org.apache.calcite.plan.RelOptPredicateList;
import com.hazelcast.org.apache.calcite.plan.RelOptRule;
import com.hazelcast.org.apache.calcite.plan.RelOptRuleCall;
import com.hazelcast.org.apache.calcite.plan.RelOptRuleOperand;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.core.RelFactories;
import com.hazelcast.org.apache.calcite.rel.core.Values;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalFilter;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalProject;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalValues;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rex.RexBuilder;
import com.hazelcast.org.apache.calcite.rex.RexInputRef;
import com.hazelcast.org.apache.calcite.rex.RexLiteral;
import com.hazelcast.org.apache.calcite.rex.RexNode;
import com.hazelcast.org.apache.calcite.rex.RexShuttle;
import com.hazelcast.org.apache.calcite.rex.RexUtil;
import com.hazelcast.org.apache.calcite.tools.RelBuilderFactory;
import com.hazelcast.org.apache.calcite.util.Util;
import com.hazelcast.org.apache.calcite.util.trace.CalciteTrace;

import com.hazelcast.com.google.com.hazelcast.com.on.collect.ImmutableList;

import com.hazelcast.org.slf4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * Planner rule that folds projections and filters into an underlying
 * {@link com.hazelcast.org.apache.calcite.rel.logical.LogicalValues}.
 *
 * 

Returns a simplified {@code Values}, perhaps containing zero tuples * if all rows are filtered away. * *

For example,

* *
select a - b from (values (1, 2), (3, 5), (7, 11)) as t (a, * b) where a + b > 4
* *

becomes

* *
select x from (values (-2), (-4))
* *

Ignores an empty {@code Values}; this is better dealt with by * {@link PruneEmptyRules}. */ public abstract class ValuesReduceRule extends RelOptRule implements TransformationRule { //~ Static fields/initializers --------------------------------------------- private static final Logger LOGGER = CalciteTrace.getPlannerTracer(); /** * Instance of this rule that applies to the pattern * Filter(Values). */ public static final ValuesReduceRule FILTER_INSTANCE = new ValuesReduceRule( operand(LogicalFilter.class, operandJ(LogicalValues.class, null, Values::isNotEmpty, none())), RelFactories.LOGICAL_BUILDER, "ValuesReduceRule(Filter)") { public void onMatch(RelOptRuleCall call) { LogicalFilter filter = call.rel(0); LogicalValues values = call.rel(1); apply(call, null, filter, values); } }; /** * Instance of this rule that applies to the pattern * Project(Values). */ public static final ValuesReduceRule PROJECT_INSTANCE = new ValuesReduceRule( operand(LogicalProject.class, operandJ(LogicalValues.class, null, Values::isNotEmpty, none())), RelFactories.LOGICAL_BUILDER, "ValuesReduceRule(Project)") { public void onMatch(RelOptRuleCall call) { LogicalProject project = call.rel(0); LogicalValues values = call.rel(1); apply(call, project, null, values); } }; /** * Singleton instance of this rule that applies to the pattern * Project(Filter(Values)). */ public static final ValuesReduceRule PROJECT_FILTER_INSTANCE = new ValuesReduceRule( operand(LogicalProject.class, operand(LogicalFilter.class, operandJ(LogicalValues.class, null, Values::isNotEmpty, none()))), RelFactories.LOGICAL_BUILDER, "ValuesReduceRule(Project-Filter)") { public void onMatch(RelOptRuleCall call) { LogicalProject project = call.rel(0); LogicalFilter filter = call.rel(1); LogicalValues values = call.rel(2); apply(call, project, filter, values); } }; //~ Constructors ----------------------------------------------------------- /** * Creates a ValuesReduceRule. * * @param operand Class of rels to which this rule should apply * @param relBuilderFactory Builder for relational expressions * @param desc Description, or null to guess description */ public ValuesReduceRule(RelOptRuleOperand operand, RelBuilderFactory relBuilderFactory, String desc) { super(operand, relBuilderFactory, desc); Util.discard(LOGGER); } //~ Methods ---------------------------------------------------------------- /** * Does the work. * * @param call Rule call * @param project Project, may be null * @param filter Filter, may be null * @param values Values rel to be reduced */ protected void apply(RelOptRuleCall call, LogicalProject project, LogicalFilter filter, LogicalValues values) { assert values != null; assert filter != null || project != null; final RexNode conditionExpr = (filter == null) ? null : filter.getCondition(); final List projectExprs = (project == null) ? null : project.getProjects(); RexBuilder rexBuilder = values.getCluster().getRexBuilder(); // Find reducible expressions. final List reducibleExps = new ArrayList<>(); final MyRexShuttle shuttle = new MyRexShuttle(); for (final List literalList : values.getTuples()) { shuttle.literalList = literalList; if (conditionExpr != null) { RexNode c = conditionExpr.accept(shuttle); reducibleExps.add(c); } if (projectExprs != null) { int k = -1; for (RexNode projectExpr : projectExprs) { ++k; RexNode e = projectExpr.accept(shuttle); if (RexLiteral.isNullLiteral(e)) { e = rexBuilder.makeAbstractCast( project.getRowType().getFieldList().get(k).getType(), e); } reducibleExps.add(e); } } } int fieldsPerRow = ((conditionExpr == null) ? 0 : 1) + ((projectExprs == null) ? 0 : projectExprs.size()); assert fieldsPerRow > 0; assert reducibleExps.size() == (values.getTuples().size() * fieldsPerRow); // Compute the values they reduce to. final RelOptPredicateList predicates = RelOptPredicateList.EMPTY; ReduceExpressionsRule.reduceExpressions(values, reducibleExps, predicates, false, true); int changeCount = 0; final ImmutableList.Builder> tuplesBuilder = ImmutableList.builder(); for (int row = 0; row < values.getTuples().size(); ++row) { int i = 0; if (conditionExpr != null) { final RexNode reducedValue = reducibleExps.get((row * fieldsPerRow) + i); ++i; if (!reducedValue.isAlwaysTrue()) { ++changeCount; continue; } } final ImmutableList valuesList; if (projectExprs != null) { ++changeCount; final ImmutableList.Builder tupleBuilder = ImmutableList.builder(); for (; i < fieldsPerRow; ++i) { final RexNode reducedValue = reducibleExps.get((row * fieldsPerRow) + i); if (reducedValue instanceof RexLiteral) { tupleBuilder.add((RexLiteral) reducedValue); } else if (RexUtil.isNullLiteral(reducedValue, true)) { tupleBuilder.add(rexBuilder.makeNullLiteral(reducedValue.getType())); } else { return; } } valuesList = tupleBuilder.build(); } else { valuesList = values.getTuples().get(row); } tuplesBuilder.add(valuesList); } if (changeCount > 0) { final RelDataType rowType; if (projectExprs != null) { rowType = project.getRowType(); } else { rowType = values.getRowType(); } final RelNode newRel = LogicalValues.create(values.getCluster(), rowType, tuplesBuilder.build()); call.transformTo(newRel); } else { // Filter had no effect, so we can say that Filter(Values) == // Values. call.transformTo(values); } // New plan is absolutely better than old plan. (Moreover, if // changeCount == 0, we've proved that the filter was trivial, and that // can send the volcano planner into a loop; see dtbug 2070.) if (filter != null) { call.getPlanner().prune(filter); } } //~ Inner Classes ---------------------------------------------------------- /** Shuttle that converts inputs to literals. */ private static class MyRexShuttle extends RexShuttle { private List literalList; public RexNode visitInputRef(RexInputRef inputRef) { return literalList.get(inputRef.getIndex()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy