@Override
 public Void visitGroupByOperator(GroupByOperator op, Pair<LogicalVariable, LogicalVariable> pair)
     throws AlgebricksException {
   subst(pair.first, pair.second, op.getGroupByList());
   subst(pair.first, pair.second, op.getDecorList());
   for (ILogicalPlan p : op.getNestedPlans()) {
     for (Mutable<ILogicalOperator> r : p.getRoots()) {
       OperatorManipulationUtil.substituteVarRec(
           (AbstractLogicalOperator) r.getValue(), pair.first, pair.second, goThroughNts, ctx);
     }
   }
   substVarTypes(op, pair);
   return null;
 }
 @Override
 public Void visitGroupByOperator(GroupByOperator op, Void arg) throws AlgebricksException {
   for (ILogicalPlan p : op.getNestedPlans()) {
     for (Mutable<ILogicalOperator> r : p.getRoots()) {
       VariableUtilities.getLiveVariables(r.getValue(), schemaVariables);
     }
   }
   for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : op.getGroupByList()) {
     if (p.first != null) {
       schemaVariables.add(p.first);
     }
   }
   for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : op.getDecorList()) {
     if (p.first != null) {
       schemaVariables.add(p.first);
     } else {
       ILogicalExpression e = p.second.getValue();
       if (e.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
         schemaVariables.add(((VariableReferenceExpression) e).getVariableReference());
       }
     }
   }
   return null;
 }
  @Override
  public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
    AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
    if (op.getOperatorTag() != LogicalOperatorTag.GROUP) {
      return false;
    }
    if (context.checkIfInDontApplySet(this, op)) {
      return false;
    }
    vars.clear();

    boolean modified = false;
    GroupByOperator groupOp = (GroupByOperator) op;
    Iterator<Pair<LogicalVariable, Mutable<ILogicalExpression>>> iter =
        groupOp.getDecorList().iterator();
    while (iter.hasNext()) {
      Pair<LogicalVariable, Mutable<ILogicalExpression>> decor = iter.next();
      if (decor.first != null
          || decor.second.getValue().getExpressionTag() != LogicalExpressionTag.VARIABLE) {
        continue;
      }
      VariableReferenceExpression varRefExpr =
          (VariableReferenceExpression) decor.second.getValue();
      LogicalVariable var = varRefExpr.getVariableReference();
      if (vars.contains(var)) {
        iter.remove();
        modified = true;
      } else {
        vars.add(var);
      }
    }
    if (modified) {
      context.addToDontApplySet(this, op);
    }
    return modified;
  }