public RelOptPredicateList inferPredicates(
        boolean includeEqualityInference) {
      final List<RexNode> inferredPredicates = new ArrayList<>();
      final List<RexNode> nonFieldsPredicates = new ArrayList<>();
      final Set<String> allExprsDigests = new HashSet<>(this.allExprsDigests);
      final JoinRelType joinType = joinRel.getJoinType();
      final List<RexNode> leftPreds = ImmutableList.copyOf(RelOptUtil.conjunctions(leftChildPredicates));
      final List<RexNode> rightPreds = ImmutableList.copyOf(RelOptUtil.conjunctions(rightChildPredicates));
      final RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
      switch (joinType) {
      case INNER:
      case LEFT:
      case SEMI:
      case ANTI:
        infer(leftPreds, allExprsDigests, inferredPredicates,
            nonFieldsPredicates, includeEqualityInference,
            joinType == JoinRelType.LEFT ? rightFieldsBitSet
                : allFieldsBitSet);
        break;
      }
      switch (joinType) {
      case INNER:
      case RIGHT:
      case SEMI:
        infer(rightPreds, allExprsDigests, inferredPredicates,
            nonFieldsPredicates, includeEqualityInference,
            joinType == JoinRelType.RIGHT ? leftFieldsBitSet
                : allFieldsBitSet);
        break;
      }

      Mappings.TargetMapping rightMapping = Mappings.createShiftMapping(
          nSysFields + nFieldsLeft + nFieldsRight,
          0, nSysFields + nFieldsLeft, nFieldsRight);
      final RexPermuteInputsShuttle rightPermute =
          new RexPermuteInputsShuttle(rightMapping, joinRel);
      Mappings.TargetMapping leftMapping = Mappings.createShiftMapping(
          nSysFields + nFieldsLeft, 0, nSysFields, nFieldsLeft);
      final RexPermuteInputsShuttle leftPermute =
          new RexPermuteInputsShuttle(leftMapping, joinRel);
      final List<RexNode> leftInferredPredicates = new ArrayList<>();
      final List<RexNode> rightInferredPredicates = new ArrayList<>();

      for (RexNode iP : inferredPredicates) {
        ImmutableBitSet iPBitSet = RelOptUtil.InputFinder.bits(iP);
        if (leftFieldsBitSet.contains(iPBitSet)) {
          leftInferredPredicates.add(iP.accept(leftPermute));
        } else if (rightFieldsBitSet.contains(iPBitSet)) {
          rightInferredPredicates.add(iP.accept(rightPermute));
        }
      }

      if ((joinType == JoinRelType.INNER || joinType == JoinRelType.SEMI) &&
              !nonFieldsPredicates.isEmpty()) {
        // Predicates without field references can be pushed to both inputs
        final Set<String> leftPredsSet = new HashSet<String>(
                Lists.transform(leftPreds, HiveCalciteUtil.REX_STR_FN));
        final Set<String> rightPredsSet = new HashSet<String>(
                Lists.transform(rightPreds, HiveCalciteUtil.REX_STR_FN));
        for (RexNode iP : nonFieldsPredicates) {
          if (!leftPredsSet.contains(iP.toString())) {
            leftInferredPredicates.add(iP);
          }
          if (!rightPredsSet.contains(iP.toString())) {
            rightInferredPredicates.add(iP);
          }
        }
      }

      switch (joinType) {
      case INNER:
        Iterable<RexNode> pulledUpPredicates = Iterables.concat(leftPreds, rightPreds,
                RelOptUtil.conjunctions(joinRel.getCondition()), inferredPredicates);
        return RelOptPredicateList.of(rexBuilder,
          pulledUpPredicates, leftInferredPredicates, rightInferredPredicates);
      case SEMI:
        return RelOptPredicateList.of(rexBuilder, Iterables.concat(leftPreds, leftInferredPredicates),
          leftInferredPredicates, rightInferredPredicates);
      case LEFT:
      case ANTI:
        return RelOptPredicateList.of(rexBuilder,
          leftPreds, EMPTY_LIST, rightInferredPredicates);
      case RIGHT:
        return RelOptPredicateList.of(rexBuilder,
          rightPreds, leftInferredPredicates, EMPTY_LIST);
      default:
        assert inferredPredicates.size() == 0;
        return RelOptPredicateList.EMPTY;
      }
    }
The PullUp Strategy is sound but not complete.
<ol>
<li>We only pullUp inferred predicates for now. Pulling up existing
predicates causes an explosion of duplicates. The existing predicates are
pushed back down as new predicates. Once we have rules to eliminate
duplicate Filter conditions, we should pullUp all predicates.
<li>For Left Outer: we infer new predicates from the left and set them as
applicable on the Right side. No predicates are pulledUp.
<li>Right Outer Joins are handled in an analogous manner.
<li>For Full Outer Joins no predicates are pulledUp or inferred.
</ol>
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdPredicates.java