diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 9a01e510b..c32f3e6e4 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -5521,16 +5521,19 @@ impl<'a> Parser<'a> { // peek the next token, which if it is another type keyword, then the // first token is a name and not a type in itself. let data_type_idx = self.get_current_index(); - if let Some(next_data_type) = self.maybe_parse(|parser| parser.parse_data_type())? { - let token = self.token_at(data_type_idx); + // DEFAULT will be parsed as `DataType::Custom`, which is undesirable in this context + if !self.peek_keyword(Keyword::DEFAULT) { + if let Some(next_data_type) = self.maybe_parse(|parser| parser.parse_data_type())? { + let token = self.token_at(data_type_idx); - // We ensure that the token is a `Word` token, and not other special tokens. - if !matches!(token.token, Token::Word(_)) { - return self.expected("a name or type", token.clone()); - } + // We ensure that the token is a `Word` token, and not other special tokens. + if !matches!(token.token, Token::Word(_)) { + return self.expected("a name or type", token.clone()); + } - name = Some(Ident::new(token.to_string())); - data_type = next_data_type; + name = Some(Ident::new(token.to_string())); + data_type = next_data_type; + } } let default_expr = if self.parse_keyword(Keyword::DEFAULT) || self.consume_token(&Token::Eq) diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 9ba0fb978..ba9d43cc7 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -4476,6 +4476,46 @@ fn parse_create_function_detailed() { pg_and_generic().verified_stmt(r#"CREATE OR REPLACE FUNCTION no_arg() RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN DELETE FROM my_table; END; $$"#); pg_and_generic().verified_stmt(r#"CREATE OR REPLACE FUNCTION return_table(i INTEGER) RETURNS TABLE(id UUID, is_active BOOLEAN) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT NULL::UUID, NULL::BOOLEAN; END; $$"#); } + +#[test] +fn parse_create_function_unnamed_default_syntax() { + let sql = + "CREATE FUNCTION add(INTEGER, INTEGER DEFAULT 1) RETURNS INTEGER AS 'select $1 + $2;'"; + let canonical = + "CREATE FUNCTION add(INTEGER, INTEGER = 1) RETURNS INTEGER AS 'select $1 + $2;'"; + assert_eq!( + pg_and_generic().one_statement_parses_to(sql, canonical), + Statement::CreateFunction(CreateFunction { + or_alter: false, + or_replace: false, + temporary: false, + name: ObjectName::from(vec![Ident::new("add")]), + args: Some(vec![ + OperateFunctionArg::unnamed(DataType::Integer(None)), + OperateFunctionArg { + mode: None, + name: None, + data_type: DataType::Integer(None), + default_expr: Some(Expr::Value(number("1").with_empty_span())), + }, + ]), + return_type: Some(DataType::Integer(None)), + language: None, + behavior: None, + called_on_null: None, + parallel: None, + function_body: Some(CreateFunctionBody::AsBeforeOptions(Expr::Value( + (Value::SingleQuotedString("select $1 + $2;".into())).with_empty_span() + ))), + if_not_exists: false, + using: None, + determinism_specifier: None, + options: None, + remote_connection: None, + }) + ); +} + #[test] fn parse_incorrect_create_function_parallel() { let sql = "CREATE FUNCTION add(INTEGER, INTEGER) RETURNS INTEGER LANGUAGE SQL PARALLEL BLAH AS 'select $1 + $2;'";