static boolean canBuildAggregationPlanUseTemplate(
      Analysis analysis,
      QueryStatement queryStatement,
      IPartitionFetcher partitionFetcher,
      ISchemaTree schemaTree,
      MPPQueryContext context,
      Template template,
      List<PartialPath> deviceList) {

    // not support order by expression and non-aligned template
    if (queryStatement.hasOrderByExpression() || !template.isDirectAligned()) {
      return false;
    }

    analysis.setNoWhereAndAggregation(false);

    if (canPushDownLimitOffsetInGroupByTimeForDevice(queryStatement)) {
      // remove the device which won't appear in resultSet after limit/offset
      deviceList =
          pushDownLimitOffsetInGroupByTimeForDevice(
              deviceList, queryStatement, context.getZoneId());
    }

    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
    boolean valid = analyzeSelect(queryStatement, analysis, outputExpressions, template);
    if (!valid) {
      analysis.setDeviceTemplate(null);
      return false;
    }

    analyzeDeviceToWhere(analysis, queryStatement);
    if (deviceList.isEmpty()) {
      analysis.setFinishQueryAfterAnalyze(true);
      return true;
    }
    analysis.setDeviceList(deviceList);

    if (analysis.getWhereExpression() != null
        && ConstantOperand.FALSE.equals(analysis.getWhereExpression())) {
      analyzeOutput(analysis, queryStatement, outputExpressions);
      analysis.setFinishQueryAfterAnalyze(true);
      return true;
    }

    valid = analyzeHaving(analysis, queryStatement);
    if (!valid) {
      analysis.setDeviceTemplate(null);
      return false;
    }

    analyzeDeviceToExpressions(analysis);

    analyzeDeviceViewOutput(analysis, queryStatement);

    // generate result set header according to output expressions
    analyzeOutput(analysis, queryStatement, outputExpressions);

    analyzeGroupByTime(analysis, queryStatement);
    context.generateGlobalTimeFilter(analysis);

    // fetch partition information
    analyzeDataPartition(analysis, schemaTree, partitionFetcher, context);
    return true;
  }
Methods in this class are used for aggregation, templated with align by device situation.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java