blob: b97597d31354a9bad4b86d342b9fe9b5b91dbf35 [file] [log] [blame]
/*
* Copyright 2009-2010 by The Regents of the University of California
* Licensed 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 from
*
* 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 edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.visitors;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
import edu.uci.ics.hyracks.algebricks.common.utils.Triple;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalPlan;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractLogicalExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DieOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.OrderOperator.IOrder;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.PartitioningSplitOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.RunningAggregateOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ScriptOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SinkOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.WriteOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
import edu.uci.ics.hyracks.algebricks.core.algebra.properties.IPartitioningProperty;
import edu.uci.ics.hyracks.algebricks.core.algebra.properties.IPhysicalPropertiesVector;
import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
public class IsomorphismOperatorVisitor implements ILogicalOperatorVisitor<Boolean, ILogicalOperator> {
private Map<LogicalVariable, LogicalVariable> variableMapping = new HashMap<LogicalVariable, LogicalVariable>();
public IsomorphismOperatorVisitor() {
}
@Override
public Boolean visitAggregateOperator(AggregateOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.AGGREGATE)
return Boolean.FALSE;
AggregateOperator aggOpArg = (AggregateOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(
getPairList(op.getVariables(), op.getExpressions()),
getPairList(aggOpArg.getVariables(), aggOpArg.getExpressions()));
return isomorphic;
}
@Override
public Boolean visitRunningAggregateOperator(RunningAggregateOperator op, ILogicalOperator arg)
throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.RUNNINGAGGREGATE)
return Boolean.FALSE;
RunningAggregateOperator aggOpArg = (RunningAggregateOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(
getPairList(op.getVariables(), op.getExpressions()),
getPairList(aggOpArg.getVariables(), aggOpArg.getExpressions()));
return isomorphic;
}
@Override
public Boolean visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, ILogicalOperator arg)
throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) copyAndSubstituteVar(op, arg);
if (aop.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE)
return Boolean.FALSE;
return Boolean.TRUE;
}
@Override
public Boolean visitExtensionOperator(ExtensionOperator op, ILogicalOperator arg) throws AlgebricksException {
ExtensionOperator aop = (ExtensionOperator) copyAndSubstituteVar(op, arg);
if (aop.getOperatorTag() != LogicalOperatorTag.EXTENSION_OPERATOR)
return Boolean.FALSE;
return Boolean.TRUE;
}
@Override
public Boolean visitGroupByOperator(GroupByOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
// require the same physical operator, otherwise delivers different data
// properties
if (aop.getOperatorTag() != LogicalOperatorTag.GROUP
|| aop.getPhysicalOperator().getOperatorTag() != op.getPhysicalOperator().getOperatorTag())
return Boolean.FALSE;
List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> keyLists = op.getGroupByList();
GroupByOperator gbyOpArg = (GroupByOperator) copyAndSubstituteVar(op, arg);
List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> keyListsArg = gbyOpArg.getGroupByList();
List<Pair<LogicalVariable, ILogicalExpression>> listLeft = new ArrayList<Pair<LogicalVariable, ILogicalExpression>>();
List<Pair<LogicalVariable, ILogicalExpression>> listRight = new ArrayList<Pair<LogicalVariable, ILogicalExpression>>();
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> pair : keyLists)
listLeft.add(new Pair<LogicalVariable, ILogicalExpression>(pair.first, pair.second.getValue()));
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> pair : keyListsArg)
listRight.add(new Pair<LogicalVariable, ILogicalExpression>(pair.first, pair.second.getValue()));
boolean isomorphic = VariableUtilities.varListEqualUnordered(listLeft, listRight);
if (!isomorphic)
return Boolean.FALSE;
int sizeOp = op.getNestedPlans().size();
int sizeArg = gbyOpArg.getNestedPlans().size();
if (sizeOp != sizeArg)
return Boolean.FALSE;
GroupByOperator argOp = (GroupByOperator) arg;
List<ILogicalPlan> plans = op.getNestedPlans();
List<ILogicalPlan> plansArg = argOp.getNestedPlans();
for (int i = 0; i < plans.size(); i++) {
List<Mutable<ILogicalOperator>> roots = plans.get(i).getRoots();
List<Mutable<ILogicalOperator>> rootsArg = plansArg.get(i).getRoots();
if (roots.size() != rootsArg.size())
return Boolean.FALSE;
for (int j = 0; j < roots.size(); j++) {
ILogicalOperator topOp1 = roots.get(j).getValue();
ILogicalOperator topOp2 = rootsArg.get(j).getValue();
isomorphic = this.checkBottomUp(topOp1, topOp2);
if (!isomorphic)
return Boolean.FALSE;
}
}
return isomorphic;
}
@Override
public Boolean visitLimitOperator(LimitOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.LIMIT)
return Boolean.FALSE;
LimitOperator limitOpArg = (LimitOperator) copyAndSubstituteVar(op, arg);
if (op.getOffset() != limitOpArg.getOffset())
return Boolean.FALSE;
boolean isomorphic = op.getMaxObjects().getValue().equals(limitOpArg.getMaxObjects().getValue());
return isomorphic;
}
@Override
public Boolean visitDieOperator(DieOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.DIE)
return Boolean.FALSE;
DieOperator dieOpArg = (DieOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = op.getAfterObjects().getValue().equals(dieOpArg.getAfterObjects().getValue());
return isomorphic;
}
@Override
public Boolean visitInnerJoinOperator(InnerJoinOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.INNERJOIN)
return Boolean.FALSE;
InnerJoinOperator joinOpArg = (InnerJoinOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = op.getCondition().getValue().equals(joinOpArg.getCondition().getValue());
return isomorphic;
}
@Override
public Boolean visitLeftOuterJoinOperator(LeftOuterJoinOperator op, ILogicalOperator arg)
throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.LEFTOUTERJOIN)
return Boolean.FALSE;
LeftOuterJoinOperator joinOpArg = (LeftOuterJoinOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = op.getCondition().getValue().equals(joinOpArg.getCondition().getValue());
return isomorphic;
}
@Override
public Boolean visitNestedTupleSourceOperator(NestedTupleSourceOperator op, ILogicalOperator arg)
throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.NESTEDTUPLESOURCE)
return Boolean.FALSE;
return Boolean.TRUE;
}
@Override
public Boolean visitOrderOperator(OrderOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.ORDER)
return Boolean.FALSE;
OrderOperator orderOpArg = (OrderOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = compareIOrderAndExpressions(op.getOrderExpressions(), orderOpArg.getOrderExpressions());
return isomorphic;
}
@Override
public Boolean visitAssignOperator(AssignOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.ASSIGN)
return Boolean.FALSE;
AssignOperator assignOpArg = (AssignOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(
getPairList(op.getVariables(), op.getExpressions()),
getPairList(assignOpArg.getVariables(), assignOpArg.getExpressions()));
return isomorphic;
}
@Override
public Boolean visitSelectOperator(SelectOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.SELECT)
return Boolean.FALSE;
SelectOperator selectOpArg = (SelectOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = op.getCondition().getValue().equals(selectOpArg.getCondition().getValue());
return isomorphic;
}
@Override
public Boolean visitProjectOperator(ProjectOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.PROJECT)
return Boolean.FALSE;
ProjectOperator projectOpArg = (ProjectOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), projectOpArg.getVariables());
return isomorphic;
}
@Override
public Boolean visitPartitioningSplitOperator(PartitioningSplitOperator op, ILogicalOperator arg)
throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.PARTITIONINGSPLIT)
return Boolean.FALSE;
PartitioningSplitOperator partitionOpArg = (PartitioningSplitOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = compareExpressions(op.getExpressions(), partitionOpArg.getExpressions());
return isomorphic;
}
@Override
public Boolean visitReplicateOperator(ReplicateOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.REPLICATE)
return Boolean.FALSE;
return Boolean.TRUE;
}
@Override
public Boolean visitScriptOperator(ScriptOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.SCRIPT)
return Boolean.FALSE;
ScriptOperator scriptOpArg = (ScriptOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = op.getScriptDescription().equals(scriptOpArg.getScriptDescription());
return isomorphic;
}
@Override
public Boolean visitSubplanOperator(SubplanOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.SUBPLAN)
return Boolean.FALSE;
SubplanOperator subplanOpArg = (SubplanOperator) copyAndSubstituteVar(op, arg);
List<ILogicalPlan> plans = op.getNestedPlans();
List<ILogicalPlan> plansArg = subplanOpArg.getNestedPlans();
for (int i = 0; i < plans.size(); i++) {
List<Mutable<ILogicalOperator>> roots = plans.get(i).getRoots();
List<Mutable<ILogicalOperator>> rootsArg = plansArg.get(i).getRoots();
if (roots.size() == rootsArg.size())
return Boolean.FALSE;
for (int j = 0; j < roots.size(); j++) {
ILogicalOperator topOp1 = roots.get(j).getValue();
ILogicalOperator topOp2 = rootsArg.get(j).getValue();
boolean isomorphic = this.checkBottomUp(topOp1, topOp2);
if (!isomorphic)
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
@Override
public Boolean visitUnionOperator(UnionAllOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.UNIONALL)
return Boolean.FALSE;
UnionAllOperator unionOpArg = (UnionAllOperator) copyAndSubstituteVar(op, arg);
List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> mapping = op.getVariableMappings();
List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> mappingArg = unionOpArg.getVariableMappings();
if (mapping.size() != mappingArg.size())
return Boolean.FALSE;
return VariableUtilities.varListEqualUnordered(mapping, mappingArg);
}
@Override
public Boolean visitUnnestOperator(UnnestOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.UNNEST)
return Boolean.FALSE;
UnnestOperator unnestOpArg = (UnnestOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), unnestOpArg.getVariables())
&& variableEqual(op.getPositionalVariable(), unnestOpArg.getPositionalVariable());
if (!isomorphic)
return Boolean.FALSE;
isomorphic = op.getExpressionRef().getValue().equals(unnestOpArg.getExpressionRef().getValue());
return isomorphic;
}
@Override
public Boolean visitUnnestMapOperator(UnnestMapOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.UNNEST_MAP)
return Boolean.FALSE;
UnnestMapOperator unnestOpArg = (UnnestMapOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), unnestOpArg.getVariables());
if (!isomorphic)
return Boolean.FALSE;
isomorphic = op.getExpressionRef().getValue().equals(unnestOpArg.getExpressionRef().getValue());
return isomorphic;
}
@Override
public Boolean visitDataScanOperator(DataSourceScanOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.DATASOURCESCAN)
return Boolean.FALSE;
DataSourceScanOperator argScan = (DataSourceScanOperator) arg;
if (!argScan.getDataSource().toString().equals(op.getDataSource().toString()))
return Boolean.FALSE;
DataSourceScanOperator scanOpArg = (DataSourceScanOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), scanOpArg.getVariables())
&& op.getDataSource().toString().equals(scanOpArg.getDataSource().toString());
return isomorphic;
}
@Override
public Boolean visitDistinctOperator(DistinctOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.DISTINCT)
return Boolean.FALSE;
DistinctOperator distinctOpArg = (DistinctOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = compareExpressions(op.getExpressions(), distinctOpArg.getExpressions());
return isomorphic;
}
@Override
public Boolean visitExchangeOperator(ExchangeOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.EXCHANGE)
return Boolean.FALSE;
// require the same partition property
if (!(op.getPhysicalOperator().getOperatorTag() == aop.getPhysicalOperator().getOperatorTag()))
return Boolean.FALSE;
variableMapping.clear();
IsomorphismUtilities.mapVariablesTopDown(op, arg, variableMapping);
IPhysicalPropertiesVector properties = op.getPhysicalOperator().getDeliveredProperties();
IPhysicalPropertiesVector propertiesArg = aop.getPhysicalOperator().getDeliveredProperties();
if (properties == null && propertiesArg == null)
return Boolean.TRUE;
if (properties == null || propertiesArg == null)
return Boolean.FALSE;
IPartitioningProperty partProp = properties.getPartitioningProperty();
IPartitioningProperty partPropArg = propertiesArg.getPartitioningProperty();
if (!partProp.getPartitioningType().equals(partPropArg.getPartitioningType()))
return Boolean.FALSE;
List<LogicalVariable> columns = new ArrayList<LogicalVariable>();
partProp.getColumns(columns);
List<LogicalVariable> columnsArg = new ArrayList<LogicalVariable>();
partPropArg.getColumns(columnsArg);
if (columns.size() != columnsArg.size())
return Boolean.FALSE;
if (columns.size() == 0)
return Boolean.TRUE;
for (int i = 0; i < columnsArg.size(); i++) {
LogicalVariable rightVar = columnsArg.get(i);
LogicalVariable leftVar = variableMapping.get(rightVar);
if (leftVar != null)
columnsArg.set(i, leftVar);
}
return VariableUtilities.varListEqualUnordered(columns, columnsArg);
}
@Override
public Boolean visitWriteOperator(WriteOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.WRITE)
return Boolean.FALSE;
WriteOperator writeOpArg = (WriteOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), writeOpArg.getSchema());
return isomorphic;
}
@Override
public Boolean visitWriteResultOperator(WriteResultOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.WRITE_RESULT)
return Boolean.FALSE;
WriteResultOperator writeOpArg = (WriteResultOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), writeOpArg.getSchema());
if (!op.getDataSource().equals(writeOpArg.getDataSource()))
isomorphic = false;
if (!op.getPayloadExpression().equals(writeOpArg.getPayloadExpression()))
isomorphic = false;
return isomorphic;
}
@Override
public Boolean visitInsertDeleteOperator(InsertDeleteOperator op, ILogicalOperator arg) throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE)
return Boolean.FALSE;
InsertDeleteOperator insertOpArg = (InsertDeleteOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), insertOpArg.getSchema());
if (!op.getDataSource().equals(insertOpArg.getDataSource()))
isomorphic = false;
if (!op.getPayloadExpression().equals(insertOpArg.getPayloadExpression()))
isomorphic = false;
return isomorphic;
}
@Override
public Boolean visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op, ILogicalOperator arg)
throws AlgebricksException {
AbstractLogicalOperator aop = (AbstractLogicalOperator) arg;
if (aop.getOperatorTag() != LogicalOperatorTag.INDEX_INSERT_DELETE)
return Boolean.FALSE;
IndexInsertDeleteOperator insertOpArg = (IndexInsertDeleteOperator) copyAndSubstituteVar(op, arg);
boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), insertOpArg.getSchema());
if (!op.getDataSourceIndex().equals(insertOpArg.getDataSourceIndex()))
isomorphic = false;
return isomorphic;
}
@Override
public Boolean visitSinkOperator(SinkOperator op, ILogicalOperator arg) throws AlgebricksException {
return true;
}
private Boolean compareExpressions(List<Mutable<ILogicalExpression>> opExprs,
List<Mutable<ILogicalExpression>> argExprs) {
if (opExprs.size() != argExprs.size())
return Boolean.FALSE;
for (int i = 0; i < opExprs.size(); i++) {
boolean isomorphic = opExprs.get(i).getValue().equals(argExprs.get(i).getValue());
if (!isomorphic)
return Boolean.FALSE;
}
return Boolean.TRUE;
}
private Boolean compareIOrderAndExpressions(List<Pair<IOrder, Mutable<ILogicalExpression>>> opOrderExprs,
List<Pair<IOrder, Mutable<ILogicalExpression>>> argOrderExprs) {
if (opOrderExprs.size() != argOrderExprs.size())
return Boolean.FALSE;
for (int i = 0; i < opOrderExprs.size(); i++) {
boolean isomorphic = opOrderExprs.get(i).first.equals(argOrderExprs.get(i).first);
if (!isomorphic)
return Boolean.FALSE;
isomorphic = opOrderExprs.get(i).second.getValue().equals(argOrderExprs.get(i).second.getValue());
if (!isomorphic)
return Boolean.FALSE;
}
return Boolean.TRUE;
}
private Boolean checkBottomUp(ILogicalOperator op1, ILogicalOperator op2) throws AlgebricksException {
List<Mutable<ILogicalOperator>> inputs1 = op1.getInputs();
List<Mutable<ILogicalOperator>> inputs2 = op2.getInputs();
if (inputs1.size() != inputs2.size())
return Boolean.FALSE;
for (int i = 0; i < inputs1.size(); i++) {
ILogicalOperator input1 = inputs1.get(i).getValue();
ILogicalOperator input2 = inputs2.get(i).getValue();
boolean isomorphic = checkBottomUp(input1, input2);
if (!isomorphic)
return Boolean.FALSE;
}
return IsomorphismUtilities.isOperatorIsomorphic(op1, op2);
}
private ILogicalOperator copyAndSubstituteVar(ILogicalOperator op, ILogicalOperator argOp)
throws AlgebricksException {
ILogicalOperator newOp = IsomorphismOperatorVisitor.deepCopy(argOp);
variableMapping.clear();
IsomorphismUtilities.mapVariablesTopDown(op, argOp, variableMapping);
List<LogicalVariable> liveVars = new ArrayList<LogicalVariable>();
if (argOp.getInputs().size() > 0)
for (int i = 0; i < argOp.getInputs().size(); i++)
VariableUtilities.getLiveVariables(argOp.getInputs().get(i).getValue(), liveVars);
List<LogicalVariable> producedVars = new ArrayList<LogicalVariable>();
VariableUtilities.getProducedVariables(argOp, producedVars);
List<LogicalVariable> producedVarsNew = new ArrayList<LogicalVariable>();
VariableUtilities.getProducedVariables(op, producedVarsNew);
if (producedVars.size() != producedVarsNew.size())
return newOp;
for (Entry<LogicalVariable, LogicalVariable> map : variableMapping.entrySet()) {
if (liveVars.contains(map.getKey())) {
VariableUtilities.substituteVariables(newOp, map.getKey(), map.getValue(), null);
}
}
for (int i = 0; i < producedVars.size(); i++)
VariableUtilities.substituteVariables(newOp, producedVars.get(i), producedVarsNew.get(i), null);
return newOp;
}
public List<Pair<LogicalVariable, ILogicalExpression>> getPairList(List<LogicalVariable> vars,
List<Mutable<ILogicalExpression>> exprs) throws AlgebricksException {
List<Pair<LogicalVariable, ILogicalExpression>> list = new ArrayList<Pair<LogicalVariable, ILogicalExpression>>();
if (vars.size() != exprs.size())
throw new AlgebricksException("variable list size does not equal to expression list size ");
for (int i = 0; i < vars.size(); i++) {
list.add(new Pair<LogicalVariable, ILogicalExpression>(vars.get(i), exprs.get(i).getValue()));
}
return list;
}
private static ILogicalOperator deepCopy(ILogicalOperator op) throws AlgebricksException {
OperatorDeepCopyVisitor visitor = new OperatorDeepCopyVisitor();
return op.accept(visitor, null);
}
private static ILogicalPlan deepCopy(ILogicalPlan plan) throws AlgebricksException {
List<Mutable<ILogicalOperator>> roots = plan.getRoots();
List<Mutable<ILogicalOperator>> newRoots = new ArrayList<Mutable<ILogicalOperator>>();
for (Mutable<ILogicalOperator> opRef : roots)
newRoots.add(new MutableObject<ILogicalOperator>(bottomUpCopyOperators(opRef.getValue())));
return new ALogicalPlanImpl(newRoots);
}
private static ILogicalOperator bottomUpCopyOperators(ILogicalOperator op) throws AlgebricksException {
ILogicalOperator newOp = deepCopy(op);
newOp.getInputs().clear();
for (Mutable<ILogicalOperator> child : op.getInputs())
newOp.getInputs().add(new MutableObject<ILogicalOperator>(bottomUpCopyOperators(child.getValue())));
return newOp;
}
private static boolean variableEqual(LogicalVariable var, LogicalVariable varArg) {
if (var == null && varArg == null)
return true;
if (var.equals(varArg))
return true;
else
return false;
}
private static class OperatorDeepCopyVisitor implements ILogicalOperatorVisitor<ILogicalOperator, Void> {
@Override
public ILogicalOperator visitAggregateOperator(AggregateOperator op, Void arg) throws AlgebricksException {
ArrayList<LogicalVariable> newList = new ArrayList<LogicalVariable>();
ArrayList<Mutable<ILogicalExpression>> newExpressions = new ArrayList<Mutable<ILogicalExpression>>();
newList.addAll(op.getVariables());
deepCopyExpressionRefs(newExpressions, op.getExpressions());
return new AggregateOperator(newList, newExpressions);
}
@Override
public ILogicalOperator visitRunningAggregateOperator(RunningAggregateOperator op, Void arg)
throws AlgebricksException {
ArrayList<LogicalVariable> newList = new ArrayList<LogicalVariable>();
ArrayList<Mutable<ILogicalExpression>> newExpressions = new ArrayList<Mutable<ILogicalExpression>>();
newList.addAll(op.getVariables());
deepCopyExpressionRefs(newExpressions, op.getExpressions());
return new RunningAggregateOperator(newList, newExpressions);
}
@Override
public ILogicalOperator visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, Void arg)
throws AlgebricksException {
return new EmptyTupleSourceOperator();
}
@Override
public ILogicalOperator visitGroupByOperator(GroupByOperator op, Void arg) throws AlgebricksException {
List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> groupByList = new ArrayList<Pair<LogicalVariable, Mutable<ILogicalExpression>>>();
List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> decoList = new ArrayList<Pair<LogicalVariable, Mutable<ILogicalExpression>>>();
ArrayList<ILogicalPlan> newSubplans = new ArrayList<ILogicalPlan>();
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> pair : op.getGroupByList())
groupByList.add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(pair.first,
deepCopyExpressionRef(pair.second)));
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> pair : op.getDecorList())
decoList.add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(pair.first,
deepCopyExpressionRef(pair.second)));
for (ILogicalPlan plan : op.getNestedPlans()) {
newSubplans.add(IsomorphismOperatorVisitor.deepCopy(plan));
}
return new GroupByOperator(groupByList, decoList, newSubplans);
}
@Override
public ILogicalOperator visitLimitOperator(LimitOperator op, Void arg) throws AlgebricksException {
return new LimitOperator(deepCopyExpressionRef(op.getMaxObjects()).getValue(), deepCopyExpressionRef(
op.getOffset()).getValue(), op.isTopmostLimitOp());
}
@Override
public ILogicalOperator visitDieOperator(DieOperator op, Void arg) throws AlgebricksException {
return new DieOperator(deepCopyExpressionRef(op.getAfterObjects()).getValue());
}
@Override
public ILogicalOperator visitInnerJoinOperator(InnerJoinOperator op, Void arg) throws AlgebricksException {
return new InnerJoinOperator(deepCopyExpressionRef(op.getCondition()), op.getInputs().get(0), op
.getInputs().get(1));
}
@Override
public ILogicalOperator visitLeftOuterJoinOperator(LeftOuterJoinOperator op, Void arg)
throws AlgebricksException {
return new LeftOuterJoinOperator(deepCopyExpressionRef(op.getCondition()), op.getInputs().get(0), op
.getInputs().get(1));
}
@Override
public ILogicalOperator visitNestedTupleSourceOperator(NestedTupleSourceOperator op, Void arg)
throws AlgebricksException {
return new NestedTupleSourceOperator(null);
}
@Override
public ILogicalOperator visitOrderOperator(OrderOperator op, Void arg) throws AlgebricksException {
return new OrderOperator(this.deepCopyOrderAndExpression(op.getOrderExpressions()));
}
@Override
public ILogicalOperator visitAssignOperator(AssignOperator op, Void arg) throws AlgebricksException {
ArrayList<LogicalVariable> newList = new ArrayList<LogicalVariable>();
ArrayList<Mutable<ILogicalExpression>> newExpressions = new ArrayList<Mutable<ILogicalExpression>>();
newList.addAll(op.getVariables());
deepCopyExpressionRefs(newExpressions, op.getExpressions());
return new AssignOperator(newList, newExpressions);
}
@Override
public ILogicalOperator visitSelectOperator(SelectOperator op, Void arg) throws AlgebricksException {
return new SelectOperator(deepCopyExpressionRef(op.getCondition()));
}
@Override
public ILogicalOperator visitProjectOperator(ProjectOperator op, Void arg) throws AlgebricksException {
ArrayList<LogicalVariable> newList = new ArrayList<LogicalVariable>();
newList.addAll(op.getVariables());
return new ProjectOperator(newList);
}
@Override
public ILogicalOperator visitPartitioningSplitOperator(PartitioningSplitOperator op, Void arg)
throws AlgebricksException {
ArrayList<Mutable<ILogicalExpression>> newExpressions = new ArrayList<Mutable<ILogicalExpression>>();
deepCopyExpressionRefs(newExpressions, op.getExpressions());
return new PartitioningSplitOperator(newExpressions, op.getDefaultBranchIndex());
}
@Override
public ILogicalOperator visitReplicateOperator(ReplicateOperator op, Void arg) throws AlgebricksException {
return new ReplicateOperator(op.getOutputArity());
}
@Override
public ILogicalOperator visitScriptOperator(ScriptOperator op, Void arg) throws AlgebricksException {
ArrayList<LogicalVariable> newInputList = new ArrayList<LogicalVariable>();
ArrayList<LogicalVariable> newOutputList = new ArrayList<LogicalVariable>();
newInputList.addAll(op.getInputVariables());
newOutputList.addAll(op.getOutputVariables());
return new ScriptOperator(op.getScriptDescription(), newInputList, newOutputList);
}
@Override
public ILogicalOperator visitSubplanOperator(SubplanOperator op, Void arg) throws AlgebricksException {
ArrayList<ILogicalPlan> newSubplans = new ArrayList<ILogicalPlan>();
for (ILogicalPlan plan : op.getNestedPlans()) {
newSubplans.add(IsomorphismOperatorVisitor.deepCopy(plan));
}
return new SubplanOperator(newSubplans);
}
@Override
public ILogicalOperator visitUnionOperator(UnionAllOperator op, Void arg) throws AlgebricksException {
List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> newVarMap = new ArrayList<Triple<LogicalVariable, LogicalVariable, LogicalVariable>>();
List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> varMap = op.getVariableMappings();
for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> triple : varMap)
newVarMap.add(new Triple<LogicalVariable, LogicalVariable, LogicalVariable>(triple.first,
triple.second, triple.third));
return new UnionAllOperator(newVarMap);
}
@Override
public ILogicalOperator visitUnnestOperator(UnnestOperator op, Void arg) throws AlgebricksException {
return new UnnestOperator(op.getVariable(), deepCopyExpressionRef(op.getExpressionRef()),
op.getPositionalVariable(), op.getPositionalVariableType());
}
@Override
public ILogicalOperator visitUnnestMapOperator(UnnestMapOperator op, Void arg) throws AlgebricksException {
ArrayList<LogicalVariable> newInputList = new ArrayList<LogicalVariable>();
newInputList.addAll(op.getVariables());
return new UnnestMapOperator(newInputList, deepCopyExpressionRef(op.getExpressionRef()),
new ArrayList<Object>(op.getVariableTypes()), op.propagatesInput());
}
@Override
public ILogicalOperator visitDataScanOperator(DataSourceScanOperator op, Void arg) throws AlgebricksException {
ArrayList<LogicalVariable> newInputList = new ArrayList<LogicalVariable>();
newInputList.addAll(op.getVariables());
return new DataSourceScanOperator(newInputList, op.getDataSource());
}
@Override
public ILogicalOperator visitDistinctOperator(DistinctOperator op, Void arg) throws AlgebricksException {
ArrayList<Mutable<ILogicalExpression>> newExpressions = new ArrayList<Mutable<ILogicalExpression>>();
deepCopyExpressionRefs(newExpressions, op.getExpressions());
return new DistinctOperator(newExpressions);
}
@Override
public ILogicalOperator visitExchangeOperator(ExchangeOperator op, Void arg) throws AlgebricksException {
return new ExchangeOperator();
}
@Override
public ILogicalOperator visitWriteOperator(WriteOperator op, Void arg) throws AlgebricksException {
ArrayList<Mutable<ILogicalExpression>> newExpressions = new ArrayList<Mutable<ILogicalExpression>>();
deepCopyExpressionRefs(newExpressions, op.getExpressions());
return new WriteOperator(newExpressions, op.getDataSink());
}
@Override
public ILogicalOperator visitWriteResultOperator(WriteResultOperator op, Void arg) throws AlgebricksException {
ArrayList<Mutable<ILogicalExpression>> newKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>();
deepCopyExpressionRefs(newKeyExpressions, op.getKeyExpressions());
return new WriteResultOperator(op.getDataSource(), deepCopyExpressionRef(op.getPayloadExpression()),
newKeyExpressions);
}
@Override
public ILogicalOperator visitInsertDeleteOperator(InsertDeleteOperator op, Void arg) throws AlgebricksException {
List<Mutable<ILogicalExpression>> newKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>();
deepCopyExpressionRefs(newKeyExpressions, op.getPrimaryKeyExpressions());
return new InsertDeleteOperator(op.getDataSource(), deepCopyExpressionRef(op.getPayloadExpression()),
newKeyExpressions, op.getOperation());
}
@Override
public ILogicalOperator visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op, Void arg)
throws AlgebricksException {
List<Mutable<ILogicalExpression>> newPrimaryKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>();
deepCopyExpressionRefs(newPrimaryKeyExpressions, op.getPrimaryKeyExpressions());
List<Mutable<ILogicalExpression>> newSecondaryKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>();
deepCopyExpressionRefs(newSecondaryKeyExpressions, op.getSecondaryKeyExpressions());
Mutable<ILogicalExpression> newFilterExpression = new MutableObject<ILogicalExpression>(((AbstractLogicalExpression)op.getFilterExpression())
.cloneExpression());
return new IndexInsertDeleteOperator(op.getDataSourceIndex(), newPrimaryKeyExpressions,
newSecondaryKeyExpressions, newFilterExpression, op.getOperation());
}
@Override
public ILogicalOperator visitSinkOperator(SinkOperator op, Void arg) throws AlgebricksException {
return new SinkOperator();
}
private void deepCopyExpressionRefs(List<Mutable<ILogicalExpression>> newExprs,
List<Mutable<ILogicalExpression>> oldExprs) {
for (Mutable<ILogicalExpression> oldExpr : oldExprs)
newExprs.add(new MutableObject<ILogicalExpression>(((AbstractLogicalExpression) oldExpr.getValue())
.cloneExpression()));
}
private Mutable<ILogicalExpression> deepCopyExpressionRef(Mutable<ILogicalExpression> oldExpr) {
return new MutableObject<ILogicalExpression>(
((AbstractLogicalExpression) oldExpr.getValue()).cloneExpression());
}
private List<Pair<IOrder, Mutable<ILogicalExpression>>> deepCopyOrderAndExpression(
List<Pair<IOrder, Mutable<ILogicalExpression>>> ordersAndExprs) {
List<Pair<IOrder, Mutable<ILogicalExpression>>> newOrdersAndExprs = new ArrayList<Pair<IOrder, Mutable<ILogicalExpression>>>();
for (Pair<IOrder, Mutable<ILogicalExpression>> pair : ordersAndExprs)
newOrdersAndExprs.add(new Pair<IOrder, Mutable<ILogicalExpression>>(pair.first,
deepCopyExpressionRef(pair.second)));
return newOrdersAndExprs;
}
@Override
public ILogicalOperator visitExtensionOperator(ExtensionOperator op, Void arg) throws AlgebricksException {
return new ExtensionOperator(op.getNewInstanceOfDelegateOperator());
}
}
}