Skip to content

Commit 4065072

Browse files
committed
fix: parse error on unnamed arg with default syntax
1 parent 308a723 commit 4065072

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

src/parser/mod.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5521,16 +5521,19 @@ impl<'a> Parser<'a> {
55215521
// peek the next token, which if it is another type keyword, then the
55225522
// first token is a name and not a type in itself.
55235523
let data_type_idx = self.get_current_index();
5524-
if let Some(next_data_type) = self.maybe_parse(|parser| parser.parse_data_type())? {
5525-
let token = self.token_at(data_type_idx);
5524+
// DEFAULT will be parsed as `DataType::Custom`, which is undesirable in this context
5525+
if !self.peek_keyword(Keyword::DEFAULT) {
5526+
if let Some(next_data_type) = self.maybe_parse(|parser| parser.parse_data_type())? {
5527+
let token = self.token_at(data_type_idx);
55265528

5527-
// We ensure that the token is a `Word` token, and not other special tokens.
5528-
if !matches!(token.token, Token::Word(_)) {
5529-
return self.expected("a name or type", token.clone());
5530-
}
5529+
// We ensure that the token is a `Word` token, and not other special tokens.
5530+
if !matches!(token.token, Token::Word(_)) {
5531+
return self.expected("a name or type", token.clone());
5532+
}
55315533

5532-
name = Some(Ident::new(token.to_string()));
5533-
data_type = next_data_type;
5534+
name = Some(Ident::new(token.to_string()));
5535+
data_type = next_data_type;
5536+
}
55345537
}
55355538

55365539
let default_expr = if self.parse_keyword(Keyword::DEFAULT) || self.consume_token(&Token::Eq)

tests/sqlparser_postgres.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4476,6 +4476,46 @@ fn parse_create_function_detailed() {
44764476
pg_and_generic().verified_stmt(r#"CREATE OR REPLACE FUNCTION no_arg() RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN DELETE FROM my_table; END; $$"#);
44774477
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; $$"#);
44784478
}
4479+
4480+
#[test]
4481+
fn parse_create_function_unnamed_default_syntax() {
4482+
let sql =
4483+
"CREATE FUNCTION add(INTEGER, INTEGER DEFAULT 1) RETURNS INTEGER AS 'select $1 + $2;'";
4484+
let canonical =
4485+
"CREATE FUNCTION add(INTEGER, INTEGER = 1) RETURNS INTEGER AS 'select $1 + $2;'";
4486+
assert_eq!(
4487+
pg_and_generic().one_statement_parses_to(sql, canonical),
4488+
Statement::CreateFunction(CreateFunction {
4489+
or_alter: false,
4490+
or_replace: false,
4491+
temporary: false,
4492+
name: ObjectName::from(vec![Ident::new("add")]),
4493+
args: Some(vec![
4494+
OperateFunctionArg::unnamed(DataType::Integer(None)),
4495+
OperateFunctionArg {
4496+
mode: None,
4497+
name: None,
4498+
data_type: DataType::Integer(None),
4499+
default_expr: Some(Expr::Value(number("1").with_empty_span())),
4500+
},
4501+
]),
4502+
return_type: Some(DataType::Integer(None)),
4503+
language: None,
4504+
behavior: None,
4505+
called_on_null: None,
4506+
parallel: None,
4507+
function_body: Some(CreateFunctionBody::AsBeforeOptions(Expr::Value(
4508+
(Value::SingleQuotedString("select $1 + $2;".into())).with_empty_span()
4509+
))),
4510+
if_not_exists: false,
4511+
using: None,
4512+
determinism_specifier: None,
4513+
options: None,
4514+
remote_connection: None,
4515+
})
4516+
);
4517+
}
4518+
44794519
#[test]
44804520
fn parse_incorrect_create_function_parallel() {
44814521
let sql = "CREATE FUNCTION add(INTEGER, INTEGER) RETURNS INTEGER LANGUAGE SQL PARALLEL BLAH AS 'select $1 + $2;'";

0 commit comments

Comments
 (0)