blob: ba396f4629e167eea56ce31d2430be00c5e0001e [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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
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.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.LogicalExpressionTag;
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.IVariableTypeEnvironment;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.properties.TypePropagationPolicy;
import edu.uci.ics.hyracks.algebricks.core.algebra.properties.VariablePropagationPolicy;
import edu.uci.ics.hyracks.algebricks.core.algebra.typing.ITypeEnvPointer;
import edu.uci.ics.hyracks.algebricks.core.algebra.typing.ITypingContext;
import edu.uci.ics.hyracks.algebricks.core.algebra.typing.OpRefTypeEnvPointer;
import edu.uci.ics.hyracks.algebricks.core.algebra.typing.PropagatingTypeEnvironment;
import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionReferenceTransform;
import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
public class GroupByOperator extends AbstractOperatorWithNestedPlans {
// If the LogicalVariable in a pair is null, it means that the GroupBy is
// only grouping by the expression, without producing a new variable.
private final List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> gByList;
private final List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> decorList;
// In decorList, if the variable (first member of the pair) is null, the
// second member of the pair is variable reference which is propagated.
public GroupByOperator() {
super();
gByList = new ArrayList<Pair<LogicalVariable, Mutable<ILogicalExpression>>>();
decorList = new ArrayList<Pair<LogicalVariable, Mutable<ILogicalExpression>>>();
}
public GroupByOperator(List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> groupByList,
List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> decorList, List<ILogicalPlan> nestedPlans) {
super(nestedPlans);
this.decorList = decorList;
this.gByList = groupByList;
}
public void addGbyExpression(LogicalVariable variable, ILogicalExpression expression) {
this.gByList.add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(variable,
new MutableObject<ILogicalExpression>(expression)));
}
public void addDecorExpression(LogicalVariable variable, ILogicalExpression expression) {
this.decorList.add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(variable,
new MutableObject<ILogicalExpression>(expression)));
}
@Override
public LogicalOperatorTag getOperatorTag() {
return LogicalOperatorTag.GROUP;
}
public List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> getGroupByList() {
return gByList;
}
public String gByListToString() {
return veListToString(gByList);
}
public String decorListToString() {
return veListToString(decorList);
}
public List<LogicalVariable> getGbyVarList() {
List<LogicalVariable> varList = new ArrayList<LogicalVariable>(gByList.size());
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> ve : gByList) {
ILogicalExpression expr = ve.second.getValue();
if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
VariableReferenceExpression v = (VariableReferenceExpression) expr;
varList.add(v.getVariableReference());
}
}
return varList;
}
public static String veListToString(List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> vePairList) {
StringBuilder sb = new StringBuilder();
sb.append("[");
boolean fst = true;
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> ve : vePairList) {
if (fst) {
fst = false;
} else {
sb.append("; ");
}
if (ve.first != null) {
sb.append(ve.first + " := " + ve.second);
} else {
sb.append(ve.second.getValue());
}
}
sb.append("]");
return sb.toString();
}
@Override
public void recomputeSchema() {
super.recomputeSchema();
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
schema.add(p.first);
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : decorList) {
schema.add(getDecorVariable(p));
}
}
@Override
public void getProducedVariablesExceptNestedPlans(Collection<LogicalVariable> vars) {
// super.getProducedVariables(vars);
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
if (p.first != null) {
vars.add(p.first);
}
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : decorList) {
if (p.first != null) {
vars.add(p.first);
}
}
}
@Override
public void getUsedVariablesExceptNestedPlans(Collection<LogicalVariable> vars) {
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> g : gByList) {
g.second.getValue().getUsedVariables(vars);
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> g : decorList) {
g.second.getValue().getUsedVariables(vars);
}
// super.getUsedVariables(vars);
}
@Override
public VariablePropagationPolicy getVariablePropagationPolicy() {
return new VariablePropagationPolicy() {
@Override
public void propagateVariables(IOperatorSchema target, IOperatorSchema... sources)
throws AlgebricksException {
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
ILogicalExpression expr = p.second.getValue();
if (p.first != null) {
target.addVariable(p.first);
} else {
if (expr.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
throw new AlgebricksException("hash group-by expects variable references.");
}
VariableReferenceExpression v = (VariableReferenceExpression) expr;
target.addVariable(v.getVariableReference());
}
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : decorList) {
ILogicalExpression expr = p.second.getValue();
if (expr.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
throw new AlgebricksException("pre-sorted group-by expects variable references.");
}
VariableReferenceExpression v = (VariableReferenceExpression) expr;
LogicalVariable decor = v.getVariableReference();
if (p.first != null) {
target.addVariable(p.first);
} else {
target.addVariable(decor);
}
}
}
};
}
@Override
public boolean acceptExpressionTransform(ILogicalExpressionReferenceTransform visitor) throws AlgebricksException {
boolean b = false;
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
if (visitor.transform(p.second)) {
b = true;
}
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : decorList) {
if (visitor.transform(p.second)) {
b = true;
}
}
return b;
}
@Override
public <R, T> R accept(ILogicalOperatorVisitor<R, T> visitor, T arg) throws AlgebricksException {
return visitor.visitGroupByOperator(this, arg);
}
public static LogicalVariable getDecorVariable(Pair<LogicalVariable, Mutable<ILogicalExpression>> p) {
if (p.first != null) {
return p.first;
} else {
VariableReferenceExpression e = (VariableReferenceExpression) p.second.getValue();
return e.getVariableReference();
}
}
public List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> getDecorList() {
return decorList;
}
@Override
public IVariableTypeEnvironment computeOutputTypeEnvironment(ITypingContext ctx) throws AlgebricksException {
int n = 0;
for (ILogicalPlan p : nestedPlans) {
n += p.getRoots().size();
}
ITypeEnvPointer[] envPointers = new ITypeEnvPointer[n];
int i = 0;
for (ILogicalPlan p : nestedPlans) {
for (Mutable<ILogicalOperator> r : p.getRoots()) {
envPointers[i] = new OpRefTypeEnvPointer(r, ctx);
i++;
}
}
IVariableTypeEnvironment env = new PropagatingTypeEnvironment(ctx.getExpressionTypeComputer(),
ctx.getNullableTypeComputer(), ctx.getMetadataProvider(), TypePropagationPolicy.ALL, envPointers);
ILogicalOperator child = inputs.get(0).getValue();
IVariableTypeEnvironment env2 = ctx.getOutputTypeEnvironment(child);
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : getGroupByList()) {
ILogicalExpression expr = p.second.getValue();
if (p.first != null) {
env.setVarType(p.first, env2.getType(expr));
if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
LogicalVariable v1 = ((VariableReferenceExpression) expr).getVariableReference();
env.setVarType(v1, env2.getVarType(v1));
}
} else {
VariableReferenceExpression vre = (VariableReferenceExpression) p.second.getValue();
LogicalVariable v2 = vre.getVariableReference();
env.setVarType(v2, env2.getVarType(v2));
}
}
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : getDecorList()) {
ILogicalExpression expr = p.second.getValue();
if (p.first != null) {
env.setVarType(p.first, env2.getType(expr));
} else {
VariableReferenceExpression vre = (VariableReferenceExpression) p.second.getValue();
LogicalVariable v2 = vre.getVariableReference();
env.setVarType(v2, env2.getVarType(v2));
}
}
return env;
}
}