@Override public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { if (hasRun) { return false; } hasRun = true; // Collect all used variables after each operator, including the used variables in itself in the plan. // This is necessary since introduceProjects() may generate a wrong project if it doesn't have the information // for all paths in the plan in case there are two or more branches since it can only deal one path at a time. // So, a variable used in one path might be removed while the method traverses another path. Set<LogicalVariable> parentUsedVars = new LinkedHashSet<>(); collectUsedVars(opRef, parentUsedVars); // Introduce projects return introduceProjects(null, -1, opRef, Collections.<LogicalVariable> emptySet(), context); }
/** * Collect all used variables after each operator, including the used variables in itself in the plan. * Collecting information in a separate method is required since there can be multiple paths in the plan * and introduceProjects() method can deal with only one path at a time during conducting depth-first-search. */ protected void collectUsedVars(Mutable<ILogicalOperator> opRef, Set<LogicalVariable> parentUsedVars) throws AlgebricksException { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); Set<LogicalVariable> usedVarsPerOp = new LinkedHashSet<>(); VariableUtilities.getUsedVariables(op, usedVarsPerOp); usedVarsPerOp.addAll(parentUsedVars); if (allUsedVarsAfterOpMap.get(op) == null) { allUsedVarsAfterOpMap.put(op, usedVarsPerOp); } else { allUsedVarsAfterOpMap.get(op).addAll(usedVarsPerOp); } for (Mutable<ILogicalOperator> inputOpRef : op.getInputs()) { collectUsedVars(inputOpRef, usedVarsPerOp); } }