private SqlNode registerFrom()

in core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java [2433:2812]


  private SqlNode registerFrom(
      SqlValidatorScope parentScope0,
      SqlValidatorScope usingScope,
      boolean register,
      final SqlNode node,
      SqlNode enclosingNode,
      @Nullable String alias,
      @Nullable SqlNodeList extendList,
      boolean forceNullable,
      final boolean lateral) {
    final SqlKind kind = node.getKind();

    SqlNode expr;
    SqlNode newExpr;

    // Add an alias if necessary.
    SqlNode newNode = node;
    if (alias == null) {
      switch (kind) {
      case IDENTIFIER:
      case OVER:
        alias = SqlValidatorUtil.alias(node);
        if (alias == null) {
          alias = SqlValidatorUtil.alias(node, nextGeneratedId++);
        }
        if (config.identifierExpansion()) {
          newNode = SqlValidatorUtil.addAlias(node, alias);
        }
        break;

      case SELECT:
      case UNION:
      case INTERSECT:
      case EXCEPT:
      case VALUES:
      case UNNEST:
      case OTHER_FUNCTION:
      case COLLECTION_TABLE:
      case PIVOT:
      case UNPIVOT:
      case MATCH_RECOGNIZE:
      case WITH:
        // give this anonymous construct a name since later
        // query processing stages rely on it
        alias = SqlValidatorUtil.alias(node, nextGeneratedId++);
        if (config.identifierExpansion()) {
          // Since we're expanding identifiers, we should make the
          // aliases explicit too, otherwise the expanded query
          // will not be consistent if we convert back to SQL, e.g.
          // "select EXPR$1.EXPR$2 from values (1)".
          newNode = SqlValidatorUtil.addAlias(node, alias);
        }
        break;
      default:
        break;
      }
    }

    final SqlValidatorScope parentScope;
    if (lateral) {
      SqlValidatorScope s = usingScope;
      while (s instanceof JoinScope) {
        s = ((JoinScope) s).getUsingScope();
      }
      final SqlNode node2 = s != null ? s.getNode() : node;
      final TableScope tableScope = new TableScope(parentScope0, node2);
      if (usingScope instanceof ListScope) {
        for (ScopeChild child : ((ListScope) usingScope).children) {
          tableScope.addChild(child.namespace, child.name, child.nullable);
        }
      }
      parentScope = tableScope;
    } else {
      parentScope = parentScope0;
    }

    SqlCall call;
    SqlNode operand;
    SqlNode newOperand;

    switch (kind) {
    case AS:
      call = (SqlCall) node;
      if (alias == null) {
        alias = String.valueOf(call.operand(1));
      }
      expr = call.operand(0);
      final boolean needAliasNamespace = call.operandCount() > 2
          || expr.getKind() == SqlKind.VALUES || expr.getKind() == SqlKind.UNNEST
          || expr.getKind() == SqlKind.COLLECTION_TABLE;
      newExpr =
          registerFrom(
              parentScope,
              usingScope,
              !needAliasNamespace,
              expr,
              enclosingNode,
              alias,
              extendList,
              forceNullable,
              lateral);
      if (newExpr != expr) {
        call.setOperand(0, newExpr);
      }

      // If alias has a column list, introduce a namespace to translate
      // column names. We skipped registering it just now.
      if (needAliasNamespace) {
        registerNamespace(
            usingScope,
            alias,
            new AliasNamespace(this, call, enclosingNode),
            forceNullable);
      }
      return node;

    case MATCH_RECOGNIZE:
      registerMatchRecognize(parentScope, usingScope,
          (SqlMatchRecognize) node, enclosingNode, alias, forceNullable);
      return node;

    case PIVOT:
      registerPivot(parentScope, usingScope, (SqlPivot) node, enclosingNode,
          alias, forceNullable);
      return node;

    case UNPIVOT:
      registerUnpivot(parentScope, usingScope, (SqlUnpivot) node, enclosingNode,
          alias, forceNullable);
      return node;

    case TABLESAMPLE:
      call = (SqlCall) node;
      expr = call.operand(0);
      newExpr =
          registerFrom(
              parentScope,
              usingScope,
              true,
              expr,
              enclosingNode,
              alias,
              extendList,
              forceNullable,
              lateral);
      if (newExpr != expr) {
        call.setOperand(0, newExpr);
      }
      return node;

    case JOIN:
      final SqlJoin join = (SqlJoin) node;
      final JoinScope joinScope =
          new JoinScope(parentScope, usingScope, join);
      scopes.put(join, joinScope);
      final SqlNode left = join.getLeft();
      final SqlNode right = join.getRight();
      boolean forceLeftNullable = forceNullable;
      boolean forceRightNullable = forceNullable;
      switch (join.getJoinType()) {
      case LEFT:
      case LEFT_ASOF:
        forceRightNullable = true;
        break;
      case RIGHT:
        forceLeftNullable = true;
        break;
      case FULL:
        forceLeftNullable = true;
        forceRightNullable = true;
        break;
      default:
        break;
      }
      final SqlNode newLeft =
          registerFrom(
              parentScope,
              joinScope,
              true,
              left,
              left,
              null,
              null,
              forceLeftNullable,
              lateral);
      if (newLeft != left) {
        join.setLeft(newLeft);
      }
      final SqlNode newRight =
          registerFrom(
              parentScope,
              joinScope,
              true,
              right,
              right,
              null,
              null,
              forceRightNullable,
              lateral);
      if (newRight != right) {
        join.setRight(newRight);
      }
      scopes.putIfAbsent(stripAs(join.getRight()), parentScope);
      scopes.putIfAbsent(stripAs(join.getLeft()), parentScope);
      registerSubQueries(joinScope, join.getCondition());
      final JoinNamespace joinNamespace = new JoinNamespace(this, join);
      registerNamespace(null, null, joinNamespace, forceNullable);
      return join;

    case IDENTIFIER:
      final SqlIdentifier id = (SqlIdentifier) node;
      final IdentifierNamespace newNs =
          new IdentifierNamespace(
              this, id, extendList, enclosingNode,
              parentScope);
      registerNamespace(register ? usingScope : null, alias, newNs,
          forceNullable);
      if (tableScope == null) {
        tableScope = new TableScope(parentScope, node);
      }
      tableScope.addChild(newNs, requireNonNull(alias, "alias"), forceNullable);
      if (extendList != null && !extendList.isEmpty()) {
        return enclosingNode;
      }
      return newNode;

    case LATERAL:
      return registerFrom(
          parentScope,
          usingScope,
          register,
          ((SqlCall) node).operand(0),
          enclosingNode,
          alias,
          extendList,
          forceNullable,
          true);

    case COLLECTION_TABLE:
      call = (SqlCall) node;
      operand = call.operand(0);
      newOperand =
          registerFrom(
              parentScope,
              usingScope,
              register,
              operand,
              enclosingNode,
              alias,
              extendList,
              forceNullable, lateral);
      if (newOperand != operand) {
        call.setOperand(0, newOperand);
      }
      // If the operator is SqlWindowTableFunction, restricts the scope as
      // its first operand's (the table) scope.
      if (operand instanceof SqlBasicCall) {
        final SqlBasicCall call1 = (SqlBasicCall) operand;
        final SqlOperator op = call1.getOperator();
        if (op instanceof SqlWindowTableFunction
            && call1.operand(0).getKind() == SqlKind.SELECT) {
          scopes.put(node, getSelectScope(call1.operand(0)));
          return newNode;
        }
      }
      // Put the usingScope which can be a JoinScope
      // or a SelectScope, in order to see the left items
      // of the JOIN tree.
      scopes.put(node, usingScope);
      return newNode;

    case UNNEST:
      if (!lateral) {
        return registerFrom(parentScope, usingScope, register, node,
            enclosingNode, alias, extendList, forceNullable, true);
      }
    // fall through
    case SELECT:
    case UNION:
    case INTERSECT:
    case EXCEPT:
    case VALUES:
    case WITH:
    case OTHER_FUNCTION:
      if (alias == null) {
        alias = SqlValidatorUtil.alias(node, nextGeneratedId++);
      }
      registerQuery(
          parentScope,
          register ? usingScope : null,
          node,
          enclosingNode,
          alias,
          forceNullable);
      return newNode;

    case OVER:
      if (!shouldAllowOverRelation()) {
        throw Util.unexpected(kind);
      }
      call = (SqlCall) node;
      final OverScope overScope = new OverScope(usingScope, call);
      scopes.put(call, overScope);
      operand = call.operand(0);
      newOperand =
          registerFrom(
              parentScope,
              overScope,
              true,
              operand,
              enclosingNode,
              alias,
              extendList,
              forceNullable,
              lateral);
      if (newOperand != operand) {
        call.setOperand(0, newOperand);
      }

      for (ScopeChild child : overScope.children) {
        registerNamespace(register ? usingScope : null, child.name,
            child.namespace, forceNullable);
      }

      return newNode;

    case TABLE_REF:
      call = (SqlCall) node;
      registerFrom(parentScope,
          usingScope,
          register,
          call.operand(0),
          enclosingNode,
          alias,
          extendList,
          forceNullable,
          lateral);
      if (extendList != null && !extendList.isEmpty()) {
        return enclosingNode;
      }
      return newNode;

    case EXTEND:
      final SqlCall extend = (SqlCall) node;
      return registerFrom(parentScope,
          usingScope,
          true,
          extend.getOperandList().get(0),
          extend,
          alias,
          (SqlNodeList) extend.getOperandList().get(1),
          forceNullable,
          lateral);

    case SNAPSHOT:
      call = (SqlCall) node;
      operand = call.operand(0);
      newOperand =
          registerFrom(parentScope,
              usingScope,
              register,
              operand,
              enclosingNode,
              alias,
              extendList,
              forceNullable,
              lateral);
      if (newOperand != operand) {
        call.setOperand(0, newOperand);
      }
      // Put the usingScope which can be a JoinScope
      // or a SelectScope, in order to see the left items
      // of the JOIN tree.
      scopes.put(node, usingScope);
      return newNode;

    default:
      throw Util.unexpected(kind);
    }
  }