docs: protected AstNode parseCreateProcedureStatement( DdlTokenStream tokens,
                                                       AstNode parentNode ) throws ParsingException {
          assert tokens != null;
          assert parentNode != null;
  
          markStartOfStatement(tokens);
          /* ----------------------------------------------------------------------
              CREATE [ OR REPLACE ] PROCEDURE [ schema. ] procedure_name
                  [ ( parameter_declaration [, parameter_declaration ] ) ]
                  [ AUTHID { CURRENT_USER | DEFINER  ]
                  { IS | AS }
                  { [ declare_section ] body | call_spec | EXTERNAL} ;
              
               call_spec = LANGUAGE { Java_declaration | C_declaration }
              
               Java_declaration = JAVA NAME string
              
               C_declaration = 
                  C [ NAME name ]
                      LIBRARY lib_name
                      [ AGENT IN (argument[, argument ]...) ]
                      [ WITH CONTEXT ]
                      [ PARAMETERS (parameter[, parameter ]...) ]
                      
              parameter_declaration = parameter_name [ IN | { { OUT | { IN OUT }} [ NOCOPY ] } ] datatype [ { := | DEFAULT } expression ]
          ---------------------------------------------------------------------- */
  
          boolean isReplace = tokens.canConsume(STMT_CREATE_OR_REPLACE_PROCEDURE);
  
          tokens.canConsume(STMT_CREATE_PROCEDURE);
  
          String name = parseName(tokens);
  
          AstNode node = nodeFactory().node(name, parentNode, TYPE_CREATE_PROCEDURE_STATEMENT);
  
          if (isReplace) {
              // TODO: SET isReplace = TRUE to node (possibly a cnd mixin of "replaceable"
          }
  
          boolean ok = parseParameters(tokens, node);
  
          if (ok) {
              if (tokens.canConsume("AUTHID")) {
                  if (tokens.canConsume("CURRENT_USER")) {
                      node.setProperty(AUTHID_VALUE, "AUTHID CURRENT_USER");
                  } else {
                      tokens.consume("DEFINER");
                      node.setProperty(AUTHID_VALUE, "DEFINER");
                  }
              }
          }
  
          parseUntilFwdSlash(tokens, false);
  
          tokens.canConsume("/");
  
          markEndOfStatement(tokens, node);
  
          return node;
      }