blob: 50bc07eec48ea8f87775cee2b4225406133e54d1 [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.vxquery.compiler.rewriter.rules.util;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.vxquery.compiler.algebricks.VXQueryConstantValue;
import org.apache.vxquery.context.StaticContext;
import org.apache.vxquery.datamodel.accessors.TaggedValuePointable;
import org.apache.vxquery.functions.BuiltinFunctions;
import org.apache.vxquery.functions.BuiltinOperators;
import org.apache.vxquery.functions.Function;
import org.apache.vxquery.types.AnyNodeType;
import org.apache.vxquery.types.Quantifier;
import org.apache.vxquery.types.SequenceType;
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.LogicalExpressionTag;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractAssignOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
import org.apache.hyracks.data.std.primitive.IntegerPointable;
public class ExpressionToolbox {
public static Mutable<ILogicalExpression> findVariableExpression(Mutable<ILogicalExpression> mutableLe,
LogicalVariable lv) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
VariableReferenceExpression vre = (VariableReferenceExpression) le;
if (vre.getVariableReference() == lv) {
return mutableLe;
}
} else if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
for (Mutable<ILogicalExpression> argExp : afce.getArguments()) {
Mutable<ILogicalExpression> resultLe = findVariableExpression(argExp, lv);
if (resultLe != null) {
return resultLe;
}
}
}
return null;
}
public static Mutable<ILogicalExpression> findVariableExpression(Mutable<ILogicalExpression> mutableLe) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
return mutableLe;
} else if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
for (Mutable<ILogicalExpression> argExp : afce.getArguments()) {
Mutable<ILogicalExpression> resultLe = findVariableExpression(argExp);
if (resultLe != null) {
return resultLe;
}
}
}
return null;
}
public static void findVariableExpressions(Mutable<ILogicalExpression> mutableLe,
List<Mutable<ILogicalExpression>> finds) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
finds.add(mutableLe);
} else if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
for (Mutable<ILogicalExpression> argExp : afce.getArguments()) {
findVariableExpressions(argExp, finds);
}
}
}
public static Mutable<ILogicalExpression> findLastFunctionExpression(Mutable<ILogicalExpression> mutableLe) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
return null;
} else if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
for (Mutable<ILogicalExpression> argExp : afce.getArguments()) {
if (argExp.getValue().getExpressionTag() == LogicalExpressionTag.VARIABLE) {
return mutableLe;
}
Mutable<ILogicalExpression> resultLe = findLastFunctionExpression(argExp);
if (resultLe != null) {
return resultLe;
}
}
}
return null;
}
public static Mutable<ILogicalExpression> findFirstFunctionExpression(Mutable<ILogicalExpression> mutableLe,
FunctionIdentifier fi) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
if (afce.getFunctionIdentifier().equals(fi)) {
return mutableLe;
}
for (Mutable<ILogicalExpression> argExp : afce.getArguments()) {
Mutable<ILogicalExpression> resultLe = findFirstFunctionExpression(argExp, fi);
if (resultLe != null) {
return resultLe;
}
}
}
return null;
}
/**
* Finds all functions for a given expression.
*
* @param mutableLe
* Search logical expression
* @param finds
* Logical expressions found
*/
public static void findAllFunctionExpressions(Mutable<ILogicalExpression> mutableLe,
List<Mutable<ILogicalExpression>> finds) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
finds.add(mutableLe);
for (Mutable<ILogicalExpression> argExp : afce.getArguments()) {
findAllFunctionExpressions(argExp, finds);
}
}
}
/**
* Finds all functions for a given expression and function identifier.
*
* @param mutableLe
* Search logical expression
* @param fi
* Function indentifier
* @param finds
* Logical expressions found
*/
public static void findAllFunctionExpressions(Mutable<ILogicalExpression> mutableLe, FunctionIdentifier fi,
List<Mutable<ILogicalExpression>> finds) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
if (afce.getFunctionIdentifier().equals(fi)) {
finds.add(mutableLe);
}
for (Mutable<ILogicalExpression> argExp : afce.getArguments()) {
findAllFunctionExpressions(argExp, fi, finds);
}
}
}
public static Function getBuiltIn(Mutable<ILogicalExpression> mutableLe) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) le;
for (Function function : BuiltinFunctions.FUNCTION_COLLECTION) {
if (function.getFunctionIdentifier().equals(afce.getFunctionIdentifier())) {
return function;
}
}
for (Function function : BuiltinOperators.OPERATOR_COLLECTION) {
if (function.getFunctionIdentifier().equals(afce.getFunctionIdentifier())) {
return function;
}
}
}
return null;
}
public static void getConstantAsPointable(ConstantExpression typeExpression, TaggedValuePointable tvp) {
VXQueryConstantValue treatTypeConstant = (VXQueryConstantValue) typeExpression.getValue();
tvp.set(treatTypeConstant.getValue(), 0, treatTypeConstant.getValue().length);
}
public static int getTypeExpressionTypeArgument(Mutable<ILogicalExpression> searchM) {
final int ARG_TYPE = 1;
AbstractFunctionCallExpression searchFunction = (AbstractFunctionCallExpression) searchM.getValue();
ILogicalExpression argType = searchFunction.getArguments().get(ARG_TYPE).getValue();
if (argType.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
return -1;
}
TaggedValuePointable tvp = (TaggedValuePointable) TaggedValuePointable.FACTORY.createPointable();
ExpressionToolbox.getConstantAsPointable((ConstantExpression) argType, tvp);
IntegerPointable pTypeCode = (IntegerPointable) IntegerPointable.FACTORY.createPointable();
tvp.getValue(pTypeCode);
return pTypeCode.getInteger();
}
public static Byte[] getConstantArgument(Mutable<ILogicalExpression> searchM, int arg) {
AbstractFunctionCallExpression searchFunction = (AbstractFunctionCallExpression) searchM.getValue();
ILogicalExpression argType = searchFunction.getArguments().get(arg).getValue();
searchFunction.getArguments().size();
if (argType.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
return null;
}
TaggedValuePointable tvp = (TaggedValuePointable) TaggedValuePointable.FACTORY.createPointable();
ExpressionToolbox.getConstantAsPointable((ConstantExpression) argType, tvp);
return ArrayUtils.toObject(tvp.getByteArray());
}
public static List<ILogicalExpression> getFullArguments(Mutable<ILogicalExpression> searchM) {
AbstractFunctionCallExpression searchFunction = (AbstractFunctionCallExpression) searchM.getValue();
ArrayList<ILogicalExpression> args = new ArrayList<ILogicalExpression>();
for (int i = 0; i < searchFunction.getArguments().size(); i++) {
args.add(searchFunction.getArguments().get(i).getValue());
}
return args;
}
public static SequenceType getTypeExpressionTypeArgument(Mutable<ILogicalExpression> searchM, StaticContext dCtx) {
int typeId = getTypeExpressionTypeArgument(searchM);
if (typeId > 0) {
return dCtx.lookupSequenceType(typeId);
} else {
return null;
}
}
public static SequenceType getOutputSequenceType(Mutable<ILogicalOperator> opRef,
Mutable<ILogicalExpression> argFirstM, StaticContext dCtx) {
ILogicalExpression argFirstLe = argFirstM.getValue();
switch (argFirstLe.getExpressionTag()) {
case FUNCTION_CALL:
// Only process defined functions.
Function function = ExpressionToolbox.getBuiltIn(argFirstM);
if (function == null) {
return null;
} else if (function.getFunctionIdentifier().equals(BuiltinOperators.CAST.getFunctionIdentifier())) {
// Special case since case has multiple type outputs.
return ExpressionToolbox.getTypeExpressionTypeArgument(argFirstM, dCtx);
} else {
return function.getSignature().getReturnType();
}
case CONSTANT:
// Consider constant values.
ConstantExpression constantExpression = (ConstantExpression) argFirstLe;
VXQueryConstantValue constantValue = (VXQueryConstantValue) constantExpression.getValue();
return constantValue.getType();
case VARIABLE:
VariableReferenceExpression variableRefExp = (VariableReferenceExpression) argFirstLe;
LogicalVariable variableId = variableRefExp.getVariableReference();
Mutable<ILogicalOperator> variableProducer = OperatorToolbox.findProducerOf(opRef, variableId);
if (variableProducer == null) {
return null;
}
AbstractLogicalOperator variableOp = (AbstractLogicalOperator) variableProducer.getValue();
switch (variableOp.getOperatorTag()) {
case ASSIGN:
case AGGREGATE:
case RUNNINGAGGREGATE:
AbstractAssignOperator assign = (AbstractAssignOperator) variableOp;
for (int i = 0; i < assign.getVariables().size(); ++i) {
if (variableId.equals(assign.getVariables().get(i))) {
return getOutputSequenceType(variableProducer, assign.getExpressions().get(i), dCtx);
}
}
return null;
case DATASOURCESCAN:
return SequenceType.create(AnyNodeType.INSTANCE, Quantifier.QUANT_ONE);
case UNNEST:
UnnestOperator unnest = (UnnestOperator) variableOp;
return getOutputSequenceType(variableProducer, unnest.getExpressionRef(), dCtx);
default:
// TODO Consider support for other operators. i.e. Assign.
break;
}
}
return null;
}
public static boolean isFunctionExpression(Mutable<ILogicalExpression> mutableLe,
AbstractFunctionCallExpression afce) {
ILogicalExpression le = mutableLe.getValue();
if (le.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
return false;
}
AbstractFunctionCallExpression fc = (AbstractFunctionCallExpression) le;
if (!fc.getFunctionIdentifier().equals(afce)) {
return false;
}
return true;
}
}