@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;
  }