blob: b6556e9d0f58a5c9f90cf8f83c0dd3f9699da948 [file] [log] [blame]
/*
* 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.hyracks.algebricks.rewriter.rules;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.utils.Triple;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
/**
* @author kereno, ecarm002, ildar.absalyamov
* Pushes down unnest through both branches of the union operator
* Before rule:
* ============
* unnest
* union (left_branch, right_branch, res)
* left_branch
* right_branch
* After rule:
* ============
* union (left_branch, right_branch, res)
* unnest
* left_branch
* unnest
* right_branch
*/
public class PushUnnestDownThroughUnionRule implements IAlgebraicRewriteRule {
@Override
public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
return false;
}
@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
throws AlgebricksException {
AbstractLogicalOperator unnest = (AbstractLogicalOperator) opRef.getValue();
if (unnest.getOperatorTag() != LogicalOperatorTag.UNNEST) {
return false;
}
UnnestOperator unnestOpRef = (UnnestOperator) opRef.getValue();
Mutable<ILogicalOperator> unionOp = unnest.getInputs().get(0);
AbstractLogicalOperator unionAbstractOp = (AbstractLogicalOperator) unionOp.getValue();
if (unionAbstractOp.getOperatorTag() != LogicalOperatorTag.UNIONALL) {
return false;
}
LogicalVariable unnestVar1 = context.newVar();
UnnestOperator unnest1 = new UnnestOperator(unnestVar1, new MutableObject<ILogicalExpression>(unnestOpRef
.getExpressionRef().getValue().cloneExpression()));
LogicalVariable unnestVar2 = context.newVar();
UnnestOperator unnest2 = new UnnestOperator(unnestVar2, new MutableObject<ILogicalExpression>(unnestOpRef
.getExpressionRef().getValue().cloneExpression()));
//Getting the two topmost branched and adding them as an input to the unnests:
Mutable<ILogicalOperator> branch1 = unionAbstractOp.getInputs().get(0);
ILogicalOperator agg1 = branch1.getValue();
List<LogicalVariable> agg1_var = new ArrayList<LogicalVariable>();
VariableUtilities.getLiveVariables(agg1, agg1_var);
Mutable<ILogicalOperator> branch2 = unionAbstractOp.getInputs().get(1);
ILogicalOperator agg2 = branch2.getValue();
List<LogicalVariable> agg2_var = new ArrayList<LogicalVariable>();
VariableUtilities.getLiveVariables(agg2, agg2_var);
//Modifying the unnest so it has the right variable
List<LogicalVariable> var_unnest_1 = new ArrayList<LogicalVariable>();
unnest1.getExpressionRef().getValue().getUsedVariables(var_unnest_1);
unnest1.getExpressionRef().getValue().substituteVar(var_unnest_1.get(0), agg1_var.get(0));
List<LogicalVariable> var_unnest2 = new ArrayList<LogicalVariable>();
unnest2.getExpressionRef().getValue().getUsedVariables(var_unnest2);
unnest2.getExpressionRef().getValue().substituteVar(var_unnest2.get(0), agg2_var.get(0));
unnest1.getInputs().add(branch1);
unnest2.getInputs().add(branch2);
context.computeAndSetTypeEnvironmentForOperator(unnest1);
context.computeAndSetTypeEnvironmentForOperator(unnest2);
//creating a new union operator with the updated logical variables
List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> varMap = new ArrayList<Triple<LogicalVariable, LogicalVariable, LogicalVariable>>(
1);
Triple<LogicalVariable, LogicalVariable, LogicalVariable> union_triple_vars = new Triple<LogicalVariable, LogicalVariable, LogicalVariable>(
unnestVar1, unnestVar2, unnestOpRef.getVariables().get(0));
varMap.add(union_triple_vars);
UnionAllOperator unionOpFinal = new UnionAllOperator(varMap);
unionOpFinal.getInputs().add(new MutableObject<ILogicalOperator>(unnest1));
unionOpFinal.getInputs().add(new MutableObject<ILogicalOperator>(unnest2));
context.computeAndSetTypeEnvironmentForOperator(unionOpFinal);
opRef.setValue(unionOpFinal);
return true;
}
}