Java源码示例:org.apache.calcite.rel.core.Correlate

示例1
/** @see #dispatch */
public Result visit(Correlate e) {
  final Result leftResult =
      visitChild(0, e.getLeft())
          .resetAlias(e.getCorrelVariable(), e.getRowType());
  parseCorrelTable(e, leftResult);
  final Result rightResult = visitChild(1, e.getRight());
  final SqlNode rightLateral =
      SqlStdOperatorTable.LATERAL.createCall(POS, rightResult.node);
  final SqlNode rightLateralAs =
      SqlStdOperatorTable.AS.createCall(POS, rightLateral,
          new SqlIdentifier(rightResult.neededAlias, POS));

  final SqlNode join =
      new SqlJoin(POS,
          leftResult.asFrom(),
          SqlLiteral.createBoolean(false, POS),
          JoinType.COMMA.symbol(POS),
          rightLateralAs,
          JoinConditionType.NONE.symbol(POS),
          null);
  return result(join, leftResult, rightResult);
}
 
示例2
private Function2<RelNode, RelNode, Void> createCopyHook() {
  return (oldNode, newNode) -> {
    if (cm.mapRefRelToCorRef.containsKey(oldNode)) {
      cm.mapRefRelToCorRef.putAll(newNode,
          cm.mapRefRelToCorRef.get(oldNode));
    }
    if (oldNode instanceof Correlate
        && newNode instanceof Correlate) {
      Correlate oldCor = (Correlate) oldNode;
      CorrelationId c = oldCor.getCorrelationId();
      if (cm.mapCorToCorRel.get(c) == oldNode) {
        cm.mapCorToCorRel.put(c, newNode);
      }

      if (generatedCorRels.contains(oldNode)) {
        generatedCorRels.add((Correlate) newNode);
      }
    }
    return null;
  };
}
 
示例3
@Test void testCorrelateUniqueKeys() {
  final String sql = "select *\n"
      + "from (select distinct deptno from emp) as e,\n"
      + "  lateral (\n"
      + "    select * from dept where dept.deptno = e.deptno)";
  final RelNode rel = convertSql(sql);
  final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();

  assertThat(rel, isA((Class) Project.class));
  final Project project = (Project) rel;
  final Set<ImmutableBitSet> result = mq.getUniqueKeys(project);
  assertThat(result, sortsAs("[{0}]"));
  if (false) {
    assertUniqueConsistent(project);
  }

  assertThat(project.getInput(), isA((Class) Correlate.class));
  final Correlate correlate = (Correlate) project.getInput();
  final Set<ImmutableBitSet> result2 = mq.getUniqueKeys(correlate);
  assertThat(result2, sortsAs("[{0}]"));
  if (false) {
    assertUniqueConsistent(correlate);
  }
}
 
示例4
/**
 * Creates a FilterCorrelateRule.
 */
public FilterCorrelateRule(RelBuilderFactory builderFactory) {
  super(
      operand(Filter.class,
          operand(Correlate.class, RelOptRule.any())),
      builderFactory, "FilterCorrelateRule");
}
 
示例5
/**
 * Pulls a {@link Project} above a {@link Correlate} from its RHS input.
 * Enforces nullability for join output.
 *
 * @param correlate  Correlate
 * @param project the original project as the RHS input of the join
 * @param isCount Positions which are calls to the <code>COUNT</code>
 *                aggregation function
 * @return the subtree with the new Project at the root
 */
private RelNode aggregateCorrelatorOutput(Correlate correlate, LogicalProject project, Set<Integer> isCount) {
    final RelNode left = correlate.getLeft();
    final JoinRelType joinType = correlate.getJoinType().toJoinType();

    // now create the new project
    final List<Pair<RexNode, String>> newProjects = new ArrayList<>();

    // Project everything from the LHS and then those from the original
    // project
    final List<RelDataTypeField> leftInputFields = left.getRowType().getFieldList();

    for (int i = 0; i < leftInputFields.size(); i++) {
        newProjects.add(RexInputRef.of2(i, leftInputFields));
    }

    // Marked where the projected expr is coming from so that the types will
    // become nullable for the original projections which are now coming out
    // of the nullable side of the OJ.
    boolean projectPulledAboveLeftCorrelator = joinType.generatesNullsOnRight();

    for (Pair<RexNode, String> pair : project.getNamedProjects()) {
        RexNode newProjExpr = removeCorrelationExpr(pair.left, projectPulledAboveLeftCorrelator, isCount);
        newProjects.add(Pair.of(newProjExpr, pair.right));
    }

    return relBuilder.push(correlate).projectNamed(Pair.left(newProjects), Pair.right(newProjects), true).build();
}
 
示例6
@Override
public boolean matches(RelOptRuleCall call) {
  Correlate correlate = call.rel(1);


  // No need to call ProjectCorrelateTransposeRule if the current lateralJoin contains excludeCorrelationColumn set to true.
  // This is needed as the project push into Lateral join rule changes the output row type which will fail assertions in ProjectCorrelateTransposeRule.
  if (correlate instanceof DrillLateralJoinRel &&
      ((DrillLateralJoinRel)correlate).excludeCorrelateColumn) {
    return false;
  }

  return true;
}
 
示例7
@Override
public Correlate copy(RelTraitSet traitSet,
      RelNode left, RelNode right, CorrelationId correlationId,
      ImmutableBitSet requiredColumns, SemiJoinType joinType) {
  return new DrillLateralJoinRel(this.getCluster(), this.getTraitSet(), left, right, this.excludeCorrelateColumn, correlationId, requiredColumns,
      this.getJoinType());
}
 
示例8
@Override
public Correlate copy(RelTraitSet traitSet,
                      RelNode left, RelNode right, CorrelationId correlationId,
                      ImmutableBitSet requiredColumns, SemiJoinType joinType) {
  return new LateralJoinPrel(this.getCluster(), this.getTraitSet(), left, right, this.excludeCorrelateColumn, correlationId, requiredColumns,
      this.getJoinType());
}
 
示例9
/**
 * Pulls a {@link Project} above a {@link Correlate} from its RHS input.
 * Enforces nullability for join output.
 *
 * @param correlate  Correlate
 * @param project the original project as the RHS input of the join
 * @param isCount Positions which are calls to the <code>COUNT</code>
 *                aggregation function
 * @return the subtree with the new Project at the root
 */
private RelNode aggregateCorrelatorOutput(
    Correlate correlate,
    LogicalProject project,
    Set<Integer> isCount) {
  final RelNode left = correlate.getLeft();
  final JoinRelType joinType = correlate.getJoinType();

  // now create the new project
  final List<Pair<RexNode, String>> newProjects = new ArrayList<>();

  // Project everything from the LHS and then those from the original
  // project
  final List<RelDataTypeField> leftInputFields =
      left.getRowType().getFieldList();

  for (int i = 0; i < leftInputFields.size(); i++) {
    newProjects.add(RexInputRef.of2(i, leftInputFields));
  }

  // Marked where the projected expr is coming from so that the types will
  // become nullable for the original projections which are now coming out
  // of the nullable side of the OJ.
  boolean projectPulledAboveLeftCorrelator =
      joinType.generatesNullsOnRight();

  for (Pair<RexNode, String> pair : project.getNamedProjects()) {
    RexNode newProjExpr =
        removeCorrelationExpr(
            pair.left,
            projectPulledAboveLeftCorrelator,
            isCount);
    newProjects.add(Pair.of(newProjExpr, pair.right));
  }

  return relBuilder.push(correlate)
      .projectNamed(Pair.left(newProjects), Pair.right(newProjects), true)
      .build();
}
 
示例10
/**
 * Pulls a {@link Project} above a {@link Correlate} from its RHS input.
 * Enforces nullability for join output.
 *
 * @param correlate  Correlate
 * @param project the original project as the RHS input of the join
 * @param isCount Positions which are calls to the <code>COUNT</code>
 *                aggregation function
 * @return the subtree with the new Project at the root
 */
private RelNode aggregateCorrelatorOutput(
    Correlate correlate,
    LogicalProject project,
    Set<Integer> isCount) {
  final RelNode left = correlate.getLeft();
  final JoinRelType joinType = correlate.getJoinType();

  // now create the new project
  final List<Pair<RexNode, String>> newProjects = new ArrayList<>();

  // Project everything from the LHS and then those from the original
  // project
  final List<RelDataTypeField> leftInputFields =
      left.getRowType().getFieldList();

  for (int i = 0; i < leftInputFields.size(); i++) {
    newProjects.add(RexInputRef.of2(i, leftInputFields));
  }

  // Marked where the projected expr is coming from so that the types will
  // become nullable for the original projections which are now coming out
  // of the nullable side of the OJ.
  boolean projectPulledAboveLeftCorrelator =
      joinType.generatesNullsOnRight();

  for (Pair<RexNode, String> pair : project.getNamedProjects()) {
    RexNode newProjExpr =
        removeCorrelationExpr(
            pair.left,
            projectPulledAboveLeftCorrelator,
            isCount);
    newProjects.add(Pair.of(newProjExpr, pair.right));
  }

  return relBuilder.push(correlate)
      .projectNamed(Pair.left(newProjects), Pair.right(newProjects), true)
      .build();
}
 
示例11
@Override
public Correlate copy(RelTraitSet traitSet,
  RelNode left, RelNode right, CorrelationId correlationId,
  ImmutableBitSet requiredColumns, SemiJoinType joinType) {
  return new CorrelateRel(getCluster(), traitSet, left, right,
    correlationId, requiredColumns, joinType);
}
 
示例12
public final T traverse(RelNode n) throws Exception {
  List<T> inputStreams = new ArrayList<>();
  for (RelNode input : n.getInputs()) {
    inputStreams.add(traverse(input));
  }

  if (n instanceof Aggregate) {
    return visitAggregate((Aggregate) n, inputStreams);
  } else if (n instanceof Calc) {
    return visitCalc((Calc) n, inputStreams);
  } else if (n instanceof Collect) {
    return visitCollect((Collect) n, inputStreams);
  } else if (n instanceof Correlate) {
    return visitCorrelate((Correlate) n, inputStreams);
  } else if (n instanceof Delta) {
    return visitDelta((Delta) n, inputStreams);
  } else if (n instanceof Exchange) {
    return visitExchange((Exchange) n, inputStreams);
  } else if (n instanceof Project) {
    return visitProject((Project) n, inputStreams);
  } else if (n instanceof Filter) {
    return visitFilter((Filter) n, inputStreams);
  } else if (n instanceof Sample) {
    return visitSample((Sample) n, inputStreams);
  } else if (n instanceof Sort) {
    return visitSort((Sort) n, inputStreams);
  } else if (n instanceof TableModify) {
    return visitTableModify((TableModify) n, inputStreams);
  } else if (n instanceof TableScan) {
    return visitTableScan((TableScan) n, inputStreams);
  } else if (n instanceof Uncollect) {
    return visitUncollect((Uncollect) n, inputStreams);
  } else if (n instanceof Window) {
    return visitWindow((Window) n, inputStreams);
  } else if (n instanceof Join) {
    return visitJoin((Join) n, inputStreams);
  } else {
    return defaultValue(n, inputStreams);
  }
}
 
示例13
/**
 * Creates a FilterCorrelateRule.
 */
public FilterCorrelateRule(RelBuilderFactory builderFactory) {
  super(
      operand(Filter.class,
          operand(Correlate.class, RelOptRule.any())),
      builderFactory, "FilterCorrelateRule");
}
 
示例14
public ProjectCorrelateTransposeRule(
    PushProjector.ExprCondition preserveExprCondition,
    RelBuilderFactory relFactory) {
  super(
      operand(Project.class,
          operand(Correlate.class, any())),
      relFactory, null);
  this.preserveExprCondition = preserveExprCondition;
}
 
示例15
/**
 * Pulls a {@link Project} above a {@link Correlate} from its RHS input.
 * Enforces nullability for join output.
 *
 * @param correlate  Correlate
 * @param project the original project as the RHS input of the join
 * @param isCount Positions which are calls to the <code>COUNT</code>
 *                aggregation function
 * @return the subtree with the new Project at the root
 */
private RelNode aggregateCorrelatorOutput(
    Correlate correlate,
    Project project,
    Set<Integer> isCount) {
  final RelNode left = correlate.getLeft();
  final JoinRelType joinType = correlate.getJoinType();

  // now create the new project
  final List<Pair<RexNode, String>> newProjects = new ArrayList<>();

  // Project everything from the LHS and then those from the original
  // project
  final List<RelDataTypeField> leftInputFields =
      left.getRowType().getFieldList();

  for (int i = 0; i < leftInputFields.size(); i++) {
    newProjects.add(RexInputRef.of2(i, leftInputFields));
  }

  // Marked where the projected expr is coming from so that the types will
  // become nullable for the original projections which are now coming out
  // of the nullable side of the OJ.
  boolean projectPulledAboveLeftCorrelator =
      joinType.generatesNullsOnRight();

  for (Pair<RexNode, String> pair : project.getNamedProjects()) {
    RexNode newProjExpr =
        removeCorrelationExpr(
            pair.left,
            projectPulledAboveLeftCorrelator,
            isCount);
    newProjects.add(Pair.of(newProjExpr, pair.right));
  }

  return relBuilder.push(correlate)
      .projectNamed(Pair.left(newProjects), Pair.right(newProjects), true)
      .build();
}
 
示例16
@Override public RexNode visitInputRef(RexInputRef inputRef) {
  if (currentRel instanceof Correlate) {
    // if this rel references corVar
    // and now it needs to be rewritten
    // it must have been pulled above the Correlate
    // replace the input ref to account for the LHS of the
    // Correlate
    final int leftInputFieldCount =
        ((Correlate) currentRel).getLeft().getRowType()
            .getFieldCount();
    RelDataType newType = inputRef.getType();

    if (projectPulledAboveLeftCorrelator) {
      newType =
          typeFactory.createTypeWithNullability(newType, true);
    }

    int pos = inputRef.getIndex();
    RexInputRef newInputRef =
        new RexInputRef(leftInputFieldCount + pos, newType);

    if ((isCount != null) && isCount.contains(pos)) {
      return createCaseExpression(
          newInputRef,
          rexBuilder.makeExactLiteral(BigDecimal.ZERO),
          newInputRef);
    } else {
      return newInputRef;
    }
  }
  return inputRef;
}
 
示例17
RemoveCorrelationForScalarProjectRule(RelBuilderFactory relBuilderFactory) {
  super(
      operand(Correlate.class,
          operand(RelNode.class, any()),
          operand(Aggregate.class,
              operand(Project.class,
                  operand(RelNode.class, any())))),
      relBuilderFactory, null);
}
 
示例18
RemoveCorrelationForScalarAggregateRule(RelBuilderFactory relBuilderFactory) {
  super(
      operand(Correlate.class,
          operand(RelNode.class, any()),
          operand(Project.class,
              operandJ(Aggregate.class, null, Aggregate::isSimple,
                  operand(Project.class,
                      operand(RelNode.class, any()))))),
      relBuilderFactory, null);
}
 
示例19
AdjustProjectForCountAggregateRule(boolean flavor,
    RelBuilderFactory relBuilderFactory) {
  super(
      flavor
          ? operand(Correlate.class,
              operand(RelNode.class, any()),
              operand(Project.class,
                  operand(Aggregate.class, any())))
          : operand(Correlate.class,
              operand(RelNode.class, any()),
              operand(Aggregate.class, any())),
      relBuilderFactory, null);
  this.flavor = flavor;
}
 
示例20
@Override public RelNode visit(RelNode other) {
  if (other instanceof Join) {
    Join join = (Join) other;
    try {
      stack.push(join);
      join.getCondition().accept(rexVisitor(join));
    } finally {
      stack.pop();
    }
    return visitJoin(join);
  } else if (other instanceof Correlate) {
    Correlate correlate = (Correlate) other;
    mapCorToCorRel.put(correlate.getCorrelationId(), correlate);
    return visitJoin(correlate);
  } else if (other instanceof Filter) {
    Filter filter = (Filter) other;
    try {
      stack.push(filter);
      filter.getCondition().accept(rexVisitor(filter));
    } finally {
      stack.pop();
    }
  } else if (other instanceof Project) {
    Project project = (Project) other;
    try {
      stack.push(project);
      for (RexNode node : project.getProjects()) {
        node.accept(rexVisitor(project));
      }
    } finally {
      stack.pop();
    }
  }
  return super.visit(other);
}
 
示例21
public Set<ImmutableBitSet> getUniqueKeys(Correlate rel, RelMetadataQuery mq,
    boolean ignoreNulls) {
  return mq.getUniqueKeys(rel.getLeft(), ignoreNulls);
}
 
示例22
public void onMatch(RelOptRuleCall call) {
  final Filter filter = call.rel(0);
  final Correlate corr = call.rel(1);

  final List<RexNode> aboveFilters =
      RelOptUtil.conjunctions(filter.getCondition());

  final List<RexNode> leftFilters = new ArrayList<>();
  final List<RexNode> rightFilters = new ArrayList<>();

  // Try to push down above filters. These are typically where clause
  // filters. They can be pushed down if they are not on the NULL
  // generating side.
  RelOptUtil.classifyFilters(
      corr,
      aboveFilters,
      JoinRelType.INNER,
      false,
      !corr.getJoinType().toJoinType().generatesNullsOnLeft(),
      !corr.getJoinType().toJoinType().generatesNullsOnRight(),
      aboveFilters,
      leftFilters,
      rightFilters);

  if (leftFilters.isEmpty()
      && rightFilters.isEmpty()) {
    // no filters got pushed
    return;
  }

  // Create Filters on top of the children if any filters were
  // pushed to them.
  final RexBuilder rexBuilder = corr.getCluster().getRexBuilder();
  final RelBuilder relBuilder = call.builder();
  final RelNode leftRel =
      relBuilder.push(corr.getLeft()).filter(leftFilters).build();
  final RelNode rightRel =
      relBuilder.push(corr.getRight()).filter(rightFilters).build();

  // Create the new Correlate
  RelNode newCorrRel =
      corr.copy(corr.getTraitSet(), ImmutableList.of(leftRel, rightRel));

  call.getPlanner().onCopy(corr, newCorrRel);

  if (!leftFilters.isEmpty()) {
    call.getPlanner().onCopy(filter, leftRel);
  }
  if (!rightFilters.isEmpty()) {
    call.getPlanner().onCopy(filter, rightRel);
  }

  // Create a Filter on top of the join if needed
  relBuilder.push(newCorrRel);
  relBuilder.filter(
      RexUtil.fixUp(rexBuilder, aboveFilters,
          RelOptUtil.getFieldTypeList(relBuilder.peek().getRowType())));

  call.transformTo(relBuilder.build());
}
 
示例23
public ProjectCorrelateTransposeRule(PushProjector.ExprCondition preserveExprCondition,
        RelBuilderFactory relFactory) {
    super(operand(Project.class, operand(Correlate.class, any())), relFactory, null);
    this.preserveExprCondition = preserveExprCondition;
}
 
示例24
@Override
public void onMatch(RelOptRuleCall call) {
    Project origProj = call.rel(0);
    final Correlate corr = call.rel(1);

    // locate all fields referenced in the projection
    // determine which inputs are referenced in the projection;
    // if all fields are being referenced and there are no
    // special expressions, no point in proceeding any further
    PushProjector pushProject = new PushProjector(origProj, call.builder().literal(true), corr,
            preserveExprCondition, call.builder());
    if (pushProject.locateAllRefs()) {
        return;
    }

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

    Map<Integer, Integer> requiredColsMap = new HashMap<>();

    // adjust requiredColumns that reference the projected columns
    int[] adjustments = pushProject.getAdjustments();
    BitSet updatedBits = new BitSet();
    for (Integer col : corr.getRequiredColumns()) {
        int newCol = col + adjustments[col];
        updatedBits.set(newCol);
        requiredColsMap.put(col, newCol);
    }

    RexBuilder rexBuilder = call.builder().getRexBuilder();

    CorrelationId correlationId = corr.getCluster().createCorrel();
    RexCorrelVariable rexCorrel = (RexCorrelVariable) rexBuilder.makeCorrel(leftProjRel.getRowType(),
            correlationId);

    // updates RexCorrelVariable and sets actual RelDataType for RexFieldAccess
    rightProjRel = rightProjRel.accept(new RelNodesExprsHandler(
            new RexFieldAccessReplacer(corr.getCorrelationId(), rexCorrel, rexBuilder, requiredColsMap)));

    // create a new correlate with the projected children
    Correlate newCorrRel = corr.copy(corr.getTraitSet(), leftProjRel, rightProjRel, correlationId,
            ImmutableBitSet.of(BitSets.toIter(updatedBits)), corr.getJoinType());

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

    call.transformTo(topProject);
}
 
示例25
@Override
public RelNode visit(LogicalCorrelate correlate) {
  RelNode left = correlate.getLeft().accept(this);
  leftInputs.put(correlate.getCorrelationId(), left);

  RelNode right = correlate.getRight().accept(this);
  // if right input wasn't changed or left input wasn't changed
  // after rewriting right input, no need to create Correlate with new CorrelationId
  if (correlate.getRight() == right
      || left == leftInputs.get(correlate.getCorrelationId())) {
    if (correlate.getLeft() == left) {
      return correlate;
    }
    // changed only inputs, but CorrelationId left the same
    return correlate.copy(correlate.getTraitSet(), Arrays.asList(left, right));
  }

  Correlate newCorrelate = correlate.copy(correlate.getTraitSet(),
      leftInputs.get(correlate.getCorrelationId()), right,
      updatedCorrelationIds.get(correlate.getCorrelationId()),
      ImmutableBitSet.of(left.getRowType().getFieldCount()), correlate.getJoinType());

  RelBuilder builder = DrillRelFactories.LOGICAL_BUILDER.create(correlate.getCluster(), null);
  builder.push(newCorrelate);

  List<RexNode> topProjectExpressions = left.getRowType().getFieldList().stream()
          .map(field -> builder.getRexBuilder().makeInputRef(newCorrelate, field.getIndex()))
          .collect(Collectors.toList());

  //Accommodate the new $COMPLEX_FIELD_NAME column.
  int rightStartIndex = left.getRowType().getFieldList().size() + 1;
  switch (correlate.getJoinType()) {
    case LEFT:
    case INNER:
      // adds field from the right input of correlate to the top project
      topProjectExpressions.addAll(right.getRowType().getFieldList().stream()
              .map(field -> builder.getRexBuilder().makeInputRef(newCorrelate, field.getIndex() + rightStartIndex))
              .collect(Collectors.toList()));
      // fall through
    case ANTI:
    case SEMI:
      builder.project(topProjectExpressions, correlate.getRowType().getFieldNames());
  }
  return builder.build();
}
 
示例26
public T visitCorrelate(Correlate correlate, List<T> inputStreams) throws Exception {
  return defaultValue(correlate, inputStreams);
}
 
示例27
public InstanceAccessByIdRule() {
    super(operand(Correlate.class, any()));
}
 
示例28
public Multimap<Class<? extends RelNode>, RelNode> getNodeTypes(Correlate rel,
    RelMetadataQuery mq) {
  return getNodeTypes(rel, Correlate.class, mq);
}
 
示例29
public Set<ImmutableBitSet> getUniqueKeys(Correlate rel, RelMetadataQuery mq,
    boolean ignoreNulls) {
  return mq.getUniqueKeys(rel.getLeft(), ignoreNulls);
}
 
示例30
public void onMatch(RelOptRuleCall call) {
  final Filter filter = call.rel(0);
  final Correlate corr = call.rel(1);

  final List<RexNode> aboveFilters =
      RelOptUtil.conjunctions(filter.getCondition());

  final List<RexNode> leftFilters = new ArrayList<>();
  final List<RexNode> rightFilters = new ArrayList<>();

  // Try to push down above filters. These are typically where clause
  // filters. They can be pushed down if they are not on the NULL
  // generating side.
  RelOptUtil.classifyFilters(
      corr,
      aboveFilters,
      corr.getJoinType(),
      false,
      true,
      !corr.getJoinType().generatesNullsOnRight(),
      aboveFilters,
      leftFilters,
      rightFilters);

  if (leftFilters.isEmpty()
      && rightFilters.isEmpty()) {
    // no filters got pushed
    return;
  }

  // Create Filters on top of the children if any filters were
  // pushed to them.
  final RexBuilder rexBuilder = corr.getCluster().getRexBuilder();
  final RelBuilder relBuilder = call.builder();
  final RelNode leftRel =
      relBuilder.push(corr.getLeft()).filter(leftFilters).build();
  final RelNode rightRel =
      relBuilder.push(corr.getRight()).filter(rightFilters).build();

  // Create the new Correlate
  RelNode newCorrRel =
      corr.copy(corr.getTraitSet(), ImmutableList.of(leftRel, rightRel));

  call.getPlanner().onCopy(corr, newCorrRel);

  if (!leftFilters.isEmpty()) {
    call.getPlanner().onCopy(filter, leftRel);
  }
  if (!rightFilters.isEmpty()) {
    call.getPlanner().onCopy(filter, rightRel);
  }

  // Create a Filter on top of the join if needed
  relBuilder.push(newCorrRel);
  relBuilder.filter(
      RexUtil.fixUp(rexBuilder, aboveFilters,
          RelOptUtil.getFieldTypeList(relBuilder.peek().getRowType())));

  call.transformTo(relBuilder.build());
}