public static List<FieldSchema> getColumns(
      ASTNode ast, boolean lowerCase, TokenRewriteStream tokenRewriteStream,
      List<SQLPrimaryKey> primaryKeys, List<SQLForeignKey> foreignKeys,
      List<SQLUniqueConstraint> uniqueConstraints, List<SQLNotNullConstraint> notNullConstraints,
      List<SQLDefaultConstraint> defaultConstraints, List<SQLCheckConstraint> checkConstraints,
      Configuration conf) throws SemanticException {
    List<FieldSchema> colList = new ArrayList<>();
    Tree parent = ast.getParent();

    for (int i = 0; i < ast.getChildCount(); i++) {
      FieldSchema col = new FieldSchema();
      ASTNode child = (ASTNode) ast.getChild(i);
      switch (child.getToken().getType()) {
      case HiveParser.TOK_UNIQUE: {
        final TableName tName =
            getQualifiedTableName((ASTNode) parent.getChild(0), MetaStoreUtils.getDefaultCatalog(conf));
        // TODO CAT - for now always use the default catalog.  Eventually will want to see if
        // the user specified a catalog
        ConstraintsUtils.processUniqueConstraints(tName, child, uniqueConstraints);
      }
      break;
      case HiveParser.TOK_PRIMARY_KEY: {
        if (!primaryKeys.isEmpty()) {
          throw new SemanticException(ErrorMsg.INVALID_CONSTRAINT
              .getMsg("Cannot exist more than one primary key definition for the same table"));
        }
        final TableName tName = getQualifiedTableName((ASTNode) parent.getChild(0));
        ConstraintsUtils.processPrimaryKeys(tName, child, primaryKeys);
      }
      break;
      case HiveParser.TOK_FOREIGN_KEY: {
        final TableName tName = getQualifiedTableName((ASTNode) parent.getChild(0));
        ConstraintsUtils.processForeignKeys(tName, child, foreignKeys);
      }
      break;
      case HiveParser.TOK_CHECK_CONSTRAINT: {
        final TableName tName =
            getQualifiedTableName((ASTNode) parent.getChild(0), MetaStoreUtils.getDefaultCatalog(conf));
        // TODO CAT - for now always use the default catalog.  Eventually will want to see if
        // the user specified a catalog
        ConstraintsUtils.processCheckConstraints(tName, child, null, checkConstraints, null, tokenRewriteStream);
      }
      break;
      default:
        Tree grandChild = child.getChild(0);
        if (grandChild != null) {
          String name = grandChild.getText();
          if (lowerCase) {
            name = name.toLowerCase();
          }
          checkColumnName(name);
          // child 0 is the name of the column
          col.setName(unescapeIdentifier(name));
          // child 1 is the type of the column
          ASTNode typeChild = (ASTNode) (child.getChild(1));
          col.setType(getTypeStringFromAST(typeChild));

          // child 2 is the optional comment of the column
          // child 3 is the optional constraint
          ASTNode constraintChild = null;
          if (child.getChildCount() == 4) {
            col.setComment(unescapeSQLString(child.getChild(2).getText()));
            constraintChild = (ASTNode) child.getChild(3);
          } else if (child.getChildCount() == 3
              && ((ASTNode) child.getChild(2)).getToken().getType() == HiveParser.StringLiteral) {
            col.setComment(unescapeSQLString(child.getChild(2).getText()));
          } else if (child.getChildCount() == 3) {
            constraintChild = (ASTNode) child.getChild(2);
          }
          if (constraintChild != null) {
            final TableName tName =
                getQualifiedTableName((ASTNode) parent.getChild(0), MetaStoreUtils.getDefaultCatalog(conf));
            // TODO CAT - for now always use the default catalog.  Eventually will want to see if
            // the user specified a catalog
            // Process column constraint
            switch (constraintChild.getToken().getType()) {
            case HiveParser.TOK_CHECK_CONSTRAINT:
              ConstraintsUtils.processCheckConstraints(tName, constraintChild, ImmutableList.of(col.getName()),
                  checkConstraints, typeChild, tokenRewriteStream);
              break;
            case HiveParser.TOK_DEFAULT_VALUE:
              ConstraintsUtils.processDefaultConstraints(tName, constraintChild, ImmutableList.of(col.getName()),
                  defaultConstraints, typeChild, tokenRewriteStream);
              break;
            case HiveParser.TOK_NOT_NULL:
              ConstraintsUtils.processNotNullConstraints(tName, constraintChild, ImmutableList.of(col.getName()),
                  notNullConstraints);
              break;
            case HiveParser.TOK_UNIQUE:
              ConstraintsUtils.processUniqueConstraints(tName, constraintChild, ImmutableList.of(col.getName()),
                  uniqueConstraints);
              break;
            case HiveParser.TOK_PRIMARY_KEY:
              if (!primaryKeys.isEmpty()) {
                throw new SemanticException(ErrorMsg.INVALID_CONSTRAINT
                    .getMsg("Cannot exist more than one primary key definition for the same table"));
              }
              ConstraintsUtils.processPrimaryKeys(tName, constraintChild, ImmutableList.of(col.getName()), primaryKeys);
              break;
            case HiveParser.TOK_FOREIGN_KEY:
              ConstraintsUtils.processForeignKeys(tName, constraintChild, foreignKeys);
              break;
            default:
              throw new SemanticException(ErrorMsg.NOT_RECOGNIZED_CONSTRAINT.getMsg(
                  constraintChild.getToken().getText()));
            }
          }
        }
        colList.add(col);
        break;
      }
    }
    return colList;
  }
Get the list of FieldSchema out of the ASTNode.
Additionally, populate the primaryKeys and foreignKeys if any.
ql/src/java/org/apache/hadoop/hive/ql/parse/BaseSemanticAnalyzer.java