@Override
  public List<PlanNode> visitJoin(JoinNode node, PlanContext context) {

    List<PlanNode> leftChildrenNodes = node.getLeftChild().accept(this, context);
    List<PlanNode> rightChildrenNodes = node.getRightChild().accept(this, context);
    if (!node.isCrossJoin()) {
      // child of JoinNode(excluding CrossJoin) must be SortNode, so after rewritten, the child must
      // be MergeSortNode or
      // SortNode
      checkArgument(
          leftChildrenNodes.size() == 1, "The size of left children node of JoinNode should be 1");
      checkArgument(
          rightChildrenNodes.size() == 1,
          "The size of right children node of JoinNode should be 1");
    }

    OrderingScheme leftChildOrdering = nodeOrderingMap.get(node.getLeftChild().getPlanNodeId());
    OrderingScheme rightChildOrdering = nodeOrderingMap.get(node.getRightChild().getPlanNodeId());

    // For CrossJoinNode, we need to merge children nodes(It's safe for other JoinNodes here since
    // the size of their children is always 1.)
    node.setLeftChild(mergeChildrenViaCollectOrMergeSort(leftChildOrdering, leftChildrenNodes));
    node.setRightChild(mergeChildrenViaCollectOrMergeSort(rightChildOrdering, rightChildrenNodes));

    // Now the join implement but CROSS is MergeSortJoin, so it can keep order
    if (!node.isCrossJoin() && !node.getAsofCriteria().isPresent()) {
      switch (node.getJoinType()) {
        case FULL:
          // If join type is FULL Join, we will process SortProperties in ProjectNode above this
          // node.
          break;
        case INNER:
        case LEFT:
          if (ImmutableSet.copyOf(node.getLeftOutputSymbols())
              .containsAll(leftChildOrdering.getOrderBy())) {
            nodeOrderingMap.put(node.getPlanNodeId(), leftChildOrdering);
          }
          break;
        case RIGHT:
          throw new IllegalStateException(
              "RIGHT Join should be transformed to LEFT Join in previous process");
        default:
          throw new UnsupportedOperationException("Unsupported Join Type: " + node.getJoinType());
      }
    }
    return Collections.singletonList(node);
  }
This class is used to generate distributed plan for table model.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableDistributedPlanGenerator.java