private GroupByComponent parseGroupByClause(
      GroupByAttributeClauseContext ctx, WindowType windowType) {

    boolean ignoringNull = true;
    if (ctx.attributePair() != null
        && !ctx.attributePair().isEmpty()
        && ctx.attributePair().key.getText().equalsIgnoreCase(IGNORENULL)) {
      ignoringNull = Boolean.parseBoolean(ctx.attributePair().value.getText());
    }
    List<ExpressionContext> expressions = ctx.expression();
    if (windowType == WindowType.VARIATION_WINDOW) {
      ExpressionContext expressionContext = expressions.get(0);
      GroupByVariationComponent groupByVariationComponent = new GroupByVariationComponent();
      Expression expression = parseExpression(expressionContext, true);
      if (expression.isConstantOperand()) {
        throw new SemanticException(
            String.format(
                "Constant operand [%s] is not allowed in group by variation, there should be an expression",
                expression.getExpressionString()));
      }
      groupByVariationComponent.setControlColumnExpression(expression);
      groupByVariationComponent.setDelta(
          ctx.delta == null ? 0 : Double.parseDouble(ctx.delta.getText()));
      groupByVariationComponent.setIgnoringNull(ignoringNull);
      return groupByVariationComponent;
    } else if (windowType == WindowType.CONDITION_WINDOW) {
      ExpressionContext conditionExpressionContext = expressions.get(0);
      GroupByConditionComponent groupByConditionComponent = new GroupByConditionComponent();
      groupByConditionComponent.setControlColumnExpression(
          parseExpression(conditionExpressionContext, true));
      if (expressions.size() == 2) {
        groupByConditionComponent.setKeepExpression(parseExpression(expressions.get(1), true));
      } else {
        throw new SemanticException("Keep threshold in group by condition should be set");
      }
      groupByConditionComponent.setIgnoringNull(ignoringNull);
      return groupByConditionComponent;
    } else if (windowType == WindowType.SESSION_WINDOW) {
      long interval = DateTimeUtils.convertDurationStrToLong(ctx.timeInterval.getText());
      return new GroupBySessionComponent(interval);
    } else if (windowType == WindowType.COUNT_WINDOW) {
      ExpressionContext countExpressionContext = expressions.get(0);
      long countNumber = Long.parseLong(ctx.countNumber.getText());
      GroupByCountComponent groupByCountComponent = new GroupByCountComponent(countNumber);
      Expression expression = parseExpression(countExpressionContext, true);
      if (expression.isConstantOperand()) {
        throw new SemanticException(
            String.format(
                "Constant operand [%s] is not allowed in group by count, there should be an expression",
                expression.getExpressionString()));
      }
      groupByCountComponent.setControlColumnExpression(expression);
      groupByCountComponent.setIgnoringNull(ignoringNull);
      return groupByCountComponent;
    } else {
      throw new SemanticException("Unsupported window type");
    }
  }
Parse time range (startTime and endTime) in group by time.

@throws SemanticException if startTime is larger or equals to endTime in timeRange
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java