/**
* 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.reloperators;
import java.util.ArrayList;
import java.util.List;
import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.AbstractRelNode;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.util.Pair;
import org.apache.hadoop.hive.ql.optimizer.calcite.CalciteSemanticException;
import org.apache.hadoop.hive.ql.optimizer.calcite.HiveCalciteUtil;
import org.apache.hadoop.hive.ql.optimizer.calcite.HiveCalciteUtil.JoinPredicateInfo;
import org.apache.hadoop.hive.ql.optimizer.calcite.TraitsUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
* A HiveMultiJoin represents a succession of binary joins.
*/
public final class HiveMultiJoin extends AbstractRelNode {
private final List<RelNode> inputs;
private final RexNode condition;
private final RelDataType rowType;
private final ImmutableList<Pair<Integer,Integer>> joinInputs;
private final ImmutableList<JoinRelType> joinTypes;
private final ImmutableList<RexNode> filters;
private final boolean outerJoin;
private final JoinPredicateInfo joinPredInfo;
/**
* Constructs a MultiJoin.
*
* @param cluster cluster that join belongs to
* @param inputs inputs into this multi-join
* @param condition join filter applicable to this join node
* @param rowType row type of the join result of this node
* @param joinInputs
* @param joinTypes the join type corresponding to each input; if
* an input is null-generating in a left or right
* outer join, the entry indicates the type of
* outer join; otherwise, the entry is set to
* INNER
* @param filters filters associated with each join
* input
* @param joinPredicateInfo join predicate information
*/
public HiveMultiJoin(
RelOptCluster cluster,
List<RelNode> inputs,
RexNode condition,
RelDataType rowType,
List<Pair<Integer,Integer>> joinInputs,
List<JoinRelType> joinTypes,
List<RexNode> filters,
JoinPredicateInfo joinPredicateInfo) {
super(cluster, TraitsUtil.getDefaultTraitSet(cluster));
this.inputs = inputs;
this.condition = condition;
this.rowType = rowType;
assert joinInputs.size() == joinTypes.size();
this.joinInputs = ImmutableList.copyOf(joinInputs);
this.joinTypes = ImmutableList.copyOf(joinTypes);
this.filters = ImmutableList.copyOf(filters);
this.outerJoin = containsOuter();
if (joinPredicateInfo == null) {
try {
this.joinPredInfo = HiveCalciteUtil.JoinPredicateInfo.constructJoinPredicateInfo(this);
} catch (CalciteSemanticException e) {
throw new RuntimeException(e);
}
} else {
this.joinPredInfo = joinPredicateInfo;
}
}
public HiveMultiJoin(
RelOptCluster cluster,
List<RelNode> inputs,
RexNode condition,
RelDataType rowType,
List<Pair<Integer,Integer>> joinInputs,
List<JoinRelType> joinTypes,
List<RexNode> filters) {
this(cluster, Lists.newArrayList(inputs), condition, rowType, joinInputs, joinTypes, filters, null);
}
@Override
public void replaceInput(int ordinalInParent, RelNode p) {
inputs.set(ordinalInParent, p);
}
@Override
public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
assert traitSet.containsIfApplicable(HiveRelNode.CONVENTION);
return new HiveMultiJoin(
getCluster(),
inputs,
condition,
rowType,
joinInputs,
joinTypes,
filters);
}
@Override
public RelWriter explainTerms(RelWriter pw) {
List<String> joinsString = new ArrayList<String>();
for (int i = 0; i < joinInputs.size(); i++) {
final StringBuilder sb = new StringBuilder();
sb.append(joinInputs.get(i).left).append(" - ").append(joinInputs.get(i).right)
.append(" : ").append(joinTypes.get(i).name());
joinsString.add(sb.toString());
}
super.explainTerms(pw);
for (Ord<RelNode> ord : Ord.zip(inputs)) {
pw.input("input#" + ord.i, ord.e);
}
return pw.item("condition", condition)
.item("joinsDescription", joinsString);
}
@Override
public RelDataType deriveRowType() {
return rowType;
}
@Override
public List<RelNode> getInputs() {
return inputs;
}
@Override public List<RexNode> getChildExps() {
return ImmutableList.of(condition);
}
@Override
public RelNode accept(RexShuttle shuttle) {
RexNode joinFilter = shuttle.apply(this.condition);
if (joinFilter == this.condition) {
return this;
}
return new HiveMultiJoin(
getCluster(),
inputs,
joinFilter,
rowType,
joinInputs,
joinTypes,
filters);
}
/**
* @return join filters associated with this MultiJoin
*/
public RexNode getCondition() {
return condition;
}
/**
* @return true if the MultiJoin contains a (partial) outer join.
*/
public boolean isOuterJoin() {
return outerJoin;
}
/**
* @return join relationships between inputs
*/
public List<Pair<Integer,Integer>> getJoinInputs() {
return joinInputs;
}
/**
* @return join types of each input
*/
public List<JoinRelType> getJoinTypes() {
return joinTypes;
}
/**
* @return join conditions filters
*/
public List<RexNode> getJoinFilters() {
return filters;
}
/**
* @return the join predicate information
*/
public JoinPredicateInfo getJoinPredicateInfo() {
return joinPredInfo;
}
private boolean containsOuter() {
for (JoinRelType joinType : joinTypes) {
if (joinType != JoinRelType.INNER) {
return true;
}
}
return false;
}
}
// End MultiJoin.java