Example usage for org.apache.commons.lang3.mutable Mutable getValue

List of usage examples for org.apache.commons.lang3.mutable Mutable getValue

Introduction

In this page you can find the example usage for org.apache.commons.lang3.mutable Mutable getValue.

Prototype

T getValue();

Source Link

Document

Gets the value of this mutable.

Usage

From source file:org.apache.asterix.optimizer.rules.InjectTypeCastForUnionRule.java

private boolean injectCast(UnionAllOperator op, int childIndex, IOptimizationContext context)
        throws AlgebricksException {
    // Gets the type environments for the union all operator and its child operator with the right child index.
    IVariableTypeEnvironment env = context.getOutputTypeEnvironment(op);
    Mutable<ILogicalOperator> branchOpRef = op.getInputs().get(childIndex);
    IVariableTypeEnvironment childEnv = context.getOutputTypeEnvironment(branchOpRef.getValue());

    // The two lists are used for the assign operator that calls cast functions.
    List<LogicalVariable> varsToCast = new ArrayList<>();
    List<Mutable<ILogicalExpression>> castFunctionsForLeft = new ArrayList<>();

    // Iterate through all triples.
    List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> triples = op.getVariableMappings();
    for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> triple : triples) {
        LogicalVariable producedVar = triple.third;
        IAType producedType = (IAType) env.getVarType(producedVar);
        LogicalVariable varToCast = childIndex == 0 ? triple.first : triple.second;
        IAType inputType = (IAType) childEnv.getVarType(varToCast);
        if (!TypeResolverUtil.needsCast(producedType, inputType)) {
            // Continues to the next triple if no cast is neeeded.
            continue;
        }/*from w  w w  . j a va 2  s.com*/
        LogicalVariable castedVar = context.newVar();
        // Resets triple variables to new variables that bind to the results of type casting.
        triple.first = childIndex == 0 ? castedVar : triple.first;
        triple.second = childIndex > 0 ? castedVar : triple.second;
        ScalarFunctionCallExpression castFunc = new ScalarFunctionCallExpression(
                FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CAST_TYPE), new ArrayList<>(Collections
                        .singletonList(new MutableObject<>(new VariableReferenceExpression(varToCast)))));
        TypeCastUtils.setRequiredAndInputTypes(castFunc, producedType, inputType);

        // Adds the variable and function expression into lists, for the assign operator.
        varsToCast.add(castedVar);
        castFunctionsForLeft.add(new MutableObject<>(castFunc));
    }
    if (castFunctionsForLeft.isEmpty()) {
        return false;
    }
    // Injects an assign operator to perform type casts.
    AssignOperator assignOp = new AssignOperator(varsToCast, castFunctionsForLeft);
    assignOp.getInputs().add(new MutableObject<>(branchOpRef.getValue()));
    branchOpRef.setValue(assignOp);
    context.computeAndSetTypeEnvironmentForOperator(assignOp);

    // Returns true to indicate that rewriting happens.
    return true;
}

From source file:org.apache.asterix.optimizer.rules.InlineUnnestFunctionRule.java

@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
        throws AlgebricksException {
    AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
    if (context.checkIfInDontApplySet(this, op1)) {
        return false;
    }/*from  www.j  a v  a  2  s . c  om*/
    context.addToDontApplySet(this, op1);
    if (op1.getOperatorTag() != LogicalOperatorTag.UNNEST) {
        return false;
    }
    UnnestOperator unnestOperator = (UnnestOperator) op1;
    AbstractFunctionCallExpression expr = (AbstractFunctionCallExpression) unnestOperator.getExpressionRef()
            .getValue();
    //we only inline for the scan-collection function
    if (expr.getFunctionIdentifier() != AsterixBuiltinFunctions.SCAN_COLLECTION) {
        return false;
    }

    // inline all variables from an unnesting function call
    AbstractFunctionCallExpression funcExpr = expr;
    List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
    for (int i = 0; i < args.size(); i++) {
        ILogicalExpression argExpr = args.get(i).getValue();
        if (argExpr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
            VariableReferenceExpression varExpr = (VariableReferenceExpression) argExpr;
            inlineVariable(varExpr.getVariableReference(), unnestOperator);
        }
    }
    return true;
}

From source file:org.apache.asterix.optimizer.rules.IntroduceAutogenerateIDRule.java

@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
        throws AlgebricksException {

    // match: commit OR distribute-result OR SINK - ... followed by:
    // [insert to internal dataset with autogenerated id] - assign - project
    // produce: insert - assign - assign* - project
    // **//from  w w w .j  av  a 2  s. co m
    // OR [insert to internal dataset with autogenerated id] - assign - [datasource scan]
    // produce insert - assign - assign* - datasource scan

    AbstractLogicalOperator currentOp = (AbstractLogicalOperator) opRef.getValue();
    if (currentOp.getOperatorTag() == LogicalOperatorTag.DELEGATE_OPERATOR) {
        DelegateOperator dOp = (DelegateOperator) currentOp;
        if (!(dOp.getDelegate() instanceof CommitOperator)) {
            return false;
        } else if (!((CommitOperator) dOp.getDelegate()).isSink()) {
            return false;
        }

    } else if (currentOp.getOperatorTag() != LogicalOperatorTag.DISTRIBUTE_RESULT
            && currentOp.getOperatorTag() != LogicalOperatorTag.SINK) {
        return false;
    }
    ArrayDeque<AbstractLogicalOperator> opStack = new ArrayDeque<>();
    opStack.push(currentOp);
    while (currentOp.getInputs().size() == 1) {
        currentOp = (AbstractLogicalOperator) currentOp.getInputs().get(0).getValue();
        if (currentOp.getOperatorTag() == LogicalOperatorTag.INSERT_DELETE_UPSERT) {
            break;
        }
        opStack.push(currentOp);
    }
    if (currentOp.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE_UPSERT) {
        return false;
    }

    InsertDeleteUpsertOperator insertOp = (InsertDeleteUpsertOperator) currentOp;
    if (insertOp.getOperation() != Kind.INSERT) {
        return false;
    }

    DatasetDataSource dds = (DatasetDataSource) insertOp.getDataSource();
    boolean autogenerated = ((InternalDatasetDetails) dds.getDataset().getDatasetDetails()).isAutogenerated();
    if (!autogenerated) {
        return false;
    }

    if (((AqlDataSource) insertOp.getDataSource()).getDatasourceType() != AqlDataSourceType.INTERNAL_DATASET) {
        return false;
    }

    AbstractLogicalOperator parentOp = (AbstractLogicalOperator) currentOp.getInputs().get(0).getValue();
    if (parentOp.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
        return false;
    }
    AssignOperator assignOp = (AssignOperator) parentOp;
    LogicalVariable inputRecord;

    //TODO: bug here. will not work for internal datasets with filters since the pattern becomes 
    //[project-assign-assign-insert]
    AbstractLogicalOperator grandparentOp = (AbstractLogicalOperator) parentOp.getInputs().get(0).getValue();
    if (grandparentOp.getOperatorTag() == LogicalOperatorTag.PROJECT) {
        ProjectOperator projectOp = (ProjectOperator) grandparentOp;
        inputRecord = projectOp.getVariables().get(0);
    } else if (grandparentOp.getOperatorTag() == LogicalOperatorTag.DATASOURCESCAN) {
        DataSourceScanOperator dssOp = (DataSourceScanOperator) grandparentOp;
        inputRecord = dssOp.getVariables().get(0);
    } else {
        return false;
    }

    List<String> pkFieldName = ((InternalDatasetDetails) dds.getDataset().getDatasetDetails()).getPrimaryKey()
            .get(0);
    ILogicalExpression rec0 = new VariableReferenceExpression(inputRecord);
    ILogicalExpression rec1 = createPrimaryKeyRecordExpression(pkFieldName);
    ILogicalExpression mergedRec = createRecordMergeFunction(rec0, rec1);
    ILogicalExpression nonNullMergedRec = createNotNullFunction(mergedRec);

    LogicalVariable v = context.newVar();
    AssignOperator newAssign = new AssignOperator(v, new MutableObject<ILogicalExpression>(nonNullMergedRec));
    newAssign.getInputs().add(new MutableObject<ILogicalOperator>(grandparentOp));
    assignOp.getInputs().set(0, new MutableObject<ILogicalOperator>(newAssign));
    VariableUtilities.substituteVariables(assignOp, inputRecord, v, context);
    VariableUtilities.substituteVariables(insertOp, inputRecord, v, context);
    context.computeAndSetTypeEnvironmentForOperator(newAssign);
    context.computeAndSetTypeEnvironmentForOperator(assignOp);
    context.computeAndSetTypeEnvironmentForOperator(insertOp);
    ;
    for (AbstractLogicalOperator op : opStack) {
        VariableUtilities.substituteVariables(op, inputRecord, v, context);
        context.computeAndSetTypeEnvironmentForOperator(op);
    }

    return true;
}

From source file:org.apache.asterix.optimizer.rules.IntroduceDynamicTypeCastForExternalFunctionRule.java

@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
        throws AlgebricksException {
    /**//w w w  .  j  av a2  s .c  o m
     * pattern match: distribute_result - project - assign (external function call) - assign (open_record_constructor)
     * resulting plan: distribute_result - project - assign (external function call) - assign (cast-record) - assign(open_record_constructor)
     */
    AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
    if (op1.getOperatorTag() != LogicalOperatorTag.DISTRIBUTE_RESULT) {
        return false;
    }
    AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
    if (op2.getOperatorTag() != LogicalOperatorTag.PROJECT) {
        return false;
    }
    AbstractLogicalOperator op3 = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
    if (op3.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
        return false;
    }
    AbstractLogicalOperator op4 = (AbstractLogicalOperator) op3.getInputs().get(0).getValue();
    if (op4.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
        return false;
    }

    // Op1 : assign (external function call), Op2 : assign (open_record_constructor)
    AssignOperator assignOp1 = (AssignOperator) op3;
    AssignOperator assignOp2 = (AssignOperator) op4;

    // Checks whether open-record-constructor is called to create a record in the first assign operator - assignOp2
    FunctionIdentifier fid = null;
    ILogicalExpression assignExpr = assignOp2.getExpressions().get(0).getValue();
    if (assignExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
        ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) assignOp2.getExpressions().get(0)
                .getValue();
        fid = funcExpr.getFunctionIdentifier();

        if (fid != AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR) {
            return false;
        }
    } else {
        return false;
    }

    // Checks whether an external function is called in the second assign operator - assignOp1
    assignExpr = assignOp1.getExpressions().get(0).getValue();
    ScalarFunctionCallExpression funcExpr = null;
    if (assignExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
        funcExpr = (ScalarFunctionCallExpression) assignOp1.getExpressions().get(0).getValue();
        fid = funcExpr.getFunctionIdentifier();

        // Checks whether this is an internal function call. Then, we return false.
        if (AsterixBuiltinFunctions.getBuiltinFunctionIdentifier(fid) != null) {
            return false;
        }

    } else {
        return false;
    }

    AsterixExternalScalarFunctionInfo finfo = (AsterixExternalScalarFunctionInfo) funcExpr.getFunctionInfo();
    ARecordType requiredRecordType = (ARecordType) finfo.getArgumenTypes().get(0);

    List<LogicalVariable> recordVar = new ArrayList<LogicalVariable>();
    recordVar.addAll(assignOp2.getVariables());

    IVariableTypeEnvironment env = assignOp2.computeOutputTypeEnvironment(context);
    IAType inputRecordType = (IAType) env.getVarType(recordVar.get(0));

    /** the input record type can be an union type -- for the case when it comes from a subplan or left-outer join */
    boolean checkUnknown = false;
    while (NonTaggedFormatUtil.isOptional(inputRecordType)) {
        /** while-loop for the case there is a nested multi-level union */
        inputRecordType = ((AUnionType) inputRecordType).getActualType();
        checkUnknown = true;
    }

    /** see whether the input record type needs to be casted */
    boolean cast = !IntroduceDynamicTypeCastRule.compatible(requiredRecordType, inputRecordType);

    if (checkUnknown) {
        recordVar.set(0, IntroduceDynamicTypeCastRule.addWrapperFunction(requiredRecordType, recordVar.get(0),
                assignOp1, context, AsterixBuiltinFunctions.CHECK_UNKNOWN));
    }
    if (cast) {
        IntroduceDynamicTypeCastRule.addWrapperFunction(requiredRecordType, recordVar.get(0), assignOp1,
                context, AsterixBuiltinFunctions.CAST_TYPE);
    }
    return cast || checkUnknown;
}

From source file:org.apache.asterix.optimizer.rules.IntroduceDynamicTypeCastRule.java

@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
        throws AlgebricksException {
    // Depending on the operator type, we need to extract the following pieces of information.
    AbstractLogicalOperator op;/*from  w  w  w  . j  a  v  a2s  .  c  o m*/
    ARecordType requiredRecordType;
    LogicalVariable recordVar;

    // We identify INSERT and DISTRIBUTE_RESULT operators.
    AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
    switch (op1.getOperatorTag()) {
    case SINK:
    case DELEGATE_OPERATOR: {
        /**
         * pattern match: commit insert assign
         * resulting plan: commit-insert-project-assign
         */
        if (op1.getOperatorTag() == LogicalOperatorTag.DELEGATE_OPERATOR) {
            DelegateOperator eOp = (DelegateOperator) op1;
            if (!(eOp.getDelegate() instanceof CommitOperator)) {
                return false;
            }
        }

        AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
        if (op2.getOperatorTag() == LogicalOperatorTag.INSERT_DELETE_UPSERT) {
            InsertDeleteUpsertOperator insertDeleteOp = (InsertDeleteUpsertOperator) op2;
            if (insertDeleteOp.getOperation() == InsertDeleteUpsertOperator.Kind.DELETE) {
                return false;
            }

            // Remember this is the operator we need to modify
            op = insertDeleteOp;

            // Derive the required ARecordType based on the schema of the AqlDataSource
            InsertDeleteUpsertOperator insertDeleteOperator = (InsertDeleteUpsertOperator) op2;
            AqlDataSource dataSource = (AqlDataSource) insertDeleteOperator.getDataSource();
            requiredRecordType = (ARecordType) dataSource.getItemType();

            // Derive the Variable which we will potentially wrap with cast/null functions
            ILogicalExpression expr = insertDeleteOperator.getPayloadExpression().getValue();
            List<LogicalVariable> payloadVars = new ArrayList<>();
            expr.getUsedVariables(payloadVars);
            recordVar = payloadVars.get(0);
        } else {
            return false;
        }

        break;
    }
    case DISTRIBUTE_RESULT: {
        // First, see if there was an output-record-type specified
        requiredRecordType = (ARecordType) op1.getAnnotations().get("output-record-type");
        if (requiredRecordType == null) {
            return false;
        }

        // Remember this is the operator we need to modify
        op = op1;

        recordVar = ((VariableReferenceExpression) ((DistributeResultOperator) op).getExpressions().get(0)
                .getValue()).getVariableReference();
        break;
    }
    default: {
        return false;
    }
    }

    // Derive the statically-computed type of the record
    IVariableTypeEnvironment env = op.computeOutputTypeEnvironment(context);
    IAType inputRecordType = (IAType) env.getVarType(recordVar);

    /** the input record type can be an union type -- for the case when it comes from a subplan or left-outer join */
    boolean checkUnknown = false;
    while (NonTaggedFormatUtil.isOptional(inputRecordType)) {
        /** while-loop for the case there is a nested multi-level union */
        inputRecordType = ((AUnionType) inputRecordType).getActualType();
        checkUnknown = true;
    }

    /** see whether the input record type needs to be casted */
    boolean cast = !compatible(requiredRecordType, inputRecordType);

    if (checkUnknown) {
        recordVar = addWrapperFunction(requiredRecordType, recordVar, op, context,
                AsterixBuiltinFunctions.CHECK_UNKNOWN);
    }
    if (cast) {
        addWrapperFunction(requiredRecordType, recordVar, op, context, AsterixBuiltinFunctions.CAST_TYPE);
    }
    return cast || checkUnknown;
}

From source file:org.apache.asterix.optimizer.rules.IntroduceDynamicTypeCastRule.java

/**
 * Inject a function to wrap a variable when necessary
 *
 * @param requiredRecordType//from   w  w w  . ja  v  a 2  s. c  om
 *            the required record type
 * @param recordVar
 *            the record variable
 * @param parent
 *            the current parent operator to be rewritten
 * @param context
 *            the optimization context
 * @param fd
 *            the function to be injected
 * @return true if cast is injected; false otherwise.
 * @throws AlgebricksException
 */
public static LogicalVariable addWrapperFunction(ARecordType requiredRecordType, LogicalVariable recordVar,
        ILogicalOperator parent, IOptimizationContext context, FunctionIdentifier fd)
        throws AlgebricksException {
    List<Mutable<ILogicalOperator>> opRefs = parent.getInputs();
    for (int index = 0; index < opRefs.size(); index++) {
        Mutable<ILogicalOperator> opRef = opRefs.get(index);
        ILogicalOperator op = opRef.getValue();

        /** get produced vars */
        List<LogicalVariable> producedVars = new ArrayList<LogicalVariable>();
        VariableUtilities.getProducedVariables(op, producedVars);
        IVariableTypeEnvironment env = op.computeOutputTypeEnvironment(context);
        for (int i = 0; i < producedVars.size(); i++) {
            LogicalVariable var = producedVars.get(i);
            if (var.equals(recordVar)) {
                /** insert an assign operator to call the function on-top-of the variable */
                IAType actualType = (IAType) env.getVarType(var);
                AbstractFunctionCallExpression cast = new ScalarFunctionCallExpression(
                        FunctionUtil.getFunctionInfo(fd));
                cast.getArguments()
                        .add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression(var)));
                /** enforce the required record type */
                TypeCastUtils.setRequiredAndInputTypes(cast, requiredRecordType, actualType);
                LogicalVariable newAssignVar = context.newVar();
                AssignOperator newAssignOperator = new AssignOperator(newAssignVar,
                        new MutableObject<ILogicalExpression>(cast));
                newAssignOperator.getInputs().add(new MutableObject<ILogicalOperator>(op));
                opRef.setValue(newAssignOperator);
                context.computeAndSetTypeEnvironmentForOperator(newAssignOperator);
                newAssignOperator.computeOutputTypeEnvironment(context);
                VariableUtilities.substituteVariables(parent, recordVar, newAssignVar, context);
                return newAssignVar;
            }
        }
        /** recursive descend to the operator who produced the recordVar */
        LogicalVariable replacedVar = addWrapperFunction(requiredRecordType, recordVar, op, context, fd);
        if (replacedVar != null) {
            /** substitute the recordVar by the replacedVar for operators who uses recordVar */
            VariableUtilities.substituteVariables(parent, recordVar, replacedVar, context);
            return replacedVar;
        }
    }
    return null;
}

From source file:org.apache.asterix.optimizer.rules.IntroduceEnforcedListTypeRule.java

private boolean rewriteExpressions(List<Mutable<ILogicalExpression>> expressions, IVariableTypeEnvironment env)
        throws AlgebricksException {
    boolean changed = false;
    for (Mutable<ILogicalExpression> exprRef : expressions) {
        ILogicalExpression expr = exprRef.getValue();
        if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
            AbstractFunctionCallExpression argFuncExpr = (AbstractFunctionCallExpression) expr;
            IAType exprType = (IAType) env.getType(argFuncExpr);
            if (StaticTypeCastUtil.rewriteListExpr(argFuncExpr, exprType, exprType, env)) {
                TypeCastUtils.resetRequiredAndInputTypes(argFuncExpr);
                changed = true;/*w w  w .jav a2 s.  c o  m*/
            }
        }
    }
    return changed;
}

From source file:org.apache.asterix.optimizer.rules.IntroduceMaterializationForInsertWithSelfScanRule.java

@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
        throws AlgebricksException {
    AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
    if (op.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE_UPSERT) {
        return false;
    }/*from   w  w w. ja  va2 s. c  o m*/

    InsertDeleteUpsertOperator insertOp = (InsertDeleteUpsertOperator) op;
    boolean sameDataset = checkIfInsertAndScanDatasetsSame(op,
            ((DatasetDataSource) insertOp.getDataSource()).getDataset().getDatasetName());

    if (sameDataset) {
        MaterializeOperator materializeOperator = new MaterializeOperator();
        MaterializePOperator materializePOperator = new MaterializePOperator(true);
        materializeOperator.setPhysicalOperator(materializePOperator);

        materializeOperator.getInputs()
                .add(new MutableObject<ILogicalOperator>(insertOp.getInputs().get(0).getValue()));
        context.computeAndSetTypeEnvironmentForOperator(materializeOperator);

        insertOp.getInputs().clear();
        insertOp.getInputs().add(new MutableObject<ILogicalOperator>(materializeOperator));
        context.computeAndSetTypeEnvironmentForOperator(insertOp);
        return true;
    } else {
        return false;
    }

}

From source file:org.apache.asterix.optimizer.rules.IntroduceRandomPartitioningFeedComputationRule.java

@Override
public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
        throws AlgebricksException {
    ILogicalOperator op = opRef.getValue();
    if (!op.getOperatorTag().equals(LogicalOperatorTag.ASSIGN)) {
        return false;
    }//from   w  w  w .  j av  a  2  s .co m

    ILogicalOperator opChild = op.getInputs().get(0).getValue();
    if (!opChild.getOperatorTag().equals(LogicalOperatorTag.DATASOURCESCAN)) {
        return false;
    }

    DataSourceScanOperator scanOp = (DataSourceScanOperator) opChild;
    AqlDataSource dataSource = (AqlDataSource) scanOp.getDataSource();
    if (dataSource.getDatasourceType() != AqlDataSourceType.FEED) {
        return false;
    }

    final FeedDataSource feedDataSource = (FeedDataSource) dataSource;
    Feed feed = feedDataSource.getFeed();
    if (feed.getAppliedFunction() == null) {
        return false;
    }

    ExchangeOperator exchangeOp = new ExchangeOperator();
    INodeDomain domain = new INodeDomain() {
        @Override
        public boolean sameAs(INodeDomain domain) {
            return domain == this;
        }

        @Override
        public Integer cardinality() {
            return feedDataSource.getComputeCardinality();
        }
    };

    exchangeOp.setPhysicalOperator(new RandomPartitionExchangePOperator(domain));
    op.getInputs().get(0).setValue(exchangeOp);
    exchangeOp.getInputs().add(new MutableObject<ILogicalOperator>(scanOp));
    ExecutionMode em = ((AbstractLogicalOperator) scanOp).getExecutionMode();
    exchangeOp.setExecutionMode(em);
    exchangeOp.computeDeliveredPhysicalProperties(context);
    context.computeAndSetTypeEnvironmentForOperator(exchangeOp);

    AssignOperator assignOp = (AssignOperator) opRef.getValue();
    AssignPOperator assignPhyOp = (AssignPOperator) assignOp.getPhysicalOperator();
    assignPhyOp.setCardinalityConstraint(domain.cardinality());

    return true;
}

From source file:org.apache.asterix.optimizer.rules.IntroduceSecondaryIndexInsertDeleteRule.java

@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
        throws AlgebricksException {
    AbstractLogicalOperator op0 = (AbstractLogicalOperator) opRef.getValue();
    if (op0.getOperatorTag() != LogicalOperatorTag.DELEGATE_OPERATOR
            && op0.getOperatorTag() != LogicalOperatorTag.SINK) {
        return false;
    }//from w  w w .  j  a  v a2  s  . c om
    if (op0.getOperatorTag() == LogicalOperatorTag.DELEGATE_OPERATOR) {
        DelegateOperator eOp = (DelegateOperator) op0;
        if (!(eOp.getDelegate() instanceof CommitOperator)) {
            return false;
        }
    }
    AbstractLogicalOperator op1 = (AbstractLogicalOperator) op0.getInputs().get(0).getValue();
    if (op1.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE_UPSERT) {
        return false;
    }
    /** find the record variable */
    InsertDeleteUpsertOperator primaryIndexModificationOp = (InsertDeleteUpsertOperator) op0.getInputs().get(0)
            .getValue();
    boolean isBulkload = primaryIndexModificationOp.isBulkload();
    ILogicalExpression newRecordExpr = primaryIndexModificationOp.getPayloadExpression().getValue();
    List<Mutable<ILogicalExpression>> newMetaExprs = primaryIndexModificationOp
            .getAdditionalNonFilteringExpressions();
    LogicalVariable newRecordVar;
    LogicalVariable newMetaVar = null;

    /**
     * inputOp is the assign operator which extracts primary keys from the input
     * variables (record or meta)
     */
    AbstractLogicalOperator inputOp = (AbstractLogicalOperator) primaryIndexModificationOp.getInputs().get(0)
            .getValue();
    newRecordVar = getRecordVar(context, inputOp, newRecordExpr, 0);
    if (newMetaExprs != null && !newMetaExprs.isEmpty()) {
        if (newMetaExprs.size() > 1) {
            throw new AlgebricksException(
                    "Number of meta records can't be more than 1. Number of meta records found = "
                            + newMetaExprs.size());
        }
        newMetaVar = getRecordVar(context, inputOp, newMetaExprs.get(0).getValue(), 1);
    }

    /*
     * At this point, we have the record variable and the insert/delete/upsert operator
     * Note: We have two operators:
     * 1. An InsertDeleteOperator (primary)
     * 2. An IndexInsertDeleteOperator (secondary)
     * The current primaryIndexModificationOp is of the first type
     */

    AqlDataSource datasetSource = (AqlDataSource) primaryIndexModificationOp.getDataSource();
    AqlMetadataProvider mp = (AqlMetadataProvider) context.getMetadataProvider();
    String dataverseName = datasetSource.getId().getDataverseName();
    String datasetName = datasetSource.getId().getDatasourceName();
    Dataset dataset = mp.findDataset(dataverseName, datasetName);
    if (dataset == null) {
        throw new AlgebricksException("Unknown dataset " + datasetName + " in dataverse " + dataverseName);
    }
    if (dataset.getDatasetType() == DatasetType.EXTERNAL) {
        return false;
    }

    // Create operators for secondary index insert / delete.
    String itemTypeName = dataset.getItemTypeName();
    IAType itemType = mp.findType(dataset.getItemTypeDataverseName(), itemTypeName);
    if (itemType.getTypeTag() != ATypeTag.RECORD) {
        throw new AlgebricksException("Only record types can be indexed.");
    }
    ARecordType recType = (ARecordType) itemType;
    // meta type
    ARecordType metaType = null;
    if (dataset.hasMetaPart()) {
        metaType = (ARecordType) mp.findType(dataset.getMetaItemTypeDataverseName(),
                dataset.getMetaItemTypeName());
    }
    List<Index> indexes = mp.getDatasetIndexes(dataset.getDataverseName(), dataset.getDatasetName());
    // Set the top operator pointer to the primary IndexInsertDeleteOperator
    ILogicalOperator currentTop = primaryIndexModificationOp;
    boolean hasSecondaryIndex = false;

    // Put an n-gram or a keyword index in the later stage of index-update,
    // since TokenizeOperator needs to be involved.
    Collections.sort(indexes, (o1, o2) -> o1.getIndexType().ordinal() - o2.getIndexType().ordinal());

    // At this point, we have the data type info, and the indexes info as well
    int secondaryIndexTotalCnt = indexes.size() - 1;
    if (secondaryIndexTotalCnt > 0) {
        op0.getInputs().clear();
    } else {
        return false;
    }
    // Initialize inputs to the SINK operator Op0 (The SINK) is now without input
    // Prepare filtering field information (This is the filter created using the "filter with" key word in the
    // create dataset ddl)
    List<String> filteringFields = ((InternalDatasetDetails) dataset.getDatasetDetails()).getFilterField();
    List<LogicalVariable> filteringVars;
    List<Mutable<ILogicalExpression>> filteringExpressions = null;

    if (filteringFields != null) {
        // The filter field var already exists. we can simply get it from the insert op
        filteringVars = new ArrayList<>();
        filteringExpressions = new ArrayList<>();
        for (Mutable<ILogicalExpression> filteringExpression : primaryIndexModificationOp
                .getAdditionalFilteringExpressions()) {
            filteringExpression.getValue().getUsedVariables(filteringVars);
            for (LogicalVariable var : filteringVars) {
                filteringExpressions
                        .add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression(var)));
            }
        }
    }

    // Replicate Operator is applied only when doing the bulk-load.
    ReplicateOperator replicateOp = null;
    if (secondaryIndexTotalCnt > 1 && primaryIndexModificationOp.isBulkload()) {
        // Split the logical plan into "each secondary index update branch"
        // to replicate each <PK,RECORD> pair.
        replicateOp = new ReplicateOperator(secondaryIndexTotalCnt);
        replicateOp.getInputs().add(new MutableObject<ILogicalOperator>(currentTop));
        replicateOp.setExecutionMode(ExecutionMode.PARTITIONED);
        context.computeAndSetTypeEnvironmentForOperator(replicateOp);
        currentTop = replicateOp;
    }

    /*
     * The two maps are used to store variables to which [casted] field access is assigned.
     * One for the beforeOp record and the other for the new record.
     * There are two uses for these maps:
     * 1. used for shared fields in indexes with overlapping keys.
     * 2. used for setting variables of secondary keys for each secondary index operator.
     */
    Map<IndexFieldId, LogicalVariable> fieldVarsForBeforeOperation = new HashMap<>();
    Map<IndexFieldId, LogicalVariable> fieldVarsForNewRecord = new HashMap<>();
    /*
     * if the index is enforcing field types (For open indexes), We add a cast
     * operator to ensure type safety
     */
    try {
        if (primaryIndexModificationOp.getOperation() == Kind.INSERT
                || primaryIndexModificationOp.getOperation() == Kind.UPSERT
                /* Actually, delete should not be here but it is now until issue
                 * https://issues.apache.org/jira/browse/ASTERIXDB-1507
                 * is solved
                 */
                || primaryIndexModificationOp.getOperation() == Kind.DELETE) {
            injectFieldAccessesForIndexes(context, dataset, indexes, fieldVarsForNewRecord, recType, metaType,
                    newRecordVar, newMetaVar, primaryIndexModificationOp, false);
            if (replicateOp != null) {
                context.computeAndSetTypeEnvironmentForOperator(replicateOp);
            }
        }
        if (primaryIndexModificationOp.getOperation() == Kind.UPSERT
        /* Actually, delete should be here but it is not until issue
         * https://issues.apache.org/jira/browse/ASTERIXDB-1507
         * is solved
         */) {
            List<LogicalVariable> beforeOpMetaVars = primaryIndexModificationOp
                    .getBeforeOpAdditionalNonFilteringVars();
            LogicalVariable beforeOpMetaVar = beforeOpMetaVars == null ? null : beforeOpMetaVars.get(0);
            currentTop = injectFieldAccessesForIndexes(context, dataset, indexes, fieldVarsForBeforeOperation,
                    recType, metaType, primaryIndexModificationOp.getBeforeOpRecordVar(), beforeOpMetaVar,
                    currentTop, true);
        }
    } catch (AsterixException e) {
        throw new AlgebricksException(e);
    }

    // Iterate each secondary index and applying Index Update operations.
    // At first, op1 is the index insert op insertOp
    for (Index index : indexes) {
        if (!index.isSecondaryIndex()) {
            continue;
        }
        hasSecondaryIndex = true;
        // Get the secondary fields names and types
        List<List<String>> secondaryKeyFields = index.getKeyFieldNames();
        List<LogicalVariable> secondaryKeyVars = new ArrayList<>();
        List<Mutable<ILogicalExpression>> secondaryExpressions = new ArrayList<>();
        List<Mutable<ILogicalExpression>> beforeOpSecondaryExpressions = new ArrayList<>();
        ILogicalOperator replicateOutput;

        for (int i = 0; i < secondaryKeyFields.size(); i++) {
            IndexFieldId indexFieldId = new IndexFieldId(index.getKeyFieldSourceIndicators().get(i),
                    secondaryKeyFields.get(i));
            LogicalVariable skVar = fieldVarsForNewRecord.get(indexFieldId);
            secondaryKeyVars.add(skVar);
            secondaryExpressions
                    .add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression(skVar)));
            if (primaryIndexModificationOp.getOperation() == Kind.UPSERT) {
                beforeOpSecondaryExpressions.add(new MutableObject<ILogicalExpression>(
                        new VariableReferenceExpression(fieldVarsForBeforeOperation.get(indexFieldId))));
            }
        }

        IndexInsertDeleteUpsertOperator indexUpdate;
        if (index.getIndexType() != IndexType.RTREE) {
            // Create an expression per key
            Mutable<ILogicalExpression> filterExpression = (primaryIndexModificationOp
                    .getOperation() == Kind.UPSERT) ? null
                            : createFilterExpression(secondaryKeyVars,
                                    context.getOutputTypeEnvironment(currentTop), index.isEnforcingKeyFileds());
            AqlIndex dataSourceIndex = new AqlIndex(index, dataverseName, datasetName, mp);

            // Introduce the TokenizeOperator only when doing bulk-load,
            // and index type is keyword or n-gram.
            if (index.getIndexType() != IndexType.BTREE && primaryIndexModificationOp.isBulkload()) {
                // Note: Bulk load case, we don't need to take care of it for upsert operation
                // Check whether the index is length-partitioned or not.
                // If partitioned, [input variables to TokenizeOperator,
                // token, number of token] pairs will be generated and
                // fed into the IndexInsertDeleteOperator.
                // If not, [input variables, token] pairs will be generated
                // and fed into the IndexInsertDeleteOperator.
                // Input variables are passed since TokenizeOperator is not an
                // filtering operator.
                boolean isPartitioned = index.getIndexType() == IndexType.LENGTH_PARTITIONED_WORD_INVIX
                        || index.getIndexType() == IndexType.LENGTH_PARTITIONED_NGRAM_INVIX;

                // Create a new logical variable - token
                List<LogicalVariable> tokenizeKeyVars = new ArrayList<>();
                List<Mutable<ILogicalExpression>> tokenizeKeyExprs = new ArrayList<>();
                LogicalVariable tokenVar = context.newVar();
                tokenizeKeyVars.add(tokenVar);
                tokenizeKeyExprs
                        .add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression(tokenVar)));

                // Check the field type of the secondary key.
                IAType secondaryKeyType;
                Pair<IAType, Boolean> keyPairType = Index.getNonNullableOpenFieldType(
                        index.getKeyFieldTypes().get(0), secondaryKeyFields.get(0), recType);
                secondaryKeyType = keyPairType.first;

                List<Object> varTypes = new ArrayList<>();
                varTypes.add(NonTaggedFormatUtil.getTokenType(secondaryKeyType));

                // If the index is a length-partitioned, then create
                // additional variable - number of token.
                // We use a special type for the length-partitioned index.
                // The type is short, and this does not contain type info.
                if (isPartitioned) {
                    LogicalVariable lengthVar = context.newVar();
                    tokenizeKeyVars.add(lengthVar);
                    tokenizeKeyExprs.add(
                            new MutableObject<ILogicalExpression>(new VariableReferenceExpression(lengthVar)));
                    varTypes.add(BuiltinType.SHORTWITHOUTTYPEINFO);
                }

                // TokenizeOperator to tokenize [SK, PK] pairs
                TokenizeOperator tokenUpdate = new TokenizeOperator(dataSourceIndex,
                        primaryIndexModificationOp.getPrimaryKeyExpressions(), secondaryExpressions,
                        tokenizeKeyVars, filterExpression, primaryIndexModificationOp.getOperation(),
                        primaryIndexModificationOp.isBulkload(), isPartitioned, varTypes);
                tokenUpdate.getInputs().add(new MutableObject<ILogicalOperator>(currentTop));
                context.computeAndSetTypeEnvironmentForOperator(tokenUpdate);
                replicateOutput = tokenUpdate;
                indexUpdate = new IndexInsertDeleteUpsertOperator(dataSourceIndex,
                        primaryIndexModificationOp.getPrimaryKeyExpressions(), tokenizeKeyExprs,
                        filterExpression, primaryIndexModificationOp.getOperation(),
                        primaryIndexModificationOp.isBulkload(),
                        primaryIndexModificationOp.getAdditionalNonFilteringExpressions() == null ? 0
                                : primaryIndexModificationOp.getAdditionalNonFilteringExpressions().size());
                indexUpdate.setAdditionalFilteringExpressions(filteringExpressions);
                indexUpdate.getInputs().add(new MutableObject<ILogicalOperator>(tokenUpdate));
            } else {
                // When TokenizeOperator is not needed
                indexUpdate = new IndexInsertDeleteUpsertOperator(dataSourceIndex,
                        primaryIndexModificationOp.getPrimaryKeyExpressions(), secondaryExpressions,
                        filterExpression, primaryIndexModificationOp.getOperation(),
                        primaryIndexModificationOp.isBulkload(),
                        primaryIndexModificationOp.getAdditionalNonFilteringExpressions() == null ? 0
                                : primaryIndexModificationOp.getAdditionalNonFilteringExpressions().size());
                indexUpdate.setAdditionalFilteringExpressions(filteringExpressions);
                replicateOutput = indexUpdate;
                // We add the necessary expressions for upsert
                if (primaryIndexModificationOp.getOperation() == Kind.UPSERT) {
                    indexUpdate.setBeforeOpSecondaryKeyExprs(beforeOpSecondaryExpressions);
                    if (filteringFields != null) {
                        indexUpdate.setBeforeOpAdditionalFilteringExpression(
                                new MutableObject<ILogicalExpression>(new VariableReferenceExpression(
                                        primaryIndexModificationOp.getBeforeOpFilterVar())));
                    }
                }
                indexUpdate.getInputs().add(new MutableObject<ILogicalOperator>(currentTop));
            }
        } else {
            // Get type, dimensions and number of keys
            Pair<IAType, Boolean> keyPairType = Index.getNonNullableOpenFieldType(
                    index.getKeyFieldTypes().get(0), secondaryKeyFields.get(0), recType);
            IAType spatialType = keyPairType.first;
            boolean isPointMBR = spatialType.getTypeTag() == ATypeTag.POINT
                    || spatialType.getTypeTag() == ATypeTag.POINT3D;
            int dimension = NonTaggedFormatUtil.getNumDimensions(spatialType.getTypeTag());
            int numKeys = (isPointMBR && isBulkload) ? dimension : dimension * 2;
            // Get variables and expressions
            List<LogicalVariable> keyVarList = new ArrayList<>();
            List<Mutable<ILogicalExpression>> keyExprList = new ArrayList<>();
            for (int i = 0; i < numKeys; i++) {
                LogicalVariable keyVar = context.newVar();
                keyVarList.add(keyVar);
                AbstractFunctionCallExpression createMBR = new ScalarFunctionCallExpression(
                        FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CREATE_MBR));
                createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
                        new VariableReferenceExpression(secondaryKeyVars.get(0))));
                createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
                        new ConstantExpression(new AsterixConstantValue(new AInt32(dimension)))));
                createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
                        new ConstantExpression(new AsterixConstantValue(new AInt32(i)))));
                keyExprList.add(new MutableObject<ILogicalExpression>(createMBR));
            }
            secondaryExpressions.clear();
            for (LogicalVariable secondaryKeyVar : keyVarList) {
                secondaryExpressions.add(new MutableObject<ILogicalExpression>(
                        new VariableReferenceExpression(secondaryKeyVar)));
            }
            if (isPointMBR && isBulkload) {
                //for PointMBR optimization: see SecondaryRTreeOperationsHelper.buildLoadingJobSpec() and
                //createFieldPermutationForBulkLoadOp(int) for more details.
                for (LogicalVariable secondaryKeyVar : keyVarList) {
                    secondaryExpressions.add(new MutableObject<ILogicalExpression>(
                            new VariableReferenceExpression(secondaryKeyVar)));
                }
            }
            AssignOperator assignCoordinates = new AssignOperator(keyVarList, keyExprList);
            assignCoordinates.getInputs().add(new MutableObject<ILogicalOperator>(currentTop));
            context.computeAndSetTypeEnvironmentForOperator(assignCoordinates);
            replicateOutput = assignCoordinates;
            Mutable<ILogicalExpression> filterExpression = null;
            AssignOperator originalAssignCoordinates = null;
            // We do something similar for beforeOp key if the operation is an upsert
            if (primaryIndexModificationOp.getOperation() == Kind.UPSERT) {
                List<LogicalVariable> originalKeyVarList = new ArrayList<>();
                List<Mutable<ILogicalExpression>> originalKeyExprList = new ArrayList<>();
                // we don't do any filtering since nulls are expected here and there
                for (int i = 0; i < numKeys; i++) {
                    LogicalVariable keyVar = context.newVar();
                    originalKeyVarList.add(keyVar);
                    AbstractFunctionCallExpression createMBR = new ScalarFunctionCallExpression(
                            FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CREATE_MBR));
                    createMBR.getArguments().add(beforeOpSecondaryExpressions.get(0));
                    createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
                            new ConstantExpression(new AsterixConstantValue(new AInt32(dimension)))));
                    createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
                            new ConstantExpression(new AsterixConstantValue(new AInt32(i)))));
                    originalKeyExprList.add(new MutableObject<ILogicalExpression>(createMBR));
                }
                beforeOpSecondaryExpressions.clear();
                for (LogicalVariable secondaryKeyVar : originalKeyVarList) {
                    beforeOpSecondaryExpressions.add(new MutableObject<ILogicalExpression>(
                            new VariableReferenceExpression(secondaryKeyVar)));
                }
                originalAssignCoordinates = new AssignOperator(originalKeyVarList, originalKeyExprList);
                originalAssignCoordinates.getInputs()
                        .add(new MutableObject<ILogicalOperator>(assignCoordinates));
                context.computeAndSetTypeEnvironmentForOperator(originalAssignCoordinates);
            } else {
                // We must enforce the filter if the originating spatial type is
                // nullable.
                boolean forceFilter = keyPairType.second;
                filterExpression = createFilterExpression(keyVarList,
                        context.getOutputTypeEnvironment(assignCoordinates), forceFilter);
            }
            AqlIndex dataSourceIndex = new AqlIndex(index, dataverseName, datasetName, mp);
            indexUpdate = new IndexInsertDeleteUpsertOperator(dataSourceIndex,
                    primaryIndexModificationOp.getPrimaryKeyExpressions(), secondaryExpressions,
                    filterExpression, primaryIndexModificationOp.getOperation(),
                    primaryIndexModificationOp.isBulkload(),
                    primaryIndexModificationOp.getAdditionalNonFilteringExpressions() == null ? 0
                            : primaryIndexModificationOp.getAdditionalNonFilteringExpressions().size());
            indexUpdate.setAdditionalFilteringExpressions(filteringExpressions);
            if (primaryIndexModificationOp.getOperation() == Kind.UPSERT) {
                // set before op secondary key expressions
                if (filteringFields != null) {
                    indexUpdate.setBeforeOpAdditionalFilteringExpression(
                            new MutableObject<ILogicalExpression>(new VariableReferenceExpression(
                                    primaryIndexModificationOp.getBeforeOpFilterVar())));
                }
                // set filtering expressions
                indexUpdate.setBeforeOpSecondaryKeyExprs(beforeOpSecondaryExpressions);
                // assign --> assign beforeOp values --> secondary index upsert
                indexUpdate.getInputs().add(new MutableObject<ILogicalOperator>(originalAssignCoordinates));
            } else {
                indexUpdate.getInputs().add(new MutableObject<ILogicalOperator>(assignCoordinates));
            }
        }
        context.computeAndSetTypeEnvironmentForOperator(indexUpdate);
        if (!primaryIndexModificationOp.isBulkload() || secondaryIndexTotalCnt == 1) {
            currentTop = indexUpdate;
        } else {
            replicateOp.getOutputs().add(new MutableObject<>(replicateOutput));
        }
        if (primaryIndexModificationOp.isBulkload()) {
            // For bulk load, we connect all fanned out insert operator to a single SINK operator
            op0.getInputs().add(new MutableObject<ILogicalOperator>(indexUpdate));
        }

    }
    if (!hasSecondaryIndex) {
        return false;
    }

    if (!primaryIndexModificationOp.isBulkload()) {
        // If this is an upsert, we need to
        // Remove the current input to the SINK operator (It is actually already removed above)
        op0.getInputs().clear();
        // Connect the last index update to the SINK
        op0.getInputs().add(new MutableObject<ILogicalOperator>(currentTop));
    }
    return true;
}