@Override public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { AbstractLogicalOperator unnest = (AbstractLogicalOperator) opRef.getValue(); if (unnest.getOperatorTag() != LogicalOperatorTag.UNNEST) { return false; } UnnestOperator unnestOpRef = (UnnestOperator) opRef.getValue(); Mutable<ILogicalOperator> unionOp = unnest.getInputs().get(0); AbstractLogicalOperator unionAbstractOp = (AbstractLogicalOperator) unionOp.getValue(); if (unionAbstractOp.getOperatorTag() != LogicalOperatorTag.UNIONALL) { return false; } LogicalVariable unnestVar1 = context.newVar(); UnnestOperator unnest1 = new UnnestOperator( unnestVar1, new MutableObject<ILogicalExpression>( unnestOpRef.getExpressionRef().getValue().cloneExpression())); LogicalVariable unnestVar2 = context.newVar(); UnnestOperator unnest2 = new UnnestOperator( unnestVar2, new MutableObject<ILogicalExpression>( unnestOpRef.getExpressionRef().getValue().cloneExpression())); // Getting the two topmost branched and adding them as an input to the unnests: Mutable<ILogicalOperator> branch1 = unionAbstractOp.getInputs().get(0); ILogicalOperator agg1 = branch1.getValue(); List<LogicalVariable> agg1_var = new ArrayList<LogicalVariable>(); VariableUtilities.getLiveVariables(agg1, agg1_var); Mutable<ILogicalOperator> branch2 = unionAbstractOp.getInputs().get(1); ILogicalOperator agg2 = branch2.getValue(); List<LogicalVariable> agg2_var = new ArrayList<LogicalVariable>(); VariableUtilities.getLiveVariables(agg2, agg2_var); // Modifying the unnest so it has the right variable List<LogicalVariable> var_unnest_1 = new ArrayList<LogicalVariable>(); unnest1.getExpressionRef().getValue().getUsedVariables(var_unnest_1); unnest1.getExpressionRef().getValue().substituteVar(var_unnest_1.get(0), agg1_var.get(0)); List<LogicalVariable> var_unnest2 = new ArrayList<LogicalVariable>(); unnest2.getExpressionRef().getValue().getUsedVariables(var_unnest2); unnest2.getExpressionRef().getValue().substituteVar(var_unnest2.get(0), agg2_var.get(0)); unnest1.getInputs().add(branch1); unnest2.getInputs().add(branch2); context.computeAndSetTypeEnvironmentForOperator(unnest1); context.computeAndSetTypeEnvironmentForOperator(unnest2); // creating a new union operator with the updated logical variables List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> varMap = new ArrayList<Triple<LogicalVariable, LogicalVariable, LogicalVariable>>(1); Triple<LogicalVariable, LogicalVariable, LogicalVariable> union_triple_vars = new Triple<LogicalVariable, LogicalVariable, LogicalVariable>( unnestVar1, unnestVar2, unnestOpRef.getVariables().get(0)); varMap.add(union_triple_vars); UnionAllOperator unionOpFinal = new UnionAllOperator(varMap); unionOpFinal.getInputs().add(new MutableObject<ILogicalOperator>(unnest1)); unionOpFinal.getInputs().add(new MutableObject<ILogicalOperator>(unnest2)); context.computeAndSetTypeEnvironmentForOperator(unionOpFinal); opRef.setValue(unionOpFinal); return true; }