/*
* 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.eigenbase.relopt;
import java.util.*;
import org.eigenbase.rel.RelNode;
import org.eigenbase.util.*;
import com.google.common.collect.ImmutableList;
/**
* A <code>RelOptRuleOperand</code> determines whether a {@link
* org.eigenbase.relopt.RelOptRule} can be applied to a particular expression.
*
* <p>For example, the rule to pull a filter up from the left side of a join
* takes operands: <code>(Join (Filter) (Any))</code>.</p>
*
* <p>Note that <code>children</code> means different things if it is empty or
* it is <code>null</code>: <code>(Join (Filter <b>()</b>) (Any))</code> means
* that, to match the rule, <code>Filter</code> must have no operands.</p>
*/
public class RelOptRuleOperand {
//~ Instance fields --------------------------------------------------------
private RelOptRuleOperand parent;
private RelOptRule rule;
// REVIEW jvs 29-Aug-2004: some of these are Volcano-specific and should be
// factored out
public int[] solveOrder;
public int ordinalInParent;
public int ordinalInRule;
private final RelTrait trait;
private final Class<? extends RelNode> clazz;
private final ImmutableList<RelOptRuleOperand> children;
/**
* Whether child operands can be matched in any order.
*/
public final RelOptRuleOperandChildPolicy childPolicy;
//~ Constructors -----------------------------------------------------------
/**
* Creates an operand.
*
* <p>The {@code childOperands} argument is often populated by calling one
* of the following methods:
* {@link RelOptRule#some},
* {@link RelOptRule#none()},
* {@link RelOptRule#any},
* {@link RelOptRule#unordered},
* See {@link org.eigenbase.relopt.RelOptRuleOperandChildren} for more
* details.</p>
*
* @param clazz Class of relational expression to match (must not be null)
* @param trait Trait to match, or null to match any trait
* @param children Child operands
*/
protected RelOptRuleOperand(
Class<? extends RelNode> clazz,
RelTrait trait,
RelOptRuleOperandChildren children) {
assert clazz != null;
switch (children.policy) {
case ANY:
break;
case LEAF:
assert children.operands.size() == 0;
break;
case UNORDERED:
assert children.operands.size() == 1;
break;
default:
assert children.operands.size() > 0;
}
this.childPolicy = children.policy;
this.clazz = clazz;
this.trait = trait;
this.children = children.operands;
for (RelOptRuleOperand child : this.children) {
assert child.parent == null : "cannot re-use operands";
child.parent = this;
}
}
//~ Methods ----------------------------------------------------------------
/**
* Returns the parent operand.
*
* @return parent operand
*/
public RelOptRuleOperand getParent() {
return parent;
}
/**
* Sets the parent operand.
*
* @param parent Parent operand
*/
public void setParent(RelOptRuleOperand parent) {
this.parent = parent;
}
/**
* Returns the rule this operand belongs to.
*
* @return containing rule
*/
public RelOptRule getRule() {
return rule;
}
/**
* Sets the rule this operand belongs to
*
* @param rule containing rule
*/
public void setRule(RelOptRule rule) {
this.rule = rule;
}
public int hashCode() {
int h = clazz.hashCode();
h = Util.hash(h, trait);
h = Util.hash(h, children);
return h;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof RelOptRuleOperand)) {
return false;
}
RelOptRuleOperand that = (RelOptRuleOperand) obj;
return (this.clazz == that.clazz)
&& Util.equal(this.trait, that.trait)
&& this.children.equals(that.children);
}
/**
* @return relational expression class matched by this operand
*/
public Class<? extends RelNode> getMatchedClass() {
return clazz;
}
/**
* Returns the child operands.
*
* @return child operands
*/
public List<RelOptRuleOperand> getChildOperands() {
return children;
}
/**
* Returns whether a relational expression matches this operand. It must be
* of the right class and trait.
*/
public boolean matches(RelNode rel) {
if (!clazz.isInstance(rel)) {
return false;
}
if ((trait != null) && !rel.getTraitSet().contains(trait)) {
return false;
}
return true;
}
}
// End RelOptRuleOperand.java