private void removeUnusedAssigns(
      Mutable<ILogicalOperator> opRef, Set<LogicalVariable> toRemove, IOptimizationContext context)
      throws AlgebricksException {
    AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
    while (removeFromAssigns(op, toRemove, context) == 0) {
      if (op.getOperatorTag() == LogicalOperatorTag.AGGREGATE) {
        break;
      }
      op = (AbstractLogicalOperator) op.getInputs().get(0).getValue();
      opRef.setValue(op);
    }
    Iterator<Mutable<ILogicalOperator>> childIter = op.getInputs().iterator();
    while (childIter.hasNext()) {
      Mutable<ILogicalOperator> cRef = childIter.next();
      removeUnusedAssigns(cRef, toRemove, context);
    }
    if (op.hasNestedPlans()) {
      AbstractOperatorWithNestedPlans opWithNest = (AbstractOperatorWithNestedPlans) op;
      Iterator<ILogicalPlan> planIter = opWithNest.getNestedPlans().iterator();
      while (planIter.hasNext()) {
        ILogicalPlan p = planIter.next();
        for (Mutable<ILogicalOperator> r : p.getRoots()) {
          removeUnusedAssigns(r, toRemove, context);
        }
      }

      // Removes redundant nested plans that produces nothing
      for (int i = opWithNest.getNestedPlans().size() - 1; i >= 0; i--) {
        ILogicalPlan nestedPlan = opWithNest.getNestedPlans().get(i);
        List<Mutable<ILogicalOperator>> rootsToBeRemoved =
            new ArrayList<Mutable<ILogicalOperator>>();
        for (Mutable<ILogicalOperator> r : nestedPlan.getRoots()) {
          ILogicalOperator topOp = r.getValue();
          Set<LogicalVariable> producedVars = new ListSet<LogicalVariable>();
          VariableUtilities.getProducedVariablesInDescendantsAndSelf(topOp, producedVars);
          if (producedVars.size() == 0) {
            rootsToBeRemoved.add(r);
          }
        }
        // Makes sure the operator should have at least ONE nested plan even it is empty
        // (because a lot of places uses this assumption,  TODO(yingyib): clean them up).
        if (nestedPlan.getRoots().size() == rootsToBeRemoved.size()
            && opWithNest.getNestedPlans().size() > 1) {
          nestedPlan.getRoots().removeAll(rootsToBeRemoved);
          opWithNest.getNestedPlans().remove(nestedPlan);
        }
      }
    }
  }
 private void collectUnusedAssignedVars(
     AbstractLogicalOperator op,
     Set<LogicalVariable> toRemove,
     boolean first,
     IOptimizationContext context)
     throws AlgebricksException {
   if (!first) {
     context.addToDontApplySet(this, op);
   }
   for (Mutable<ILogicalOperator> c : op.getInputs()) {
     collectUnusedAssignedVars((AbstractLogicalOperator) c.getValue(), toRemove, false, context);
   }
   if (op.hasNestedPlans()) {
     AbstractOperatorWithNestedPlans opWithNested = (AbstractOperatorWithNestedPlans) op;
     for (ILogicalPlan plan : opWithNested.getNestedPlans()) {
       for (Mutable<ILogicalOperator> r : plan.getRoots()) {
         collectUnusedAssignedVars(
             (AbstractLogicalOperator) r.getValue(), toRemove, false, context);
       }
     }
   }
   boolean removeUsedVars = true;
   switch (op.getOperatorTag()) {
     case ASSIGN:
       {
         AssignOperator assign = (AssignOperator) op;
         toRemove.addAll(assign.getVariables());
         break;
       }
     case AGGREGATE:
       {
         AggregateOperator agg = (AggregateOperator) op;
         toRemove.addAll(agg.getVariables());
         break;
       }
     case UNNEST:
       {
         UnnestOperator uOp = (UnnestOperator) op;
         LogicalVariable pVar = uOp.getPositionalVariable();
         if (pVar != null) {
           toRemove.add(pVar);
         }
         break;
       }
     case UNIONALL:
       {
         UnionAllOperator unionOp = (UnionAllOperator) op;
         for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> varMapping :
             unionOp.getVariableMappings()) {
           toRemove.add(varMapping.third);
         }
         removeUsedVars = false;
         break;
       }
   }
   if (removeUsedVars) {
     List<LogicalVariable> used = new LinkedList<LogicalVariable>();
     VariableUtilities.getUsedVariables(op, used);
     toRemove.removeAll(used);
   }
 }