com.hazelcast.org.apache.calcite.plan.hep.HepProgramBuilder Maven / Gradle / Ivy
/*
* 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 com.hazelcast.org.apache.calcite.plan.hep;
import com.hazelcast.org.apache.calcite.plan.CommonRelSubExprRule;
import com.hazelcast.org.apache.calcite.plan.RelOptPlanner;
import com.hazelcast.org.apache.calcite.plan.RelOptRule;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* HepProgramBuilder creates instances of {@link HepProgram}.
*/
public class HepProgramBuilder {
//~ Instance fields --------------------------------------------------------
private final List instructions = new ArrayList<>();
private HepInstruction.BeginGroup group;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new HepProgramBuilder with an initially empty program. The
* program under construction has an initial match order of
* {@link HepMatchOrder#DEPTH_FIRST}, and an initial match limit of
* {@link HepProgram#MATCH_UNTIL_FIXPOINT}.
*/
public HepProgramBuilder() {
}
//~ Methods ----------------------------------------------------------------
private void clear() {
instructions.clear();
group = null;
}
/**
* Adds an instruction to attempt to match any rules of a given class. The
* order in which the rules within a class will be attempted is arbitrary,
* so if more control is needed, use addRuleInstance instead.
*
* Note that when this method is used, it is also necessary to add the
* actual rule objects of interest to the planner via
* {@link RelOptPlanner#addRule}. If the planner does not have any
* rules of the given class, this instruction is a nop.
*
*
TODO: support classification via rule annotations.
*
* @param ruleClass class of rules to fire, e.g. ConverterRule.class
*/
public HepProgramBuilder addRuleClass(
Class ruleClass) {
HepInstruction.RuleClass instruction =
new HepInstruction.RuleClass();
instruction.ruleClass = ruleClass;
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to attempt to match any rules in a given collection.
* The order in which the rules within a collection will be attempted is
* arbitrary, so if more control is needed, use addRuleInstance instead. The
* collection can be "live" in the sense that not all rule instances need to
* have been added to it at the time this method is called. The collection
* contents are reevaluated for each execution of the program.
*
* Note that when this method is used, it is NOT necessary to add the
* rules to the planner via {@link RelOptPlanner#addRule}; the instances
* supplied here will be used. However, adding the rules to the planner
* redundantly is good form since other planners may require it.
*
* @param rules collection of rules to fire
*/
public HepProgramBuilder addRuleCollection(Collection rules) {
HepInstruction.RuleCollection instruction =
new HepInstruction.RuleCollection();
instruction.rules = rules;
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to attempt to match a specific rule object.
*
* Note that when this method is used, it is NOT necessary to add the
* rule to the planner via {@link RelOptPlanner#addRule}; the instance
* supplied here will be used. However, adding the rule to the planner
* redundantly is good form since other planners may require it.
*
* @param rule rule to fire
*/
public HepProgramBuilder addRuleInstance(RelOptRule rule) {
HepInstruction.RuleInstance instruction =
new HepInstruction.RuleInstance();
instruction.rule = rule;
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to attempt to match a specific rule identified by its
* unique description.
*
*
Note that when this method is used, it is necessary to also add the
* rule object of interest to the planner via {@link RelOptPlanner#addRule}.
* This allows for some decoupling between optimizers and plugins: the
* optimizer only knows about rule descriptions, while the plugins supply
* the actual instances. If the planner does not have a rule matching the
* description, this instruction is a nop.
*
* @param ruleDescription description of rule to fire
*/
public HepProgramBuilder addRuleByDescription(String ruleDescription) {
HepInstruction.RuleInstance instruction =
new HepInstruction.RuleInstance();
instruction.ruleDescription = ruleDescription;
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to begin a group of rules. All subsequent rules added
* (until the next endRuleGroup) will be collected into the group rather
* than firing individually. After addGroupBegin has been called, only
* addRuleXXX methods may be called until the next addGroupEnd.
*/
public HepProgramBuilder addGroupBegin() {
assert group == null;
HepInstruction.BeginGroup instruction = new HepInstruction.BeginGroup();
instructions.add(instruction);
group = instruction;
return this;
}
/**
* Adds an instruction to end a group of rules, firing the group
* collectively. The order in which the rules within a group will be
* attempted is arbitrary. Match order and limit applies to the group as a
* whole.
*/
public HepProgramBuilder addGroupEnd() {
assert group != null;
HepInstruction.EndGroup instruction = new HepInstruction.EndGroup();
instructions.add(instruction);
group.endGroup = instruction;
group = null;
return this;
}
/**
* Adds an instruction to attempt to match instances of
* {@link com.hazelcast.org.apache.calcite.rel.convert.ConverterRule},
* but only where a conversion is actually required.
*
* @param guaranteed if true, use only guaranteed converters; if false, use
* only non-guaranteed converters
*/
public HepProgramBuilder addConverters(boolean guaranteed) {
assert group == null;
HepInstruction.ConverterRules instruction =
new HepInstruction.ConverterRules();
instruction.guaranteed = guaranteed;
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to attempt to match instances of
* {@link CommonRelSubExprRule}, but only in cases where vertices have more
* than one parent.
*/
public HepProgramBuilder addCommonRelSubExprInstruction() {
assert group == null;
HepInstruction.CommonRelSubExprRules instruction =
new HepInstruction.CommonRelSubExprRules();
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to change the order of pattern matching for
* subsequent instructions. The new order will take effect for the rest of
* the program (not counting subprograms) or until another match order
* instruction is encountered.
*
* @param order new match direction to set
*/
public HepProgramBuilder addMatchOrder(HepMatchOrder order) {
assert group == null;
HepInstruction.MatchOrder instruction = new HepInstruction.MatchOrder();
instruction.order = order;
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to limit the number of pattern matches for subsequent
* instructions. The limit will take effect for the rest of the program (not
* counting subprograms) or until another limit instruction is encountered.
*
* @param limit limit to set; use {@link HepProgram#MATCH_UNTIL_FIXPOINT} to
* remove limit
*/
public HepProgramBuilder addMatchLimit(int limit) {
assert group == null;
HepInstruction.MatchLimit instruction = new HepInstruction.MatchLimit();
instruction.limit = limit;
instructions.add(instruction);
return this;
}
/**
* Adds an instruction to execute a subprogram. Note that this is different
* from adding the instructions from the subprogram individually. When added
* as a subprogram, the sequence will execute repeatedly until a fixpoint is
* reached, whereas when the instructions are added individually, the
* sequence will only execute once (with a separate fixpoint for each
* instruction).
*
*
The subprogram has its own state for match order and limit
* (initialized to the defaults every time the subprogram is executed) and
* any changes it makes to those settings do not affect the parent program.
*
* @param program subprogram to execute
*/
public HepProgramBuilder addSubprogram(HepProgram program) {
assert group == null;
HepInstruction.Subprogram instruction = new HepInstruction.Subprogram();
instruction.subprogram = program;
instructions.add(instruction);
return this;
}
/**
* Returns the constructed program, clearing the state of this program
* builder as a side-effect.
*
* @return immutable program
*/
public HepProgram build() {
assert group == null;
HepProgram program = new HepProgram(instructions);
clear();
return program;
}
}