private void analyzeWindowDefinitions(QuerySpecification node, Scope scope) {
      for (WindowDefinition windowDefinition : node.getWindows()) {
        CanonicalizationAware<Identifier> canonicalName =
            canonicalizationAwareKey(windowDefinition.getName());

        if (analysis.getWindowDefinition(node, canonicalName) != null) {
          throw new SemanticException(
              String.format(
                  "WINDOW name '%s' specified more than once", windowDefinition.getName()));
        }

        Analysis.ResolvedWindow resolvedWindow =
            resolveWindowSpecification(node, windowDefinition.getWindow());

        // Analyze window after it is resolved, because resolving might provide necessary
        // information, e.g. ORDER BY necessary for frame analysis.
        // Analyze only newly introduced window properties. Properties of the referenced window have
        // been already analyzed.
        analyzeWindow(node, resolvedWindow, scope, windowDefinition.getWindow());

        analysis.addWindowDefinition(node, canonicalName, resolvedWindow);
      }
    }
Visitor context represents local query scope (if exists). The invariant is that the local query
scopes hierarchy should always have outer query scope (if provided) as ancestor.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java