private void analyzeWindow(
        Analysis.ResolvedWindow window,
        StackableAstVisitorContext<Context> context,
        Node originalNode) {
      // check no nested window functions
      ImmutableList.Builder<Node> childNodes = ImmutableList.builder();
      if (!window.isPartitionByInherited()) {
        childNodes.addAll(window.getPartitionBy());
      }
      if (!window.isOrderByInherited()) {
        window.getOrderBy().ifPresent(orderBy -> childNodes.addAll(orderBy.getSortItems()));
      }
      if (!window.isFrameInherited()) {
        window.getFrame().ifPresent(childNodes::add);
      }

      if (!window.isPartitionByInherited()) {
        for (Expression expression : window.getPartitionBy()) {
          process(expression, context);
          Type type = getExpressionType(expression);
          if (!type.isComparable()) {
            throw new SemanticException(
                String.format(
                    "%s is not comparable, and therefore cannot be used in window function PARTITION BY",
                    type));
          }
        }
      }

      if (!window.isOrderByInherited()) {
        for (SortItem sortItem : getSortItemsFromOrderBy(window.getOrderBy())) {
          process(sortItem.getSortKey(), context);
          Type type = getExpressionType(sortItem.getSortKey());
          if (!type.isOrderable()) {
            throw new SemanticException(
                String.format(
                    "%s is not orderable, and therefore cannot be used in window function ORDER BY",
                    type));
          }
        }
      }

      if (window.getFrame().isPresent() && !window.isFrameInherited()) {
        WindowFrame frame = window.getFrame().get();

        // validate frame start and end types
        FrameBound.Type startType = frame.getStart().getType();
        FrameBound.Type endType =
            frame.getEnd().orElse(new FrameBound(null, CURRENT_ROW)).getType();
        if (startType == UNBOUNDED_FOLLOWING) {
          throw new SemanticException("Window frame start cannot be UNBOUNDED FOLLOWING");
        }
        if (endType == UNBOUNDED_PRECEDING) {
          throw new SemanticException("Window frame end cannot be UNBOUNDED PRECEDING");
        }
        if ((startType == CURRENT_ROW) && (endType == PRECEDING)) {
          throw new SemanticException(
              "Window frame starting from CURRENT ROW cannot end with PRECEDING");
        }
        if ((startType == FOLLOWING) && (endType == PRECEDING)) {
          throw new SemanticException(
              "Window frame starting from FOLLOWING cannot end with PRECEDING");
        }
        if ((startType == FOLLOWING) && (endType == CURRENT_ROW)) {
          throw new SemanticException(
              "Window frame starting from FOLLOWING cannot end with CURRENT ROW");
        }

        // analyze frame offset values
        if (frame.getType() == ROWS) {
          if (frame.getStart().getValue().isPresent()) {
            Expression startValue = frame.getStart().getValue().get();
            Type type = process(startValue, context);
            if (!isExactNumericWithScaleZero(type)) {
              throw new SemanticException(
                  String.format(
                      "Window frame ROWS start value type must be exact numeric type with scale 0 (actual %s)",
                      type));
            }
          }
          if (frame.getEnd().isPresent() && frame.getEnd().get().getValue().isPresent()) {
            Expression endValue = frame.getEnd().get().getValue().get();
            Type type = process(endValue, context);
            if (!isExactNumericWithScaleZero(type)) {
              throw new SemanticException(
                  String.format(
                      "Window frame ROWS end value type must be exact numeric type with scale 0 (actual %s)",
                      type));
            }
          }
        } else if (frame.getType() == RANGE) {
          if (frame.getStart().getValue().isPresent()) {
            Expression startValue = frame.getStart().getValue().get();
            analyzeFrameRangeOffset(
                startValue, frame.getStart().getType(), context, window, originalNode);
          }
          if (frame.getEnd().isPresent() && frame.getEnd().get().getValue().isPresent()) {
            Expression endValue = frame.getEnd().get().getValue().get();
            analyzeFrameRangeOffset(
                endValue, frame.getEnd().get().getType(), context, window, originalNode);
          }
        } else if (frame.getType() == GROUPS) {
          if (frame.getStart().getValue().isPresent()) {
            if (!window.getOrderBy().isPresent()) {
              throw new SemanticException(
                  "Window frame of type GROUPS PRECEDING or FOLLOWING requires ORDER BY");
            }
            Expression startValue = frame.getStart().getValue().get();
            Type type = process(startValue, context);
            if (!isExactNumericWithScaleZero(type)) {
              throw new SemanticException(
                  String.format(
                      "Window frame GROUPS start value type must be exact numeric type with scale 0 (actual %s)",
                      type));
            }
          }
          if (frame.getEnd().isPresent() && frame.getEnd().get().getValue().isPresent()) {
            if (!window.getOrderBy().isPresent()) {
              throw new SemanticException(
                  "Window frame of type GROUPS PRECEDING or FOLLOWING requires ORDER BY");
            }
            Expression endValue = frame.getEnd().get().getValue().get();
            Type type = process(endValue, context);
            if (!isExactNumericWithScaleZero(type)) {
              throw new SemanticException(
                  String.format(
                      "Window frame ROWS end value type must be exact numeric type with scale 0 (actual %s)",
                      type));
            }
          }
        } else {
          throw new SemanticException("Unsupported frame type: " + frame.getType());
        }
      }
    }
@return the common supertype between the value type and subquery type
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/ExpressionAnalyzer.java