Search in sources :

Example 26 with ScalarFunctionCallExpression

use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.

the class EquivalenceClassUtils method addEquivalenceClassesForPrimaryIndexAccess.

/**
     * Adds equivalent classes for primary index accesses, including unnest-map for
     * primary index access and data source scan through primary index ---
     * one equivalent class between a primary key variable and a record field-access expression.
     *
     * @param operator
     *            , the primary index access operator.
     * @param indexSearchVars
     *            , the returned variables from primary index access. The last variable
     *            is the record variable.
     * @param recordType
     *            , the record type of an index payload record.
     * @param metaRecordType
     *            , the type of a meta record associated with an index payload record.
     * @param dataset
     *            , the accessed dataset.
     * @param context
     *            , the optimization context.
     * @throws AlgebricksException
     */
@SuppressWarnings("unchecked")
public static void addEquivalenceClassesForPrimaryIndexAccess(ILogicalOperator operator, List<LogicalVariable> indexSearchVars, ARecordType recordType, ARecordType metaRecordType, Dataset dataset, IOptimizationContext context) throws AlgebricksException {
    if (dataset.getDatasetDetails().getDatasetType() != DatasetType.INTERNAL) {
        return;
    }
    InternalDatasetDetails datasetDetails = (InternalDatasetDetails) dataset.getDatasetDetails();
    List<List<String>> primaryKey = datasetDetails.getPrimaryKey();
    Map<String, Integer> fieldNameToIndexMap = new HashMap<String, Integer>();
    String[] fieldNames = recordType.getFieldNames();
    for (int fieldIndex = 0; fieldIndex < fieldNames.length; ++fieldIndex) {
        fieldNameToIndexMap.put(fieldNames[fieldIndex], fieldIndex);
    }
    boolean hasMeta = dataset.hasMetaPart();
    Map<String, Integer> metaFieldNameToIndexMap = new HashMap<>();
    if (hasMeta) {
        String[] metaFieldNames = metaRecordType.getFieldNames();
        for (int metaFieldIndex = 0; metaFieldIndex < metaFieldNames.length; ++metaFieldIndex) {
            metaFieldNameToIndexMap.put(metaFieldNames[metaFieldIndex], metaFieldIndex);
        }
    }
    List<Integer> keySourceIndicators = datasetDetails.getKeySourceIndicator();
    LogicalVariable recordVar = hasMeta ? indexSearchVars.get(indexSearchVars.size() - 2) : indexSearchVars.get(indexSearchVars.size() - 1);
    LogicalVariable metaRecordVar = hasMeta ? indexSearchVars.get(indexSearchVars.size() - 1) : null;
    for (int pkIndex = 0; pkIndex < primaryKey.size(); ++pkIndex) {
        LogicalVariable referredRecordVar = recordVar;
        String pkFieldName = primaryKey.get(pkIndex).get(0);
        int source = keySourceIndicators.get(pkIndex);
        Integer fieldIndexInRecord;
        if (source == 0) {
            // The field is from the main record.
            fieldIndexInRecord = fieldNameToIndexMap.get(pkFieldName);
        } else {
            // The field is from the auxiliary meta record.
            referredRecordVar = metaRecordVar;
            fieldIndexInRecord = metaFieldNameToIndexMap.get(pkFieldName);
        }
        LogicalVariable var = indexSearchVars.get(pkIndex);
        ILogicalExpression expr = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.FIELD_ACCESS_BY_INDEX), new MutableObject<ILogicalExpression>(new VariableReferenceExpression(referredRecordVar)), new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(new AInt32(fieldIndexInRecord)))));
        EquivalenceClass equivClass = new EquivalenceClass(Collections.singletonList(var), var, Collections.singletonList(expr));
        Map<LogicalVariable, EquivalenceClass> equivalenceMap = context.getEquivalenceClassMap(operator);
        if (equivalenceMap == null) {
            equivalenceMap = new HashMap<LogicalVariable, EquivalenceClass>();
            context.putEquivalenceClassMap(operator, equivalenceMap);
        }
        equivalenceMap.put(var, equivClass);
    }
}
Also used : LogicalVariable(org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable) HashMap(java.util.HashMap) InternalDatasetDetails(org.apache.asterix.metadata.entities.InternalDatasetDetails) ConstantExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression) AInt32(org.apache.asterix.om.base.AInt32) ILogicalExpression(org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression) AsterixConstantValue(org.apache.asterix.om.constants.AsterixConstantValue) VariableReferenceExpression(org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression) ArrayList(java.util.ArrayList) List(java.util.List) EquivalenceClass(org.apache.hyracks.algebricks.core.algebra.base.EquivalenceClass) ScalarFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression)

Example 27 with ScalarFunctionCallExpression

use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.

the class LangExpressionToPlanTranslator method visit.

@Override
public Pair<ILogicalOperator, LogicalVariable> visit(RecordConstructor rc, Mutable<ILogicalOperator> tupSource) throws CompilationException {
    AbstractFunctionCallExpression f = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR));
    LogicalVariable v1 = context.newVar();
    AssignOperator a = new AssignOperator(v1, new MutableObject<>(f));
    Mutable<ILogicalOperator> topOp = tupSource;
    for (FieldBinding fb : rc.getFbList()) {
        Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo1 = langExprToAlgExpression(fb.getLeftExpr(), topOp);
        f.getArguments().add(new MutableObject<>(eo1.first));
        topOp = eo1.second;
        Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo2 = langExprToAlgExpression(fb.getRightExpr(), topOp);
        f.getArguments().add(new MutableObject<>(eo2.first));
        topOp = eo2.second;
    }
    a.getInputs().add(topOp);
    return new Pair<>(a, v1);
}
Also used : LogicalVariable(org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable) Mutable(org.apache.commons.lang3.mutable.Mutable) ILogicalExpression(org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression) AbstractFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression) ILogicalOperator(org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator) FieldBinding(org.apache.asterix.lang.common.expression.FieldBinding) AssignOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator) ScalarFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression) GbyVariableExpressionPair(org.apache.asterix.lang.common.expression.GbyVariableExpressionPair) Pair(org.apache.hyracks.algebricks.common.utils.Pair) QuantifiedPair(org.apache.asterix.lang.common.struct.QuantifiedPair)

Example 28 with ScalarFunctionCallExpression

use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.

the class LangExpressionToPlanTranslator method generateNoMatchedPrecedingWhenBranchesFilter.

// Generates the filter condition for whether a conditional branch should be executed.
protected Mutable<ILogicalExpression> generateNoMatchedPrecedingWhenBranchesFilter(List<ILogicalExpression> inputBooleanExprs) {
    List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
    for (ILogicalExpression inputBooleanExpr : inputBooleanExprs) {
        // A NULL/MISSING valued WHEN expression does not lead to the corresponding THEN execution.
        // Therefore, we should check a previous WHEN boolean condition is not unknown.
        arguments.add(generateAndNotIsUnknownWrap(inputBooleanExpr));
    }
    Mutable<ILogicalExpression> hasBeenExecutedExprRef = new MutableObject<>(new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.OR), arguments));
    return new MutableObject<>(new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.NOT), new ArrayList<>(Collections.singletonList(hasBeenExecutedExprRef))));
}
Also used : Mutable(org.apache.commons.lang3.mutable.Mutable) ILogicalExpression(org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression) ArrayList(java.util.ArrayList) MutableObject(org.apache.commons.lang3.mutable.MutableObject) ScalarFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression)

Example 29 with ScalarFunctionCallExpression

use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.

the class StaticTypeCastUtil method injectCastToRelaxType.

private static boolean injectCastToRelaxType(Mutable<ILogicalExpression> expRef, IAType inputFieldType, IVariableTypeEnvironment env) throws AlgebricksException {
    ILogicalExpression argExpr = expRef.getValue();
    List<LogicalVariable> parameterVars = new ArrayList<LogicalVariable>();
    argExpr.getUsedVariables(parameterVars);
    // we need to handle open fields recursively by their default
    // types
    // for list, their item type is any
    // for record, their
    boolean castInjected = false;
    if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL || argExpr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
        IAType reqFieldType = inputFieldType;
        // do not enforce nested type in the case of no-used variables
        switch(inputFieldType.getTypeTag()) {
            case OBJECT:
                reqFieldType = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
                break;
            case ARRAY:
                reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
                break;
            case MULTISET:
                reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
                break;
            default:
                break;
        }
        // do not enforce nested type in the case of no-used variables
        if (!inputFieldType.equals(reqFieldType) && !parameterVars.isEmpty()) {
            //inject dynamic type casting
            injectCastFunction(FunctionUtil.getFunctionInfo(BuiltinFunctions.CAST_TYPE), reqFieldType, inputFieldType, expRef, argExpr);
            castInjected = true;
        }
        //recursively rewrite function arguments
        if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL && TypeCastUtils.getRequiredType((AbstractFunctionCallExpression) argExpr) == null && reqFieldType != null) {
            if (castInjected) {
                //rewrite the arg expression inside the dynamic cast
                ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) argExpr;
                rewriteFuncExpr(argFunc, inputFieldType, inputFieldType, env);
            } else {
                //rewrite arg
                ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) argExpr;
                rewriteFuncExpr(argFunc, reqFieldType, inputFieldType, env);
            }
        }
    }
    return castInjected;
}
Also used : LogicalVariable(org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable) ILogicalExpression(org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression) AbstractFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression) ArrayList(java.util.ArrayList) IAType(org.apache.asterix.om.types.IAType) ScalarFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression)

Example 30 with ScalarFunctionCallExpression

use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.

the class StaticTypeCastUtil method staticRecordTypeCast.

/**
     * This method statically cast the type of records from their current type to the required type.
     *
     * @param func
     *            The record constructor expression.
     * @param reqType
     *            The required type.
     * @param inputType
     *            The current type.
     * @param env
     *            The type environment.
     * @throws AlgebricksException
     */
private static boolean staticRecordTypeCast(AbstractFunctionCallExpression func, ARecordType reqType, ARecordType inputType, IVariableTypeEnvironment env) throws AlgebricksException {
    if (!(func.getFunctionIdentifier() == BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR || func.getFunctionIdentifier() == BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR)) {
        return false;
    }
    IAType[] reqFieldTypes = reqType.getFieldTypes();
    String[] reqFieldNames = reqType.getFieldNames();
    IAType[] inputFieldTypes = inputType.getFieldTypes();
    String[] inputFieldNames = inputType.getFieldNames();
    int[] fieldPermutation = new int[reqFieldTypes.length];
    boolean[] nullFields = new boolean[reqFieldTypes.length];
    boolean[] openFields = new boolean[inputFieldTypes.length];
    Arrays.fill(nullFields, false);
    Arrays.fill(openFields, true);
    Arrays.fill(fieldPermutation, -1);
    // forward match: match from actual to required
    boolean matched = false;
    for (int i = 0; i < inputFieldNames.length; i++) {
        String fieldName = inputFieldNames[i];
        IAType fieldType = inputFieldTypes[i];
        if (2 * i + 1 > func.getArguments().size()) {
            // it is not a record constructor function
            return false;
        }
        // 2*i+1 is the index of field value expression
        ILogicalExpression arg = func.getArguments().get(2 * i + 1).getValue();
        matched = false;
        for (int j = 0; j < reqFieldNames.length; j++) {
            String reqFieldName = reqFieldNames[j];
            IAType reqFieldType = reqFieldTypes[j];
            if (fieldName.equals(reqFieldName)) {
                //type matched
                if (fieldType.equals(reqFieldType)) {
                    fieldPermutation[j] = i;
                    openFields[i] = false;
                    matched = true;
                    if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                        ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
                        rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
                    }
                    break;
                }
                // match the optional field
                if (NonTaggedFormatUtil.isOptional(reqFieldType)) {
                    IAType itemType = ((AUnionType) reqFieldType).getActualType();
                    reqFieldType = itemType;
                    if (fieldType.equals(BuiltinType.AMISSING) || fieldType.equals(itemType)) {
                        fieldPermutation[j] = i;
                        openFields[i] = false;
                        matched = true;
                        // rewrite record expr
                        if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                            ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
                            rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
                        }
                        break;
                    }
                }
                // delay that to runtime by calling the not-null function
                if (NonTaggedFormatUtil.isOptional(fieldType)) {
                    IAType itemType = ((AUnionType) fieldType).getActualType();
                    if (reqFieldType.equals(itemType)) {
                        fieldPermutation[j] = i;
                        openFields[i] = false;
                        matched = true;
                        ScalarFunctionCallExpression notNullFunc = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CHECK_UNKNOWN));
                        notNullFunc.getArguments().add(new MutableObject<ILogicalExpression>(arg));
                        //wrap the not null function to the original function
                        func.getArguments().get(2 * i + 1).setValue(notNullFunc);
                        break;
                    }
                }
                // match the record field: need cast
                if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                    ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
                    rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
                    fieldPermutation[j] = i;
                    openFields[i] = false;
                    matched = true;
                    break;
                }
            }
        }
        // the input has extra fields
        if (!matched && !reqType.isOpen()) {
            throw new AlgebricksException("static type mismatch: the input record includes an extra closed field " + fieldName + ":" + fieldType + "! Please check the field name and type.");
        }
    }
    // backward match: match from required to actual
    for (int i = 0; i < reqFieldNames.length; i++) {
        String reqFieldName = reqFieldNames[i];
        IAType reqFieldType = reqFieldTypes[i];
        matched = false;
        for (int j = 0; j < inputFieldNames.length; j++) {
            String fieldName = inputFieldNames[j];
            IAType fieldType = inputFieldTypes[j];
            if (!fieldName.equals(reqFieldName)) {
                continue;
            }
            // the entry index of fieldPermuatons is req field index
            if (!openFields[j]) {
                matched = true;
                break;
            }
            // match the optional field
            if (!NonTaggedFormatUtil.isOptional(reqFieldType)) {
                continue;
            }
            IAType itemType = ((AUnionType) reqFieldType).getActualType();
            if (fieldType.equals(BuiltinType.AMISSING) || fieldType.equals(itemType)) {
                matched = true;
                break;
            }
        }
        if (matched) {
            continue;
        }
        if (NonTaggedFormatUtil.isOptional(reqFieldType)) {
            // add a null field
            nullFields[i] = true;
        } else {
            // no matched field in the input for a required closed field
            if (inputType.isOpen()) {
                //if the input type is open, return false, give that to dynamic type cast to defer the error to the runtime
                return false;
            } else {
                throw new AlgebricksException("static type mismatch: the input record misses a required closed field " + reqFieldName + ":" + reqFieldType + "! Please check the field name and type.");
            }
        }
    }
    List<Mutable<ILogicalExpression>> arguments = func.getArguments();
    List<Mutable<ILogicalExpression>> originalArguments = new ArrayList<Mutable<ILogicalExpression>>();
    originalArguments.addAll(arguments);
    arguments.clear();
    // re-order the closed part and fill in null fields
    for (int i = 0; i < fieldPermutation.length; i++) {
        int pos = fieldPermutation[i];
        if (pos >= 0) {
            arguments.add(originalArguments.get(2 * pos));
            arguments.add(originalArguments.get(2 * pos + 1));
        }
        if (nullFields[i]) {
            // add a null field
            arguments.add(new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(new AString(reqFieldNames[i])))));
            arguments.add(new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(ANull.NULL))));
        }
    }
    // add the open part
    for (int i = 0; i < openFields.length; i++) {
        if (openFields[i]) {
            arguments.add(originalArguments.get(2 * i));
            Mutable<ILogicalExpression> expRef = originalArguments.get(2 * i + 1);
            injectCastToRelaxType(expRef, inputFieldTypes[i], env);
            arguments.add(expRef);
        }
    }
    return true;
}
Also used : AUnionType(org.apache.asterix.om.types.AUnionType) ConstantExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression) AlgebricksException(org.apache.hyracks.algebricks.common.exceptions.AlgebricksException) ArrayList(java.util.ArrayList) AString(org.apache.asterix.om.base.AString) Mutable(org.apache.commons.lang3.mutable.Mutable) ILogicalExpression(org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression) AsterixConstantValue(org.apache.asterix.om.constants.AsterixConstantValue) AString(org.apache.asterix.om.base.AString) IAType(org.apache.asterix.om.types.IAType) ScalarFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression)

Aggregations

ScalarFunctionCallExpression (org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression)71 ILogicalExpression (org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression)57 Mutable (org.apache.commons.lang3.mutable.Mutable)48 ArrayList (java.util.ArrayList)38 LogicalVariable (org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable)38 VariableReferenceExpression (org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression)34 AbstractFunctionCallExpression (org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression)31 ILogicalOperator (org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator)26 ConstantExpression (org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression)26 AssignOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator)26 MutableObject (org.apache.commons.lang3.mutable.MutableObject)25 AsterixConstantValue (org.apache.asterix.om.constants.AsterixConstantValue)22 AString (org.apache.asterix.om.base.AString)14 IAType (org.apache.asterix.om.types.IAType)14 IFunctionInfo (org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo)14 Pair (org.apache.hyracks.algebricks.common.utils.Pair)13 GbyVariableExpressionPair (org.apache.asterix.lang.common.expression.GbyVariableExpressionPair)10 AInt32 (org.apache.asterix.om.base.AInt32)10 SelectOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator)10 QuantifiedPair (org.apache.asterix.lang.common.struct.QuantifiedPair)8