@Test
  public void testConsumeAllChildrenPipelineBuilder3() throws IllegalPathException {
    TypeProvider typeProvider = new TypeProvider();
    FullOuterTimeJoinNode fullOuterTimeJoinNode = initFullOuterTimeJoinNode(typeProvider, 4);
    LocalExecutionPlanContext context = createLocalExecutionPlanContext(typeProvider);
    context.setDegreeOfParallelism(3);

    List<Operator> childrenOperator =
        operatorTreeGenerator.dealWithConsumeAllChildrenPipelineBreaker(
            fullOuterTimeJoinNode, context);
    // The number of pipeline is 2, since parent pipeline hasn't joined
    assertEquals(2, context.getPipelineNumber());

    // Validate the first pipeline
    assertEquals(3, childrenOperator.size());
    assertEquals(SeriesScanOperator.class, childrenOperator.get(0).getClass());
    assertEquals(ExchangeOperator.class, childrenOperator.get(1).getClass());
    assertEquals(ExchangeOperator.class, childrenOperator.get(2).getClass());

    // Validate the changes of node structure
    assertEquals(3, fullOuterTimeJoinNode.getChildren().size());
    assertEquals(
        "root.sg.d0.s1", fullOuterTimeJoinNode.getChildren().get(0).getOutputColumnNames().get(0));
    assertEquals(
        "root.sg.d1.s1", fullOuterTimeJoinNode.getChildren().get(1).getOutputColumnNames().get(0));
    assertEquals(
        FullOuterTimeJoinNode.class, fullOuterTimeJoinNode.getChildren().get(2).getClass());

    // Validate the second pipeline
    ExchangeOperator exchangeOperator1 = (ExchangeOperator) childrenOperator.get(1);
    assertEquals("SeriesScanNode1", exchangeOperator1.getSourceId().getId());

    // Validate the third pipeline
    FullOuterTimeJoinNode subFullOuterTimeJoinNode =
        (FullOuterTimeJoinNode) fullOuterTimeJoinNode.getChildren().get(2);
    assertEquals(2, subFullOuterTimeJoinNode.getChildren().size());
    assertEquals(
        "root.sg.d2.s1",
        subFullOuterTimeJoinNode.getChildren().get(0).getOutputColumnNames().get(0));
    assertEquals(
        "root.sg.d3.s1",
        subFullOuterTimeJoinNode.getChildren().get(1).getOutputColumnNames().get(0));
    ExchangeOperator exchangeOperator2 = (ExchangeOperator) childrenOperator.get(2);
    assertEquals(exchangeOperator2.getSourceId(), subFullOuterTimeJoinNode.getPlanNodeId());

    // Validate the number exchange operator
    assertEquals(2, context.getExchangeSumNum());

    // Validate PipelineMemoryEstimator
    try (Operator root =
        fullOuterTimeJoinNode.accept(
            operatorTreeGenerator, createLocalExecutionPlanContext(typeProvider))) {
      PipelineMemoryEstimator rootPipelineMemoryEstimator =
          context.constructPipelineMemoryEstimator(root, null, fullOuterTimeJoinNode, -1);
      assertEquals(
          ConsumeAllChildrenPipelineMemoryEstimator.class, rootPipelineMemoryEstimator.getClass());
      List<PipelineMemoryEstimator> childrenPipelineMemoryEstimators =
          rootPipelineMemoryEstimator.getChildren();
      assertEquals(2, childrenPipelineMemoryEstimators.size());
      for (int i = 0; i < 2; i++) {
        assertEquals(
            ConsumeAllChildrenPipelineMemoryEstimator.class,
            childrenPipelineMemoryEstimators.get(i).getClass());
        if (i == 0) {
          assertEquals(
              SeriesScanOperator.class,
              childrenPipelineMemoryEstimators.get(i).getRoot().getClass());
        } else {
          assertEquals(
              FullOuterTimeJoinOperator.class,
              childrenPipelineMemoryEstimators.get(i).getRoot().getClass());
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail();
    }
  }
This test will test dop = 3. Expected result is three pipelines:

<p>The first is: TimeJoin1 - [SeriesScan0, ExchangeOperator, ExchangeOperator];

<p>The second is: ExchangeOperator - SeriesScan1.

<p>The third is: ExchangeOperator - TimeJoin1-1[SeriesScan2, SeriesScan3].
iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/PipelineBuilderTest.java