blob: e6a8032b29610c176552a55143fe5e764056aa8a [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.core.algebra.operators.logical.visitors;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.utils.Pair;
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.ILogicalPlan;
import org.apache.hyracks.algebricks.core.algebra.base.IPhysicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractUnnestMapOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistributeResultOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteUpsertOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteUpsertOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.IntersectOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestMapOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.MaterializeOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator.IOrder;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.RangeForwardOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.RunningAggregateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ScriptOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SinkOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SplitOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.TokenizeOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.physical.HashPartitionExchangePOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.physical.HashPartitionMergeExchangePOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.physical.RangePartitionExchangePOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.physical.RangePartitionMergeExchangePOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.physical.SortMergeExchangePOperator;
import org.apache.hyracks.algebricks.core.algebra.properties.OrderColumn;
import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
public class UsedVariableVisitor implements ILogicalOperatorVisitor<Void, Void> {
private Collection<LogicalVariable> usedVariables;
public UsedVariableVisitor(Collection<LogicalVariable> usedVariables) {
this.usedVariables = usedVariables;
}
@Override
public Void visitAggregateOperator(AggregateOperator op, Void arg) {
for (Mutable<ILogicalExpression> exprRef : op.getExpressions()) {
exprRef.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitAssignOperator(AssignOperator op, Void arg) {
for (Mutable<ILogicalExpression> exprRef : op.getExpressions()) {
exprRef.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitDataScanOperator(DataSourceScanOperator op, Void arg) {
if (op.getAdditionalFilteringExpressions() != null) {
for (Mutable<ILogicalExpression> e : op.getAdditionalFilteringExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
}
return null;
}
@Override
public Void visitDistinctOperator(DistinctOperator op, Void arg) {
for (Mutable<ILogicalExpression> eRef : op.getExpressions()) {
eRef.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, Void arg) {
// does not use any variable
return null;
}
@Override
public Void visitExchangeOperator(ExchangeOperator op, Void arg) throws AlgebricksException {
// Used variables depend on the physical operator.
if (op.getPhysicalOperator() != null) {
IPhysicalOperator physOp = op.getPhysicalOperator();
switch (physOp.getOperatorTag()) {
case BROADCAST_EXCHANGE:
case ONE_TO_ONE_EXCHANGE:
case RANDOM_MERGE_EXCHANGE: {
// No variables used.
break;
}
case HASH_PARTITION_EXCHANGE: {
HashPartitionExchangePOperator concreteOp = (HashPartitionExchangePOperator) physOp;
usedVariables.addAll(concreteOp.getHashFields());
break;
}
case HASH_PARTITION_MERGE_EXCHANGE: {
HashPartitionMergeExchangePOperator concreteOp = (HashPartitionMergeExchangePOperator) physOp;
usedVariables.addAll(concreteOp.getPartitionFields());
for (OrderColumn orderCol : concreteOp.getOrderColumns()) {
usedVariables.add(orderCol.getColumn());
}
break;
}
case SORT_MERGE_EXCHANGE: {
SortMergeExchangePOperator concreteOp = (SortMergeExchangePOperator) physOp;
for (OrderColumn orderCol : concreteOp.getSortColumns()) {
usedVariables.add(orderCol.getColumn());
}
break;
}
case RANGE_PARTITION_EXCHANGE: {
RangePartitionExchangePOperator concreteOp = (RangePartitionExchangePOperator) physOp;
for (OrderColumn partCol : concreteOp.getPartitioningFields()) {
usedVariables.add(partCol.getColumn());
}
break;
}
case RANGE_PARTITION_MERGE_EXCHANGE: {
RangePartitionMergeExchangePOperator concreteOp = (RangePartitionMergeExchangePOperator) physOp;
for (OrderColumn partCol : concreteOp.getPartitioningFields()) {
usedVariables.add(partCol.getColumn());
}
break;
}
case RANDOM_PARTITION_EXCHANGE: {
break;
}
default: {
throw new AlgebricksException("Unhandled physical operator tag '" + physOp.getOperatorTag() + "'.");
}
}
}
return null;
}
@Override
public Void visitGroupByOperator(GroupByOperator op, Void arg) throws AlgebricksException {
for (ILogicalPlan p : op.getNestedPlans()) {
for (Mutable<ILogicalOperator> r : p.getRoots()) {
VariableUtilities.getUsedVariablesInDescendantsAndSelf(r.getValue(), usedVariables);
}
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> g : op.getGroupByList()) {
g.second.getValue().getUsedVariables(usedVariables);
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> g : op.getDecorList()) {
g.second.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitInnerJoinOperator(InnerJoinOperator op, Void arg) {
op.getCondition().getValue().getUsedVariables(usedVariables);
return null;
}
@Override
public Void visitLeftOuterJoinOperator(LeftOuterJoinOperator op, Void arg) {
op.getCondition().getValue().getUsedVariables(usedVariables);
return null;
}
@Override
public Void visitLimitOperator(LimitOperator op, Void arg) {
op.getMaxObjects().getValue().getUsedVariables(usedVariables);
ILogicalExpression offsetExpr = op.getOffset().getValue();
if (offsetExpr != null) {
offsetExpr.getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op, Void arg) {
// does not use any variable
return null;
}
@Override
public Void visitOrderOperator(OrderOperator op, Void arg) {
for (Pair<IOrder, Mutable<ILogicalExpression>> oe : op.getOrderExpressions()) {
oe.second.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitProjectOperator(ProjectOperator op, Void arg) {
List<LogicalVariable> parameterVariables = op.getVariables();
for (LogicalVariable v : parameterVariables) {
if (!usedVariables.contains(v)) {
usedVariables.add(v);
}
}
return null;
}
@Override
public Void visitRunningAggregateOperator(RunningAggregateOperator op, Void arg) {
for (Mutable<ILogicalExpression> exprRef : op.getExpressions()) {
exprRef.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitScriptOperator(ScriptOperator op, Void arg) {
List<LogicalVariable> parameterVariables = op.getInputVariables();
for (LogicalVariable v : parameterVariables) {
if (!usedVariables.contains(v)) {
usedVariables.add(v);
}
}
return null;
}
@Override
public Void visitSelectOperator(SelectOperator op, Void arg) {
op.getCondition().getValue().getUsedVariables(usedVariables);
return null;
}
@Override
public Void visitSubplanOperator(SubplanOperator op, Void arg) throws AlgebricksException {
for (ILogicalPlan p : op.getNestedPlans()) {
for (Mutable<ILogicalOperator> r : p.getRoots()) {
VariableUtilities.getUsedVariablesInDescendantsAndSelf(r.getValue(), usedVariables);
}
}
return null;
}
@Override
public Void visitUnionOperator(UnionAllOperator op, Void arg) {
for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> m : op.getVariableMappings()) {
if (!usedVariables.contains(m.first)) {
usedVariables.add(m.first);
}
if (!usedVariables.contains(m.second)) {
usedVariables.add(m.second);
}
}
return null;
}
@Override
public Void visitIntersectOperator(IntersectOperator op, Void arg) throws AlgebricksException {
for (int i = 0; i < op.getNumInput(); i++) {
for (LogicalVariable var : op.getInputVariables(i)) {
if (!usedVariables.contains(var)) {
usedVariables.add(var);
}
}
}
return null;
}
@Override
public Void visitUnnestMapOperator(UnnestMapOperator op, Void arg) {
getUsedVarsFromExprAndFilterExpr(op);
return null;
}
@Override
public Void visitLeftOuterUnnestMapOperator(LeftOuterUnnestMapOperator op, Void arg) throws AlgebricksException {
getUsedVarsFromExprAndFilterExpr(op);
return null;
}
private void getUsedVarsFromExprAndFilterExpr(AbstractUnnestMapOperator op) {
op.getExpressionRef().getValue().getUsedVariables(usedVariables);
if (op.getAdditionalFilteringExpressions() != null) {
for (Mutable<ILogicalExpression> e : op.getAdditionalFilteringExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
}
}
@Override
public Void visitUnnestOperator(UnnestOperator op, Void arg) {
op.getExpressionRef().getValue().getUsedVariables(usedVariables);
return null;
}
@Override
public Void visitWriteOperator(WriteOperator op, Void arg) {
for (Mutable<ILogicalExpression> expr : op.getExpressions()) {
expr.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitDistributeResultOperator(DistributeResultOperator op, Void arg) {
for (Mutable<ILogicalExpression> expr : op.getExpressions()) {
expr.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitWriteResultOperator(WriteResultOperator op, Void arg) {
op.getPayloadExpression().getValue().getUsedVariables(usedVariables);
for (Mutable<ILogicalExpression> e : op.getKeyExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
if (op.getAdditionalFilteringExpressions() != null) {
for (Mutable<ILogicalExpression> e : op.getAdditionalFilteringExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
}
return null;
}
@Override
public Void visitInsertDeleteUpsertOperator(InsertDeleteUpsertOperator op, Void arg) {
// 1. The record variable
op.getPayloadExpression().getValue().getUsedVariables(usedVariables);
// 2. The primary key variables
for (Mutable<ILogicalExpression> e : op.getPrimaryKeyExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
// 3. The filters variables
if (op.getAdditionalFilteringExpressions() != null) {
for (Mutable<ILogicalExpression> e : op.getAdditionalFilteringExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
}
// 4. The Other variables (Not key, Not payload, and Not Filter)
if (op.getAdditionalNonFilteringExpressions() != null) {
for (Mutable<ILogicalExpression> e : op.getAdditionalNonFilteringExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
}
return null;
}
@Override
public Void visitIndexInsertDeleteUpsertOperator(IndexInsertDeleteUpsertOperator op, Void arg) {
for (Mutable<ILogicalExpression> e : op.getPrimaryKeyExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
for (Mutable<ILogicalExpression> e : op.getSecondaryKeyExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
if (op.getFilterExpression() != null) {
op.getFilterExpression().getValue().getUsedVariables(usedVariables);
}
if (op.getAdditionalFilteringExpressions() != null) {
for (Mutable<ILogicalExpression> e : op.getAdditionalFilteringExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
}
if (op.getPrevAdditionalFilteringExpression() != null) {
op.getPrevAdditionalFilteringExpression().getValue().getUsedVariables(usedVariables);
}
if (op.getPrevSecondaryKeyExprs() != null) {
for (Mutable<ILogicalExpression> e : op.getPrevSecondaryKeyExprs()) {
e.getValue().getUsedVariables(usedVariables);
}
}
return null;
}
@Override
public Void visitTokenizeOperator(TokenizeOperator op, Void arg) {
for (Mutable<ILogicalExpression> e : op.getPrimaryKeyExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
for (Mutable<ILogicalExpression> e : op.getSecondaryKeyExpressions()) {
e.getValue().getUsedVariables(usedVariables);
}
return null;
}
@Override
public Void visitSinkOperator(SinkOperator op, Void arg) {
return null;
}
@Override
public Void visitReplicateOperator(ReplicateOperator op, Void arg) throws AlgebricksException {
return null;
}
@Override
public Void visitSplitOperator(SplitOperator op, Void arg) throws AlgebricksException {
op.getBranchingExpression().getValue().getUsedVariables(usedVariables);
return null;
}
@Override
public Void visitRangeForwardOperator(RangeForwardOperator op, Void arg) throws AlgebricksException {
return null;
}
@Override
public Void visitMaterializeOperator(MaterializeOperator op, Void arg) throws AlgebricksException {
return null;
}
@Override
public Void visitExtensionOperator(ExtensionOperator op, Void arg) throws AlgebricksException {
op.getDelegate().getUsedVariables(usedVariables);
return null;
}
@Override
public Void visitLeftOuterUnnestOperator(LeftOuterUnnestOperator op, Void arg) throws AlgebricksException {
op.getExpressionRef().getValue().getUsedVariables(usedVariables);
return null;
}
}