@Override
  public Operator visitColumnInject(ColumnInjectNode node, LocalExecutionPlanContext context) {
    final OperatorContext operatorContext =
        context
            .getDriverContext()
            .addOperatorContext(
                context.getNextOperatorId(),
                node.getPlanNodeId(),
                ColumnInjectNode.class.getSimpleName());

    Operator childOperator = node.getChild().accept(this, context);
    ColumnGeneratorParameter parameter = node.getColumnGeneratorParameter();
    ColumnGenerator columnGenerator =
        genColumnGeneratorAccordingToParameter(parameter, context.getZoneId());
    long maxExtraColumnSize = 0;
    for (TSDataType dataType : node.getGeneratedColumnTypes()) {
      maxExtraColumnSize += getOutputColumnSizePerLine(dataType);
    }
    maxExtraColumnSize *= TSFileDescriptor.getInstance().getConfig().getMaxTsBlockLineNumber();

    return new ColumnInjectOperator(
        operatorContext, childOperator, columnGenerator, node.getTargetIndex(), maxExtraColumnSize);
  }
Now, we allocate children to each pipeline as average as possible. For example, 5 children with
3 dop, the children group will be [1, 2, 2]. After we can estimate the workload of each
operator, maybe we can allocate based on workload rather than child number.

<p>If child is ExchangeNode, it won't affect the children number of current group.

<p>This method can only be invoked when dop <= localChildrenSize.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java