@Override
  public PlanNode optimize(PlanNode plan, Analysis analysis, MPPQueryContext context) {
    if (analysis.getTreeStatement().getType() != StatementType.QUERY) {
      return plan;
    }
    QueryStatement queryStatement = analysis.getQueryStatement();
    if (queryStatement.isGroupByTime() && queryStatement.isOutputEndTime()) {
      // When the aggregation with GROUP BY TIME isn't rawDataQuery, there are AggregationNode and
      // SeriesAggregationNode,
      // If it is and has overlap in groupByParameter, there is SlidingWindowNode
      // There will be a ColumnInjectNode on them, so we need to check if it can be pushed down.
      return plan.accept(new Rewriter(), null);
    }
    return plan;
  }
<b>Optimization phase:</b> Distributed plan planning.

<p><b>Rules:</b>
<pre>1.
       ColumnInject
            |              ->  SeriesAggregationSource
 SeriesAggregationSource
<pre>2.
       ColumnInject
            |              ->        Aggregation
       Aggregation
<pre>3.
       ColumnInject
            |              ->     RawDataAggregation
    RawDataAggregation
<pre>4.
       ColumnInject
            |              ->  SlidingWindowAggregation
 SlidingWindowAggregation
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/optimization/ColumnInjectionPushDown.java