@@ -346,9 +346,14 @@ impl<'a> Parser<'a> {
346346 expecting_statement_delimiter = false ;
347347 }
348348
349- if self . peek_token ( ) == Token :: EOF {
350- break ;
349+ match self . peek_token ( ) . token {
350+ Token :: EOF => break ,
351+
352+ // end of statement
353+ Token :: Word ( word) if word. keyword == Keyword :: END => break ,
354+ _ => { }
351355 }
356+
352357 if expecting_statement_delimiter {
353358 return self . expected ( "end of statement" , self . peek_token ( ) ) ;
354359 }
@@ -2324,6 +2329,7 @@ impl<'a> Parser<'a> {
23242329 /// Parse a SQL CREATE statement
23252330 pub fn parse_create ( & mut self ) -> Result < Statement , ParserError > {
23262331 let or_replace = self . parse_keywords ( & [ Keyword :: OR , Keyword :: REPLACE ] ) ;
2332+ let or_alter = self . parse_keywords ( & [ Keyword :: OR , Keyword :: ALTER ] ) ;
23272333 let local = self . parse_one_of_keywords ( & [ Keyword :: LOCAL ] ) . is_some ( ) ;
23282334 let global = self . parse_one_of_keywords ( & [ Keyword :: GLOBAL ] ) . is_some ( ) ;
23292335 let transient = self . parse_one_of_keywords ( & [ Keyword :: TRANSIENT ] ) . is_some ( ) ;
@@ -2369,6 +2375,8 @@ impl<'a> Parser<'a> {
23692375 self . parse_create_sequence ( temporary)
23702376 } else if self . parse_keyword ( Keyword :: TYPE ) {
23712377 self . parse_create_type ( )
2378+ } else if self . parse_keyword ( Keyword :: PROCEDURE ) {
2379+ self . parse_create_procedure ( or_alter)
23722380 } else {
23732381 self . expected ( "an object type after CREATE" , self . peek_token ( ) )
23742382 }
@@ -3503,6 +3511,28 @@ impl<'a> Parser<'a> {
35033511 . build ( ) )
35043512 }
35053513
3514+ pub fn parse_optional_procedure_parameters (
3515+ & mut self ,
3516+ ) -> Result < Option < Vec < ProcedureParam > > , ParserError > {
3517+ let mut params = vec ! [ ] ;
3518+ if !self . consume_token ( & Token :: LParen ) || self . consume_token ( & Token :: RParen ) {
3519+ return Ok ( Some ( params) ) ;
3520+ }
3521+ loop {
3522+ if let Token :: Word ( _) = self . peek_token ( ) . token {
3523+ params. push ( self . parse_procedure_param ( ) ?)
3524+ }
3525+ let comma = self . consume_token ( & Token :: Comma ) ;
3526+ if self . consume_token ( & Token :: RParen ) {
3527+ // allow a trailing comma, even though it's not in standard
3528+ break ;
3529+ } else if !comma {
3530+ return self . expected ( "',' or ')' after parameter definition" , self . peek_token ( ) ) ;
3531+ }
3532+ }
3533+ Ok ( Some ( params) )
3534+ }
3535+
35063536 pub fn parse_columns ( & mut self ) -> Result < ( Vec < ColumnDef > , Vec < TableConstraint > ) , ParserError > {
35073537 let mut columns = vec ! [ ] ;
35083538 let mut constraints = vec ! [ ] ;
@@ -3530,6 +3560,12 @@ impl<'a> Parser<'a> {
35303560 Ok ( ( columns, constraints) )
35313561 }
35323562
3563+ pub fn parse_procedure_param ( & mut self ) -> Result < ProcedureParam , ParserError > {
3564+ let name = self . parse_identifier ( ) ?;
3565+ let data_type = self . parse_data_type ( ) ?;
3566+ Ok ( ProcedureParam { name, data_type } )
3567+ }
3568+
35333569 pub fn parse_column_def ( & mut self ) -> Result < ColumnDef , ParserError > {
35343570 let name = self . parse_identifier ( ) ?;
35353571 let data_type = self . parse_data_type ( ) ?;
@@ -7082,6 +7118,21 @@ impl<'a> Parser<'a> {
70827118 Ok ( NamedWindowDefinition ( ident, window_spec) )
70837119 }
70847120
7121+ pub fn parse_create_procedure ( & mut self , or_alter : bool ) -> Result < Statement , ParserError > {
7122+ let name = self . parse_object_name ( ) ?;
7123+ let params = self . parse_optional_procedure_parameters ( ) ?;
7124+ self . expect_keyword ( Keyword :: AS ) ?;
7125+ self . expect_keyword ( Keyword :: BEGIN ) ?;
7126+ let statements = self . parse_statements ( ) ?;
7127+ self . expect_keyword ( Keyword :: END ) ?;
7128+ Ok ( Statement :: CreateProcedure {
7129+ name,
7130+ or_alter,
7131+ params,
7132+ body : statements,
7133+ } )
7134+ }
7135+
70857136 pub fn parse_window_spec ( & mut self ) -> Result < WindowSpec , ParserError > {
70867137 let partition_by = if self . parse_keywords ( & [ Keyword :: PARTITION , Keyword :: BY ] ) {
70877138 self . parse_comma_separated ( Parser :: parse_expr) ?
0 commit comments