private boolean tryProcessRecursiveQuery(
        WithQuery withQuery, String name, Scope.Builder withScopeBuilder) {
      if (!withQuery.getColumnNames().isPresent()) {
        throw new SemanticException("missing column aliases in recursive WITH query");
      }
      preOrder(withQuery.getQuery())
          .filter(child -> child instanceof With && ((With) child).isRecursive())
          .findFirst()
          .ifPresent(
              child -> {
                throw new SemanticException("nested recursive WITH query");
              });
      // if RECURSIVE is specified, all queries in the WITH list are considered potentially
      // recursive
      // try resolve WITH query as expandable query
      // a) validate shape of the query and location of recursive reference
      if (!(withQuery.getQuery().getQueryBody() instanceof Union)) {
        return false;
      }
      Union union = (Union) withQuery.getQuery().getQueryBody();
      if (union.getRelations().size() != 2) {
        return false;
      }
      Relation anchor = union.getRelations().get(0);
      Relation step = union.getRelations().get(1);
      List<Node> anchorReferences = findReferences(anchor, withQuery.getName());
      if (!anchorReferences.isEmpty()) {
        throw new SemanticException(
            "WITH table name is referenced in the base relation of recursion");
      }
      // a WITH query is linearly recursive if it has a single recursive reference
      List<Node> stepReferences = findReferences(step, withQuery.getName());
      if (stepReferences.size() > 1) {
        throw new SemanticException(
            "multiple recursive references in the step relation of recursion");
      }
      if (stepReferences.size() != 1) {
        return false;
      }
      // search for QuerySpecification in parenthesized subquery
      Relation specification = step;
      while (specification instanceof TableSubquery) {
        Query query = ((TableSubquery) specification).getQuery();
        query
            .getLimit()
            .ifPresent(
                limit -> {
                  throw new SemanticException(
                      "FETCH FIRST / LIMIT clause in the step relation of recursion");
                });
        specification = query.getQueryBody();
      }
      if (!(specification instanceof QuerySpecification)
          || !((QuerySpecification) specification).getFrom().isPresent()) {
        throw new SemanticException(
            "recursive reference outside of FROM clause of the step relation of recursion");
      }
      Relation from = ((QuerySpecification) specification).getFrom().get();
      List<Node> fromReferences = findReferences(from, withQuery.getName());
      if (fromReferences.isEmpty()) {
        throw new SemanticException(
            "recursive reference outside of FROM clause of the step relation of recursion");
      }

      // b) validate top-level shape of recursive query
      withQuery
          .getQuery()
          .getWith()
          .ifPresent(
              innerWith -> {
                throw new SemanticException(
                    "immediate WITH clause in recursive query is not supported");
              });
      withQuery
          .getQuery()
          .getFill()
          .ifPresent(
              orderBy -> {
                throw new SemanticException(
                    "immediate FILL clause in recursive query is not supported");
              });
      withQuery
          .getQuery()
          .getOrderBy()
          .ifPresent(
              orderBy -> {
                throw new SemanticException(
                    "immediate ORDER BY clause in recursive query is not supported");
              });
      withQuery
          .getQuery()
          .getOffset()
          .ifPresent(
              offset -> {
                throw new SemanticException(
                    "immediate OFFSET clause in recursive query is not supported");
              });
      withQuery
          .getQuery()
          .getLimit()
          .ifPresent(
              limit -> {
                throw new SemanticException(
                    "immediate FETCH FIRST / LIMIT clause in recursive query is not support");
              });

      // c) validate recursion step has no illegal clauses
      validateFromClauseOfRecursiveTerm(from, withQuery.getName());

      // shape validation complete - process query as expandable query
      Scope parentScope = withScopeBuilder.build();
      // process expandable query -- anchor
      Scope anchorScope = process(anchor, parentScope);
      // set aliases in anchor scope as defined for WITH query. Recursion step will refer to anchor
      // fields by aliases.
      Scope aliasedAnchorScope =
          setAliases(anchorScope, withQuery.getName(), withQuery.getColumnNames().get());
      // record expandable query base scope for recursion step analysis
      Node recursiveReference = fromReferences.get(0);
      analysis.setExpandableBaseScope(recursiveReference, aliasedAnchorScope);
      // process expandable query -- recursion step
      Scope stepScope = process(step, parentScope);

      // verify anchor and step have matching descriptors
      RelationType anchorType = aliasedAnchorScope.getRelationType().withOnlyVisibleFields();
      RelationType stepType = stepScope.getRelationType().withOnlyVisibleFields();
      if (anchorType.getVisibleFieldCount() != stepType.getVisibleFieldCount()) {
        throw new SemanticException(
            String.format(
                "base and step relations of recursion have different number of fields: %s, %s",
                anchorType.getVisibleFieldCount(), stepType.getVisibleFieldCount()));
      }

      List<Type> anchorFieldTypes =
          anchorType.getVisibleFields().stream().map(Field::getType).collect(toImmutableList());
      List<Type> stepFieldTypes =
          stepType.getVisibleFields().stream().map(Field::getType).collect(toImmutableList());

      for (int i = 0; i < anchorFieldTypes.size(); i++) {
        if (stepFieldTypes.get(i) != anchorFieldTypes.get(i)) {
          // TODO for more precise error location, pass the mismatching select expression instead of
          // `step`
          throw new SemanticException(
              String.format(
                  "recursion step relation output type (%s) is not coercible to recursion base relation output type (%s) at column %s",
                  stepFieldTypes.get(i), anchorFieldTypes.get(i), i + 1));
        }
      }

      if (!anchorFieldTypes.equals(stepFieldTypes)) {
        analysis.addRelationCoercion(step, anchorFieldTypes.toArray(new Type[0]));
      }

      analysis.setScope(withQuery.getQuery(), aliasedAnchorScope);
      analysis.registerExpandableQuery(withQuery.getQuery(), recursiveReference);
      withScopeBuilder.withNamedQuery(name, withQuery);
      return true;
    }
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