blob: 958f5f6ab52652655b50819a66eb21e21a373a53 [file] [log] [blame]
package edu.uci.ics.asterix.optimizer.rules;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
import edu.uci.ics.asterix.metadata.declared.AqlDataSource;
import edu.uci.ics.asterix.om.typecomputer.base.TypeComputerUtilities;
import edu.uci.ics.asterix.om.types.ARecordType;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
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.IOptimizationContext;
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.AbstractFunctionCallExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
public class TopDownTypeInferenceRule implements IAlgebraicRewriteRule {
@Override
public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
return false;
}
@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
throws AlgebricksException {
/**
* pattern match: sink/insert/assign
* record type is propagated from insert data source to the record-constructor expression
*/
AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
if (op1.getOperatorTag() != LogicalOperatorTag.SINK)
return false;
AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
if (op2.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE)
return false;
AbstractLogicalOperator op3 = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
if (op3.getOperatorTag() != LogicalOperatorTag.ASSIGN)
return false;
/**
* get required record type
*/
InsertDeleteOperator insertDeleteOperator = (InsertDeleteOperator) op2;
AssignOperator oldAssignOperator = (AssignOperator) op3;
AqlDataSource dataSource = (AqlDataSource) insertDeleteOperator.getDataSource();
IAType[] schemaTypes = (IAType[]) dataSource.getSchemaTypes();
ARecordType requiredRecordType = (ARecordType) schemaTypes[schemaTypes.length - 1];
/**
* get input record type to the insert operator
*/
List<LogicalVariable> usedVariables = new ArrayList<LogicalVariable>();
VariableUtilities.getUsedVariables(oldAssignOperator, usedVariables);
if (usedVariables.size() == 0)
return false;
LogicalVariable oldRecordVariable = usedVariables.get(0);
LogicalVariable inputRecordVar = usedVariables.get(0);
IVariableTypeEnvironment env = oldAssignOperator.computeOutputTypeEnvironment(context);
ARecordType inputRecordType = (ARecordType) env.getVarType(inputRecordVar);
AbstractLogicalOperator currentOperator = oldAssignOperator;
List<LogicalVariable> producedVariables = new ArrayList<LogicalVariable>();
boolean changed = false;
if (!requiredRecordType.equals(inputRecordType)) {
/**
* find the assign operator for the "input record" to the
* insert_delete operator
*/
do {
if (currentOperator.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
producedVariables.clear();
VariableUtilities.getProducedVariables(currentOperator, producedVariables);
int position = producedVariables.indexOf(oldRecordVariable);
/**
* set the top-down propagated type
*/
if (position >= 0) {
AssignOperator originalAssign = (AssignOperator) currentOperator;
List<Mutable<ILogicalExpression>> expressionPointers = originalAssign.getExpressions();
ILogicalExpression expr = expressionPointers.get(position).getValue();
if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) expr;
changed = TypeComputerUtilities.setRequiredType(funcExpr, requiredRecordType);
List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
int openPartStart = requiredRecordType.getFieldTypes().length * 2;
for (int j = openPartStart; j < args.size(); j++) {
ILogicalExpression arg = args.get(j).getValue();
if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression argFunc = (AbstractFunctionCallExpression) arg;
TypeComputerUtilities.setOpenType(argFunc, true);
}
}
}
}
}
if (currentOperator.getInputs().size() > 0)
currentOperator = (AbstractLogicalOperator) currentOperator.getInputs().get(0).getValue();
else
break;
} while (currentOperator != null);
}
return changed;
}
}