@Override
  public Result apply(CorrelatedJoinNode correlatedJoinNode, Captures captures, Context context) {
    checkArgument(
        correlatedJoinNode.getJoinType() == INNER || correlatedJoinNode.getJoinType() == LEFT,
        "correlation in %s JOIN",
        correlatedJoinNode.getJoinType().name());
    PlanNode subquery = correlatedJoinNode.getSubquery();

    PlanNodeDecorrelator planNodeDecorrelator =
        new PlanNodeDecorrelator(plannerContext, context.getSymbolAllocator(), context.getLookup());
    Optional<PlanNodeDecorrelator.DecorrelatedNode> decorrelatedNodeOptional =
        planNodeDecorrelator.decorrelateFilters(subquery, correlatedJoinNode.getCorrelation());
    if (!decorrelatedNodeOptional.isPresent()) {
      return Result.empty();
    }
    PlanNodeDecorrelator.DecorrelatedNode decorrelatedSubquery = decorrelatedNodeOptional.get();

    Expression filter =
        combineConjuncts(
            decorrelatedSubquery.getCorrelatedPredicates().orElse(TRUE_LITERAL),
            correlatedJoinNode.getFilter());

    return Result.ofPlanNode(
        new JoinNode(
            correlatedJoinNode.getPlanNodeId(),
            correlatedJoinNode.getJoinType(),
            correlatedJoinNode.getInput(),
            decorrelatedSubquery.getNode(),
            ImmutableList.of(),
            Optional.empty(),
            correlatedJoinNode.getInput().getOutputSymbols(),
            correlatedJoinNode.getSubquery().getOutputSymbols(),
            filter.equals(TRUE_LITERAL) ? Optional.empty() : Optional.of(filter),
            Optional.empty()));
  }
Tries to decorrelate subquery and rewrite it using normal join. Decorrelated predicates are part
of join condition.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/TransformCorrelatedJoinToJoin.java