// traversing origin, find ExprNodeDesc in sources and replaces it with ExprNodeDesc // in targets having same index. // return null if failed to find public static ExprNodeDesc replace( ExprNodeDesc origin, List<ExprNodeDesc> sources, List<ExprNodeDesc> targets) { int index = indexOf(origin, sources); if (index >= 0) { return targets.get(index); } // encountered column or field which cannot be found in sources if (origin instanceof ExprNodeColumnDesc || origin instanceof ExprNodeFieldDesc) { return null; } // for ExprNodeGenericFuncDesc, it should be deterministic and stateless if (origin instanceof ExprNodeGenericFuncDesc) { ExprNodeGenericFuncDesc func = (ExprNodeGenericFuncDesc) origin; if (!FunctionRegistry.isDeterministic(func.getGenericUDF()) || FunctionRegistry.isStateful(func.getGenericUDF())) { return null; } List<ExprNodeDesc> children = new ArrayList<ExprNodeDesc>(); for (int i = 0; i < origin.getChildren().size(); i++) { ExprNodeDesc child = replace(origin.getChildren().get(i), sources, targets); if (child == null) { return null; } children.add(child); } // duplicate function with possibly replaced children ExprNodeGenericFuncDesc clone = (ExprNodeGenericFuncDesc) func.clone(); clone.setChildren(children); return clone; } // constant or null, just return it return origin; }