org.apache.calcite.rel.core.Correlate Java Examples

The following examples show how to use org.apache.calcite.rel.core.Correlate. 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: RelMetadataTest.java    From calcite with Apache License 2.0 6 votes vote down vote up
@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);
  }
}
 
Example #2
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 6 votes vote down vote up
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;
  };
}
 
Example #3
Source File: RelToSqlConverter.java    From calcite with Apache License 2.0 6 votes vote down vote up
/** @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);
}
 
Example #4
Source File: FilterCorrelateRule.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a FilterCorrelateRule.
 */
public FilterCorrelateRule(RelBuilderFactory builderFactory) {
  super(
      operand(Filter.class,
          operand(Correlate.class, RelOptRule.any())),
      builderFactory, "FilterCorrelateRule");
}
 
Example #5
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 5 votes vote down vote up
@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);
}
 
Example #6
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 5 votes vote down vote up
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;
}
 
Example #7
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 5 votes vote down vote up
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);
}
 
Example #8
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 5 votes vote down vote up
RemoveCorrelationForScalarProjectRule(RelBuilderFactory relBuilderFactory) {
  super(
      operand(Correlate.class,
          operand(RelNode.class, any()),
          operand(Aggregate.class,
              operand(Project.class,
                  operand(RelNode.class, any())))),
      relBuilderFactory, null);
}
 
Example #9
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 5 votes vote down vote up
@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;
}
 
Example #10
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * 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();
}
 
Example #11
Source File: ProjectCorrelateTransposeRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
public ProjectCorrelateTransposeRule(
    PushProjector.ExprCondition preserveExprCondition,
    RelBuilderFactory relFactory) {
  super(
      operand(Project.class,
          operand(Correlate.class, any())),
      relFactory, null);
  this.preserveExprCondition = preserveExprCondition;
}
 
Example #12
Source File: FilterCorrelateRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a FilterCorrelateRule.
 */
public FilterCorrelateRule(RelBuilderFactory builderFactory) {
  super(
      operand(Filter.class,
          operand(Correlate.class, RelOptRule.any())),
      builderFactory, "FilterCorrelateRule");
}
 
Example #13
Source File: PostOrderRelNodeVisitor.java    From streamline with Apache License 2.0 5 votes vote down vote up
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);
  }
}
 
Example #14
Source File: RelDecorrelator.java    From flink with Apache License 2.0 5 votes vote down vote up
/**
 * 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();
}
 
Example #15
Source File: RelDecorrelator.java    From flink with Apache License 2.0 5 votes vote down vote up
/**
 * 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();
}
 
Example #16
Source File: RelDecorrelator.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * 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();
}
 
Example #17
Source File: DrillProjectLateralJoinTransposeRule.java    From Bats with Apache License 2.0 5 votes vote down vote up
@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;
}
 
Example #18
Source File: LateralJoinPrel.java    From Bats with Apache License 2.0 5 votes vote down vote up
@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());
}
 
Example #19
Source File: CorrelateRel.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@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);
}
 
Example #20
Source File: DrillLateralJoinRel.java    From Bats with Apache License 2.0 5 votes vote down vote up
@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());
}
 
Example #21
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 4 votes vote down vote up
public Frame decorrelateRel(LogicalCorrelate rel) {
  return decorrelateRel((Correlate) rel);
}
 
Example #22
Source File: RelMdUniqueKeys.java    From Bats with Apache License 2.0 4 votes vote down vote up
public Set<ImmutableBitSet> getUniqueKeys(Correlate rel, RelMetadataQuery mq,
    boolean ignoreNulls) {
  return mq.getUniqueKeys(rel.getLeft(), ignoreNulls);
}
 
Example #23
Source File: SqlToRelTestBase.java    From calcite with Apache License 2.0 4 votes vote down vote up
@Override public Correlate copy(RelTraitSet traitSet,
    RelNode left, RelNode right, CorrelationId correlationId,
    ImmutableBitSet requiredColumns, JoinRelType joinType) {
  return new CustomCorrelate(getCluster(), traitSet, left, right,
      correlationId, requiredColumns, joinType);
}
 
Example #24
Source File: FilterCorrelateRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
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());
}
 
Example #25
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 4 votes vote down vote up
private void onMatch2(
    RelOptRuleCall call,
    Correlate correlate,
    RelNode leftInput,
    Project aggOutputProject,
    Aggregate aggregate) {
  if (generatedCorRels.contains(correlate)) {
    // This Correlate was generated by a previous invocation of
    // this rule. No further work to do.
    return;
  }

  setCurrent(call.getPlanner().getRoot(), correlate);

  // check for this pattern
  // The pattern matching could be simplified if rules can be applied
  // during decorrelation,
  //
  // CorrelateRel(left correlation, condition = true)
  //   leftInput
  //   Project-A (a RexNode)
  //     Aggregate (groupby (0), agg0(), agg1()...)

  // check aggOutputProj projects only one expression
  List<RexNode> aggOutputProjExprs = aggOutputProject.getProjects();
  if (aggOutputProjExprs.size() != 1) {
    return;
  }

  JoinRelType joinType = correlate.getJoinType();
  // corRel.getCondition was here, however Correlate was updated so it
  // never includes a join condition. The code was not modified for brevity.
  RexNode joinCond = relBuilder.literal(true);
  if ((joinType != JoinRelType.LEFT)
      || (joinCond != relBuilder.literal(true))) {
    return;
  }

  // check that the agg is on the entire input
  if (!aggregate.getGroupSet().isEmpty()) {
    return;
  }

  List<AggregateCall> aggCalls = aggregate.getAggCallList();
  Set<Integer> isCount = new HashSet<>();

  // remember the count() positions
  int i = -1;
  for (AggregateCall aggCall : aggCalls) {
    ++i;
    if (aggCall.getAggregation() instanceof SqlCountAggFunction) {
      isCount.add(i);
    }
  }

  // now rewrite the plan to
  //
  // Project-A' (all LHS plus transformed original projections,
  //             replacing references to count() with case statement)
  //   Correlate(left correlation, condition = true)
  //     leftInput
  //     Aggregate(groupby (0), agg0(), agg1()...)
  //
  List<RexNode> requiredNodes =
      correlate.getRequiredColumns().asList().stream()
          .map(ord -> relBuilder.getRexBuilder().makeInputRef(correlate, ord))
          .collect(Collectors.toList());
  Correlate newCorrelate = (Correlate) relBuilder.push(leftInput)
      .push(aggregate).correlate(correlate.getJoinType(),
          correlate.getCorrelationId(),
          requiredNodes).build();


  // remember this rel so we don't fire rule on it again
  // REVIEW jhyde 29-Oct-2007: rules should not save state; rule
  // should recognize patterns where it does or does not need to do
  // work
  generatedCorRels.add(newCorrelate);

  // need to update the mapCorToCorRel Update the output position
  // for the corVars: only pass on the corVars that are not used in
  // the join key.
  if (cm.mapCorToCorRel.get(correlate.getCorrelationId()) == correlate) {
    cm.mapCorToCorRel.put(correlate.getCorrelationId(), newCorrelate);
  }

  RelNode newOutput =
      aggregateCorrelatorOutput(newCorrelate, aggOutputProject, isCount);

  call.transformTo(newOutput);
}
 
Example #26
Source File: ProjectCorrelateTransposeRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
public ProjectCorrelateTransposeRule(PushProjector.ExprCondition preserveExprCondition,
        RelBuilderFactory relFactory) {
    super(operand(Project.class, operand(Correlate.class, any())), relFactory, null);
    this.preserveExprCondition = preserveExprCondition;
}
 
Example #27
Source File: ProjectCorrelateTransposeRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
@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);
}
 
Example #28
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Remove correlated variables from the tree at root corRel
 *
 * @param correlate Correlate
 */
private void removeCorVarFromTree(Correlate correlate) {
  if (cm.mapCorToCorRel.get(correlate.getCorrelationId()) == correlate) {
    cm.mapCorToCorRel.remove(correlate.getCorrelationId());
  }
}
 
Example #29
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Checks whether the correlations in projRel and filter are related to
 * the correlated variables provided by corRel.
 *
 * @param correlate    Correlate
 * @param project   The original Project as the RHS input of the join
 * @param filter    Filter
 * @param correlatedJoinKeys Correlated join keys
 * @return true if filter and proj only references corVar provided by corRel
 */
private boolean checkCorVars(
    Correlate correlate,
    Project project,
    Filter filter,
    List<RexFieldAccess> correlatedJoinKeys) {
  if (filter != null) {
    assert correlatedJoinKeys != null;

    // check that all correlated refs in the filter condition are
    // used in the join(as field access).
    Set<CorRef> corVarInFilter =
        Sets.newHashSet(cm.mapRefRelToCorRef.get(filter));

    for (RexFieldAccess correlatedJoinKey : correlatedJoinKeys) {
      corVarInFilter.remove(cm.mapFieldAccessToCorRef.get(correlatedJoinKey));
    }

    if (!corVarInFilter.isEmpty()) {
      return false;
    }

    // Check that the correlated variables referenced in these
    // comparisons do come from the Correlate.
    corVarInFilter.addAll(cm.mapRefRelToCorRef.get(filter));

    for (CorRef corVar : corVarInFilter) {
      if (cm.mapCorToCorRel.get(corVar.corr) != correlate) {
        return false;
      }
    }
  }

  // if project has any correlated reference, make sure they are also
  // provided by the current correlate. They will be projected out of the LHS
  // of the correlate.
  if ((project != null) && cm.mapRefRelToCorRef.containsKey(project)) {
    for (CorRef corVar : cm.mapRefRelToCorRef.get(project)) {
      if (cm.mapCorToCorRel.get(corVar.corr) != correlate) {
        return false;
      }
    }
  }

  return true;
}
 
Example #30
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 4 votes vote down vote up
public Frame decorrelateRel(Correlate rel) {
  //
  // Rewrite logic:
  //
  // The original left input will be joined with the new right input that
  // has generated correlated variables propagated up. For any generated
  // corVars that are not used in the join key, pass them along to be
  // joined later with the Correlates that produce them.
  //

  // the right input to Correlate should produce correlated variables
  final RelNode oldLeft = rel.getInput(0);
  final RelNode oldRight = rel.getInput(1);

  final Frame leftFrame = getInvoke(oldLeft, rel);
  final Frame rightFrame = getInvoke(oldRight, rel);

  if (leftFrame == null || rightFrame == null) {
    // If any input has not been rewritten, do not rewrite this rel.
    return null;
  }

  if (rightFrame.corDefOutputs.isEmpty()) {
    return null;
  }

  assert rel.getRequiredColumns().cardinality()
      <= rightFrame.corDefOutputs.keySet().size();

  // Change correlator rel into a join.
  // Join all the correlated variables produced by this correlator rel
  // with the values generated and propagated from the right input
  final SortedMap<CorDef, Integer> corDefOutputs =
      new TreeMap<>(rightFrame.corDefOutputs);
  final List<RexNode> conditions = new ArrayList<>();
  final List<RelDataTypeField> newLeftOutput =
      leftFrame.r.getRowType().getFieldList();
  int newLeftFieldCount = newLeftOutput.size();

  final List<RelDataTypeField> newRightOutput =
      rightFrame.r.getRowType().getFieldList();

  for (Map.Entry<CorDef, Integer> rightOutput
      : new ArrayList<>(corDefOutputs.entrySet())) {
    final CorDef corDef = rightOutput.getKey();
    if (!corDef.corr.equals(rel.getCorrelationId())) {
      continue;
    }
    final int newLeftPos = leftFrame.oldToNewOutputs.get(corDef.field);
    final int newRightPos = rightOutput.getValue();
    conditions.add(
        relBuilder.call(SqlStdOperatorTable.EQUALS,
            RexInputRef.of(newLeftPos, newLeftOutput),
            new RexInputRef(newLeftFieldCount + newRightPos,
                newRightOutput.get(newRightPos).getType())));

    // remove this corVar from output position mapping
    corDefOutputs.remove(corDef);
  }

  // Update the output position for the corVars: only pass on the cor
  // vars that are not used in the join key.
  for (CorDef corDef : corDefOutputs.keySet()) {
    int newPos = corDefOutputs.get(corDef) + newLeftFieldCount;
    corDefOutputs.put(corDef, newPos);
  }

  // then add any corVar from the left input. Do not need to change
  // output positions.
  corDefOutputs.putAll(leftFrame.corDefOutputs);

  // Create the mapping between the output of the old correlation rel
  // and the new join rel
  final Map<Integer, Integer> mapOldToNewOutputs = new HashMap<>();

  int oldLeftFieldCount = oldLeft.getRowType().getFieldCount();

  int oldRightFieldCount = oldRight.getRowType().getFieldCount();
  //noinspection AssertWithSideEffects
  assert rel.getRowType().getFieldCount()
      == oldLeftFieldCount + oldRightFieldCount;

  // Left input positions are not changed.
  mapOldToNewOutputs.putAll(leftFrame.oldToNewOutputs);

  // Right input positions are shifted by newLeftFieldCount.
  for (int i = 0; i < oldRightFieldCount; i++) {
    mapOldToNewOutputs.put(i + oldLeftFieldCount,
        rightFrame.oldToNewOutputs.get(i) + newLeftFieldCount);
  }

  final RexNode condition =
      RexUtil.composeConjunction(relBuilder.getRexBuilder(), conditions);
  RelNode newJoin = relBuilder.push(leftFrame.r).push(rightFrame.r)
      .join(rel.getJoinType(), condition).build();

  return register(rel, newJoin, mapOldToNewOutputs, corDefOutputs);
}