private static void downStreamMerge(Operator<?> op, SharedWorkOptimizerCache optimizerCache, ParseContext pctx)
      throws SemanticException {
    List<Operator<?>> childs = op.getChildOperators();
    for (int i = 0; i < childs.size(); i++) {
      Operator<?> cI = childs.get(i);
      if (cI instanceof ReduceSinkOperator || cI instanceof JoinOperator || cI.getParentOperators().size() != 1) {
        continue;
      }
      for (int j = i + 1; j < childs.size(); j++) {
        Operator<?> cJ = childs.get(j);
        if (cI.logicalEquals(cJ)) {
          LOG.debug("downstream merge: from {} into {}", cJ, cI);
          adoptChildren(cI, cJ);
          op.removeChild(cJ);
          optimizerCache.removeOp(cJ);
          j--;
          downStreamMerge(cI, optimizerCache, pctx);
        }
      }
    }
  }
When we call this method, we have already verified that the SJ expressions targeting
two TS operators are the same.
Since we already had a method to push the filter expressions on top of the discardable
TS (pushFilterToTopOfTableScan), here we remove the old SJ expressions from the
discardable TS (and follow-up Filters if present) and we add the SJ expressions
from the retainable TS. That way the SJ expressions will be pushed on top of the
discardable TS by pushFilterToTopOfTableScan.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/SharedWorkOptimizer.java