Java Code Examples for org.apache.calcite.rel.core.Join#getCondition()

The following examples show how to use org.apache.calcite.rel.core.Join#getCondition() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: JoinCommuteRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a relational expression with the inputs switched round. Does not
 * modify <code>join</code>. Returns null if the join cannot be swapped (for
 * example, because it is an outer join).
 *
 * @param join              join to be swapped
 * @param swapOuterJoins    whether outer joins should be swapped
 * @param relBuilder        Builder for relational expressions
 * @return swapped join if swapping possible; else null
 */
public static RelNode swap(Join join, boolean swapOuterJoins, RelBuilder relBuilder) {
    final JoinRelType joinType = join.getJoinType();
    if (!swapOuterJoins && joinType != JoinRelType.INNER) {
        return null;
    }
    final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
    final RelDataType leftRowType = join.getLeft().getRowType();
    final RelDataType rightRowType = join.getRight().getRowType();
    final VariableReplacer variableReplacer = new VariableReplacer(rexBuilder, leftRowType, rightRowType);
    final RexNode oldCondition = join.getCondition();
    RexNode condition = variableReplacer.go(oldCondition);

    // NOTE jvs 14-Mar-2006: We preserve attribute semiJoinDone after the
    // swap. This way, we will generate one semijoin for the original
    // join, and one for the swapped join, and no more. This
    // doesn't prevent us from seeing any new combinations assuming
    // that the planner tries the desired order (semijoins after swaps).
    Join newJoin = join.copy(join.getTraitSet(), condition, join.getRight(), join.getLeft(), joinType.swap(),
            join.isSemiJoinDone());
    final List<RexNode> exps = RelOptUtil.createSwappedJoinExprs(newJoin, join, true);
    return relBuilder.push(newJoin).project(exps, join.getRowType().getFieldNames()).build();
}
 
Example 2
Source File: DrillRelOptUtil.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Returns whether the join condition is a simple equi-join or not. A simple equi-join is
 * defined as an two-table equality join (no self-join)
 * @param join : input join
 * @param joinFieldOrdinals: join field ordinal w.r.t. the underlying inputs to the join
 * @return TRUE if the join is a simple equi-join (not a self-join), FALSE otherwise
 * */
public static boolean analyzeSimpleEquiJoin(Join join, int[] joinFieldOrdinals) {
    RexNode joinExp = join.getCondition();
    if (joinExp.getKind() != SqlKind.EQUALS) {
        return false;
    } else {
        RexCall binaryExpression = (RexCall) joinExp;
        RexNode leftComparand = binaryExpression.getOperands().get(0);
        RexNode rightComparand = binaryExpression.getOperands().get(1);
        if (!(leftComparand instanceof RexInputRef)) {
            return false;
        } else if (!(rightComparand instanceof RexInputRef)) {
            return false;
        } else {
            int leftFieldCount = join.getLeft().getRowType().getFieldCount();
            int rightFieldCount = join.getRight().getRowType().getFieldCount();
            RexInputRef leftFieldAccess = (RexInputRef) leftComparand;
            RexInputRef rightFieldAccess = (RexInputRef) rightComparand;
            if (leftFieldAccess.getIndex() >= leftFieldCount + rightFieldCount
                    || rightFieldAccess.getIndex() >= leftFieldCount + rightFieldCount) {
                return false;
            }
            /* Both columns reference same table */
            if ((leftFieldAccess.getIndex() >= leftFieldCount && rightFieldAccess.getIndex() >= leftFieldCount)
                    || (leftFieldAccess.getIndex() < leftFieldCount
                            && rightFieldAccess.getIndex() < leftFieldCount)) {
                return false;
            } else {
                if (leftFieldAccess.getIndex() < leftFieldCount) {
                    joinFieldOrdinals[0] = leftFieldAccess.getIndex();
                    joinFieldOrdinals[1] = rightFieldAccess.getIndex() - leftFieldCount;
                } else {
                    joinFieldOrdinals[0] = rightFieldAccess.getIndex();
                    joinFieldOrdinals[1] = leftFieldAccess.getIndex() - leftFieldCount;
                }
                return true;
            }
        }
    }
}
 
Example 3
Source File: RelToSqlConverter.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
/**
 * @see #dispatch
 */
public Result visit(Join e) {
  final Result leftResult = visitChild(0, e.getLeft()).resetAlias();
  final Result rightResult = visitChild(1, e.getRight()).resetAlias();
  final Context leftContext = leftResult.qualifiedContext();
  final Context rightContext = rightResult.qualifiedContext();
  SqlNode sqlCondition = null;
  SqlLiteral condType = JoinConditionType.ON.symbol(POS);
  JoinType joinType = joinType(e.getJoinType());
  if (e.getJoinType() == JoinRelType.INNER && e.getCondition().isAlwaysTrue()) {
    joinType = JoinType.COMMA;
    condType = JoinConditionType.NONE.symbol(POS);
  } else {
    final RexNode condition = e.getCondition() != null
      ? simplifyDatetimePlus(e.getCondition(), e.getCluster().getRexBuilder())
      : null;
    sqlCondition = convertConditionToSqlNode(
      condition,
      leftContext,
      rightContext,
      e.getLeft().getRowType().getFieldCount());
  }
  SqlNode join =
    new SqlJoin(POS,
      leftResult.asFrom(),
      SqlLiteral.createBoolean(false, POS),
      joinType.symbol(POS),
      rightResult.asFrom(),
      condType,
      sqlCondition);
  return result(join, leftResult, rightResult);
}
 
Example 4
Source File: DremioRelToSqlConverter.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
/**
 * @see #dispatch
 */
@Override
public SqlImplementor.Result visit(Join e) {
  final DremioRelToSqlConverter.Result leftResult = (DremioRelToSqlConverter.Result) visitChild(0, e.getLeft()).resetAlias();
  final DremioRelToSqlConverter.Result rightResult = (DremioRelToSqlConverter.Result) visitChild(1, e.getRight()).resetAlias();

  SqlNode sqlCondition = null;
  SqlLiteral condType = JoinConditionType.ON.symbol(POS);
  JoinType joinType = joinType(e.getJoinType());
  final Context leftContext = leftResult.qualifiedContext();
  final Context rightContext = rightResult.qualifiedContext();
  final Context joinContext = leftContext.implementor().joinContext(leftContext, rightContext);
  final RexNode condition = e.getCondition() == null ?
    null :
    this.simplifyDatetimePlus(e.getCondition(), e.getCluster().getRexBuilder());
  sqlCondition = joinContext.toSql(null, condition);

  final SqlNode join =
    new SqlJoin(POS,
      leftResult.asFrom(),
      SqlLiteral.createBoolean(false, POS),
      joinType.symbol(POS),
      rightResult.asFrom(),
      condType,
      sqlCondition);
  return result(join, leftResult, rightResult);
}
 
Example 5
Source File: JoinCommuteRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a relational expression with the inputs switched round. Does not
 * modify <code>join</code>. Returns null if the join cannot be swapped (for
 * example, because it is an outer join).
 *
 * @param join              join to be swapped
 * @param swapOuterJoins    whether outer joins should be swapped
 * @param relBuilder        Builder for relational expressions
 * @return swapped join if swapping possible; else null
 */
public static RelNode swap(Join join, boolean swapOuterJoins,
    RelBuilder relBuilder) {
  final JoinRelType joinType = join.getJoinType();
  if (!swapOuterJoins && joinType != JoinRelType.INNER) {
    return null;
  }
  final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
  final RelDataType leftRowType = join.getLeft().getRowType();
  final RelDataType rightRowType = join.getRight().getRowType();
  final VariableReplacer variableReplacer =
      new VariableReplacer(rexBuilder, leftRowType, rightRowType);
  final RexNode oldCondition = join.getCondition();
  RexNode condition = variableReplacer.apply(oldCondition);

  // NOTE jvs 14-Mar-2006: We preserve attribute semiJoinDone after the
  // swap.  This way, we will generate one semijoin for the original
  // join, and one for the swapped join, and no more.  This
  // doesn't prevent us from seeing any new combinations assuming
  // that the planner tries the desired order (semijoins after swaps).
  Join newJoin =
      join.copy(join.getTraitSet(), condition, join.getRight(),
          join.getLeft(), joinType.swap(), join.isSemiJoinDone());
  final List<RexNode> exps =
      RelOptUtil.createSwappedJoinExprs(newJoin, join, true);
  return relBuilder.push(newJoin)
      .project(exps, join.getRowType().getFieldNames())
      .build();
}
 
Example 6
Source File: JdbcRules.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Converts a {@code Join} into a {@code JdbcJoin}.
 *
 * @param join Join operator to convert
 * @param convertInputTraits Whether to convert input to {@code join}'s
 *                            JDBC convention
 * @return A new JdbcJoin
 */
public RelNode convert(Join join, boolean convertInputTraits) {
  final List<RelNode> newInputs = new ArrayList<>();
  for (RelNode input : join.getInputs()) {
    if (convertInputTraits && input.getConvention() != getOutTrait()) {
      input =
          convert(input,
              input.getTraitSet().replace(out));
    }
    newInputs.add(input);
  }
  if (convertInputTraits && !canJoinOnCondition(join.getCondition())) {
    return null;
  }
  try {
    return new JdbcJoin(
        join.getCluster(),
        join.getTraitSet().replace(out),
        newInputs.get(0),
        newInputs.get(1),
        join.getCondition(),
        join.getVariablesSet(),
        join.getJoinType());
  } catch (InvalidRelException e) {
    LOGGER.debug(e.toString());
    return null;
  }
}
 
Example 7
Source File: RelMdAllPredicates.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Add the Join condition to the list obtained from the input.
 */
public RelOptPredicateList getAllPredicates(Join join, RelMetadataQuery mq) {
  if (join.getJoinType() != JoinRelType.INNER) {
    // We cannot map origin of this expression.
    return null;
  }

  final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
  final RexNode pred = join.getCondition();

  final Multimap<List<String>, RelTableRef> qualifiedNamesToRefs = HashMultimap.create();
  RelOptPredicateList newPreds = RelOptPredicateList.EMPTY;
  for (RelNode input : join.getInputs()) {
    final RelOptPredicateList inputPreds = mq.getAllPredicates(input);
    if (inputPreds == null) {
      // Bail out
      return null;
    }
    // Gather table references
    final Set<RelTableRef> tableRefs = mq.getTableReferences(input);
    if (input == join.getLeft()) {
      // Left input references remain unchanged
      for (RelTableRef leftRef : tableRefs) {
        qualifiedNamesToRefs.put(leftRef.getQualifiedName(), leftRef);
      }
      newPreds = newPreds.union(rexBuilder, inputPreds);
    } else {
      // Right input references might need to be updated if there are table name
      // clashes with left input
      final Map<RelTableRef, RelTableRef> currentTablesMapping = new HashMap<>();
      for (RelTableRef rightRef : tableRefs) {
        int shift = 0;
        Collection<RelTableRef> lRefs = qualifiedNamesToRefs.get(
            rightRef.getQualifiedName());
        if (lRefs != null) {
          shift = lRefs.size();
        }
        currentTablesMapping.put(rightRef,
            RelTableRef.of(rightRef.getTable(), shift + rightRef.getEntityNumber()));
      }
      final List<RexNode> updatedPreds = Lists.newArrayList(
          Iterables.transform(inputPreds.pulledUpPredicates,
              e -> RexUtil.swapTableReferences(rexBuilder, e,
                  currentTablesMapping)));
      newPreds = newPreds.union(rexBuilder,
          RelOptPredicateList.of(rexBuilder, updatedPreds));
    }
  }

  // Extract input fields referenced by Join condition
  final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<>();
  final RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(inputExtraFields);
  pred.accept(inputFinder);
  final ImmutableBitSet inputFieldsUsed = inputFinder.inputBitSet.build();

  // Infer column origin expressions for given references
  final Map<RexInputRef, Set<RexNode>> mapping = new LinkedHashMap<>();
  for (int idx : inputFieldsUsed) {
    final RexInputRef inputRef = RexInputRef.of(idx, join.getRowType().getFieldList());
    final Set<RexNode> originalExprs = mq.getExpressionLineage(join, inputRef);
    if (originalExprs == null) {
      // Bail out
      return null;
    }
    final RexInputRef ref = RexInputRef.of(idx, join.getRowType().getFieldList());
    mapping.put(ref, originalExprs);
  }

  // Replace with new expressions and return union of predicates
  final Set<RexNode> allExprs =
      RelMdExpressionLineage.createAllPossibleExpressions(rexBuilder, pred, mapping);
  if (allExprs == null) {
    return null;
  }
  return newPreds.union(rexBuilder, RelOptPredicateList.of(rexBuilder, allExprs));
}
 
Example 8
Source File: ProjectJoinTransposeRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  Project origProj = call.rel(0);
  final Join join = call.rel(1);

  if (join instanceof SemiJoin) {
    return; // TODO: support SemiJoin
  }
  // locate all fields referenced in the projection and join condition;
  // determine which inputs are referenced in the projection and
  // join condition; if all fields are being referenced and there are no
  // special expressions, no point in proceeding any further
  PushProjector pushProject =
      new PushProjector(
          origProj,
          join.getCondition(),
          join,
          preserveExprCondition,
          call.builder());
  if (pushProject.locateAllRefs()) {
    return;
  }

  // create left and right projections, projecting only those
  // fields referenced on each side
  RelNode leftProjRel =
      pushProject.createProjectRefsAndExprs(
          join.getLeft(),
          true,
          false);
  RelNode rightProjRel =
      pushProject.createProjectRefsAndExprs(
          join.getRight(),
          true,
          true);

  // convert the join condition to reference the projected columns
  RexNode newJoinFilter = null;
  int[] adjustments = pushProject.getAdjustments();
  if (join.getCondition() != null) {
    List<RelDataTypeField> projJoinFieldList = new ArrayList<>();
    projJoinFieldList.addAll(
        join.getSystemFieldList());
    projJoinFieldList.addAll(
        leftProjRel.getRowType().getFieldList());
    projJoinFieldList.addAll(
        rightProjRel.getRowType().getFieldList());
    newJoinFilter =
        pushProject.convertRefsAndExprs(
            join.getCondition(),
            projJoinFieldList,
            adjustments);
  }

  // create a new join with the projected children
  Join newJoinRel =
      join.copy(
          join.getTraitSet(),
          newJoinFilter,
          leftProjRel,
          rightProjRel,
          join.getJoinType(),
          join.isSemiJoinDone());

  // put the original project on top of the join, converting it to
  // reference the modified projection list
  RelNode topProject =
      pushProject.createNewProject(newJoinRel, adjustments);

  call.transformTo(topProject);
}
 
Example 9
Source File: FlinkProjectJoinTransposeRule.java    From flink with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
	Project origProj = call.rel(0);
	final Join join = call.rel(1);

	if (!join.getJoinType().projectsRight()) {
		return; // TODO: support SEMI/ANTI join later
	}
	// locate all fields referenced in the projection and join condition;
	// determine which inputs are referenced in the projection and
	// join condition; if all fields are being referenced and there are no
	// special expressions, no point in proceeding any further
	PushProjector pushProject =
			new PushProjector(
					origProj,
					join.getCondition(),
					join,
					preserveExprCondition,
					call.builder());
	if (pushProject.locateAllRefs()) {
		return;
	}

	// create left and right projections, projecting only those
	// fields referenced on each side
	RelNode leftProjRel =
			pushProject.createProjectRefsAndExprs(
					join.getLeft(),
					true,
					false);
	RelNode rightProjRel =
			pushProject.createProjectRefsAndExprs(
					join.getRight(),
					true,
					true);

	// convert the join condition to reference the projected columns
	RexNode newJoinFilter = null;
	int[] adjustments = pushProject.getAdjustments();
	if (join.getCondition() != null) {
		List<RelDataTypeField> projJoinFieldList = new ArrayList<>();
		projJoinFieldList.addAll(
				join.getSystemFieldList());
		projJoinFieldList.addAll(
				leftProjRel.getRowType().getFieldList());
		projJoinFieldList.addAll(
				rightProjRel.getRowType().getFieldList());
		newJoinFilter =
				pushProject.convertRefsAndExprs(
						join.getCondition(),
						projJoinFieldList,
						adjustments);
	}

	// create a new join with the projected children
	Join newJoinRel =
			join.copy(
					join.getTraitSet(),
					newJoinFilter,
					leftProjRel,
					rightProjRel,
					join.getJoinType(),
					join.isSemiJoinDone());

	// put the original project on top of the join, converting it to
	// reference the modified projection list
	RelNode topProject =
			pushProject.createNewProject(newJoinRel, adjustments);

	call.transformTo(topProject);
}
 
Example 10
Source File: RelMdRowCount.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
public static double estimateRowCount(Join rel, RelMetadataQuery mq) {
  double rightJoinFactor = 1.0;

  RexNode condition = rel.getCondition();
  if (condition.isAlwaysTrue()) {
    // Cartesian join is only supported for NLJ. If join type is right, make it more expensive
    if (rel.getJoinType() == JoinRelType.RIGHT) {
      rightJoinFactor = 2.0;
    }
    return RelMdUtil.getJoinRowCount(mq, rel, condition) * rightJoinFactor;
  }

  final PlannerSettings plannerSettings = PrelUtil.getPlannerSettings(rel.getCluster().getPlanner());
  double filterMinSelectivityEstimateFactor = plannerSettings == null ?
    PlannerSettings.DEFAULT_FILTER_MIN_SELECTIVITY_ESTIMATE_FACTOR :
    plannerSettings.getFilterMinSelectivityEstimateFactor();
  double filterMaxSelectivityEstimateFactor = plannerSettings == null ?
    PlannerSettings.DEFAULT_FILTER_MAX_SELECTIVITY_ESTIMATE_FACTOR :
    plannerSettings.getFilterMaxSelectivityEstimateFactor();

  final RexNode remaining;
  if (rel instanceof JoinRelBase) {
    remaining = ((JoinRelBase) rel).getRemaining();
  } else {
    remaining = RelOptUtil.splitJoinCondition(rel.getLeft(), rel.getRight(), condition, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
  }

  double selectivity = mq.getSelectivity(rel, remaining);
  if (!remaining.isAlwaysFalse()) {
    // Cap selectivity at filterMinSelectivityEstimateFactor unless it is always FALSE
    if (selectivity < filterMinSelectivityEstimateFactor) {
      selectivity = filterMinSelectivityEstimateFactor;
    }
  }

  if (!remaining.isAlwaysTrue()) {
    // Cap selectivity at filterMaxSelectivityEstimateFactor unless it is always TRUE
    if (selectivity > filterMaxSelectivityEstimateFactor) {
      selectivity = filterMaxSelectivityEstimateFactor;
    }
    // Make right join more expensive for inequality join condition (logical phase)
    if (rel.getJoinType() == JoinRelType.RIGHT) {
      rightJoinFactor = 2.0;
    }
  }

  return selectivity * Math.max(mq.getRowCount(rel.getLeft()), mq.getRowCount(rel.getRight())) * rightJoinFactor;
}
 
Example 11
Source File: FlinkProjectJoinTransposeRule.java    From flink with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
	Project origProj = call.rel(0);
	final Join join = call.rel(1);

	if (!join.getJoinType().projectsRight()) {
		return; // TODO: support SEMI/ANTI join later
	}
	// locate all fields referenced in the projection and join condition;
	// determine which inputs are referenced in the projection and
	// join condition; if all fields are being referenced and there are no
	// special expressions, no point in proceeding any further
	PushProjector pushProject =
			new PushProjector(
					origProj,
					join.getCondition(),
					join,
					preserveExprCondition,
					call.builder());
	if (pushProject.locateAllRefs()) {
		return;
	}

	// create left and right projections, projecting only those
	// fields referenced on each side
	RelNode leftProjRel =
			pushProject.createProjectRefsAndExprs(
					join.getLeft(),
					true,
					false);
	RelNode rightProjRel =
			pushProject.createProjectRefsAndExprs(
					join.getRight(),
					true,
					true);

	// convert the join condition to reference the projected columns
	RexNode newJoinFilter = null;
	int[] adjustments = pushProject.getAdjustments();
	if (join.getCondition() != null) {
		List<RelDataTypeField> projJoinFieldList = new ArrayList<>();
		projJoinFieldList.addAll(
				join.getSystemFieldList());
		projJoinFieldList.addAll(
				leftProjRel.getRowType().getFieldList());
		projJoinFieldList.addAll(
				rightProjRel.getRowType().getFieldList());
		newJoinFilter =
				pushProject.convertRefsAndExprs(
						join.getCondition(),
						projJoinFieldList,
						adjustments);
	}

	// create a new join with the projected children
	Join newJoinRel =
			join.copy(
					join.getTraitSet(),
					newJoinFilter,
					leftProjRel,
					rightProjRel,
					join.getJoinType(),
					join.isSemiJoinDone());

	// put the original project on top of the join, converting it to
	// reference the modified projection list
	RelNode topProject =
			pushProject.createNewProject(newJoinRel, adjustments);

	call.transformTo(topProject);
}
 
Example 12
Source File: RelMdAllPredicates.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Add the Join condition to the list obtained from the input.
 */
public RelOptPredicateList getAllPredicates(Join join, RelMetadataQuery mq) {
  if (join.getJoinType().isOuterJoin()) {
    // We cannot map origin of this expression.
    return null;
  }

  final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
  final RexNode pred = join.getCondition();

  final Multimap<List<String>, RelTableRef> qualifiedNamesToRefs = HashMultimap.create();
  RelOptPredicateList newPreds = RelOptPredicateList.EMPTY;
  for (RelNode input : join.getInputs()) {
    final RelOptPredicateList inputPreds = mq.getAllPredicates(input);
    if (inputPreds == null) {
      // Bail out
      return null;
    }
    // Gather table references
    final Set<RelTableRef> tableRefs = mq.getTableReferences(input);
    if (input == join.getLeft()) {
      // Left input references remain unchanged
      for (RelTableRef leftRef : tableRefs) {
        qualifiedNamesToRefs.put(leftRef.getQualifiedName(), leftRef);
      }
      newPreds = newPreds.union(rexBuilder, inputPreds);
    } else {
      // Right input references might need to be updated if there are table name
      // clashes with left input
      final Map<RelTableRef, RelTableRef> currentTablesMapping = new HashMap<>();
      for (RelTableRef rightRef : tableRefs) {
        int shift = 0;
        Collection<RelTableRef> lRefs = qualifiedNamesToRefs.get(
            rightRef.getQualifiedName());
        if (lRefs != null) {
          shift = lRefs.size();
        }
        currentTablesMapping.put(rightRef,
            RelTableRef.of(rightRef.getTable(), shift + rightRef.getEntityNumber()));
      }
      final List<RexNode> updatedPreds = Lists.newArrayList(
          Iterables.transform(inputPreds.pulledUpPredicates,
              e -> RexUtil.swapTableReferences(rexBuilder, e,
                  currentTablesMapping)));
      newPreds = newPreds.union(rexBuilder,
          RelOptPredicateList.of(rexBuilder, updatedPreds));
    }
  }

  // Extract input fields referenced by Join condition
  final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<>();
  final RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(inputExtraFields);
  pred.accept(inputFinder);
  final ImmutableBitSet inputFieldsUsed = inputFinder.build();

  // Infer column origin expressions for given references
  final Map<RexInputRef, Set<RexNode>> mapping = new LinkedHashMap<>();
  final RelDataType fullRowType = SqlValidatorUtil.createJoinType(
      rexBuilder.getTypeFactory(),
      join.getLeft().getRowType(),
      join.getRight().getRowType(),
      null,
      ImmutableList.of());
  for (int idx : inputFieldsUsed) {
    final RexInputRef inputRef = RexInputRef.of(idx, fullRowType.getFieldList());
    final Set<RexNode> originalExprs = mq.getExpressionLineage(join, inputRef);
    if (originalExprs == null) {
      // Bail out
      return null;
    }
    final RexInputRef ref = RexInputRef.of(idx, fullRowType.getFieldList());
    mapping.put(ref, originalExprs);
  }

  // Replace with new expressions and return union of predicates
  final Set<RexNode> allExprs =
      RelMdExpressionLineage.createAllPossibleExpressions(rexBuilder, pred, mapping);
  if (allExprs == null) {
    return null;
  }
  return newPreds.union(rexBuilder, RelOptPredicateList.of(rexBuilder, allExprs));
}