OrderByRelBuilder addSortByKeys(ASTNode obAST) throws SemanticException {
      if (obAST == null) {
        return this;
      }

      // 2. Walk through OB exprs and extract field collations and additional
      // virtual columns needed
      List<Node> obASTExprLst = obAST.getChildren();

      for (int i = 0; i < obASTExprLst.size(); i++) {
        // 2.1 Convert AST Expr to ExprNode
        ASTNode orderByNode = (ASTNode) obASTExprLst.get(i);
        ASTNode nullObASTExpr = (ASTNode) orderByNode.getChild(0);
        ASTNode ref = (ASTNode) nullObASTExpr.getChild(0);

        int fieldIndex = genSortByKey(ref);
        if (fieldIndex < 0) {
          continue;
        }

        // 2.4 Determine the Direction of order by
        RelFieldCollation.Direction order = RelFieldCollation.Direction.DESCENDING;
        if (orderByNode.getType() == HiveParser.TOK_TABSORTCOLNAMEASC) {
          order = RelFieldCollation.Direction.ASCENDING;
        }
        RelFieldCollation.NullDirection nullOrder;
        if (nullObASTExpr.getType() == HiveParser.TOK_NULLS_FIRST) {
          nullOrder = RelFieldCollation.NullDirection.FIRST;
        } else if (nullObASTExpr.getType() == HiveParser.TOK_NULLS_LAST) {
          nullOrder = RelFieldCollation.NullDirection.LAST;
        } else {
          throw new SemanticException("Unexpected null ordering option: "
                  + nullObASTExpr.getType());
        }

        // 2.5 Add to field collations
        fieldCollations.add(new RelFieldCollation(fieldIndex, order, nullOrder));
      }

      return this;
    }
This method can be called at startup time to pre-register all the
additional Hive classes (compared to Calcite core classes) that may
be visited during the planning phase in the metadata providers
and the field trimmer.
ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java