iffyio commented on code in PR #1808: URL: https://github.com/apache/datafusion-sqlparser-rs/pull/1808#discussion_r2050170398
########## src/ast/spans.rs: ########## @@ -2280,6 +2277,12 @@ impl Spanned for TableObject { } } +impl Spanned for BeginEndStatements { + fn span(&self) -> Span { + union_spans([self.begin_token.0.span, self.end_token.0.span].into_iter()) Review Comment: We can do an exhausitve match here, so that the code is revisite if fields get added or changed ```rust let BeginEndStatements { begin, statements, end } = self; union_spans(begin, statements, end) ``` we can probably include statements in the union spans call if only for completeness ########## tests/sqlparser_mssql.rs: ########## @@ -187,6 +188,386 @@ fn parse_mssql_create_procedure() { let _ = ms().verified_stmt("CREATE PROCEDURE [foo] AS BEGIN UPDATE bar SET col = 'test'; SELECT [foo] FROM BAR WHERE [FOO] > 10 END"); } +#[test] +fn parse_create_function() { + let return_expression_function = "CREATE FUNCTION some_scalar_udf(@foo INT, @bar VARCHAR(256)) RETURNS INT AS BEGIN RETURN 1; END"; + assert_eq!( + ms().verified_stmt(return_expression_function), + sqlparser::ast::Statement::CreateFunction(CreateFunction { + or_alter: false, + or_replace: false, + temporary: false, + if_not_exists: false, + name: ObjectName::from(vec![Ident { + value: "some_scalar_udf".into(), + quote_style: None, + span: Span::empty(), + }]), + args: Some(vec![ + OperateFunctionArg { + mode: None, + name: Some(Ident { + value: "@foo".into(), + quote_style: None, + span: Span::empty(), + }), + data_type: DataType::Int(None), + default_expr: None, + }, + OperateFunctionArg { + mode: None, + name: Some(Ident { + value: "@bar".into(), + quote_style: None, + span: Span::empty(), + }), + data_type: DataType::Varchar(Some(CharacterLength::IntegerLength { + length: 256, + unit: None + })), + default_expr: None, + }, + ]), + return_type: Some(DataType::Int(None)), + function_body: Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements { + begin_token: AttachedToken(TokenWithSpan::wrap(sqlparser::tokenizer::Token::Word( + sqlparser::tokenizer::Word { + value: "BEGIN".to_string(), + quote_style: None, + keyword: Keyword::BEGIN + } + ))), + statements: vec![Statement::Return(ReturnStatement { + value: Some(ReturnStatementValue::Expr(Expr::Value( + (number("1")).with_empty_span() + ))), + }),], + end_token: AttachedToken(TokenWithSpan::wrap(sqlparser::tokenizer::Token::Word( + sqlparser::tokenizer::Word { + value: "END".to_string(), + quote_style: None, + keyword: Keyword::END + } + ))), + })), + behavior: None, + called_on_null: None, + parallel: None, + using: None, + language: None, + determinism_specifier: None, + options: None, + remote_connection: None, + }), + ); + + let multi_statement_function = "\ Review Comment: Yeah that's correct! ########## tests/sqlparser_common.rs: ########## @@ -15015,3 +15015,8 @@ fn parse_set_time_zone_alias() { _ => unreachable!(), } } + +#[test] +fn parse_return() { + all_dialects().verified_stmt("RETURN"); Review Comment: Can we have this check assert the AST? Also we can add another test case that includes a return statement having an expression ########## src/parser/mod.rs: ########## @@ -5135,6 +5146,63 @@ impl<'a> Parser<'a> { })) } + /// Parse `CREATE FUNCTION` for [SQL Server] + /// + /// [SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql + fn parse_mssql_create_function( + &mut self, + or_alter: bool, + or_replace: bool, + temporary: bool, + ) -> Result<Statement, ParserError> { + let name = self.parse_object_name(false)?; + + let parse_function_param = + |parser: &mut Parser| -> Result<OperateFunctionArg, ParserError> { + let name = parser.parse_identifier()?; + let data_type = parser.parse_data_type()?; + Ok(OperateFunctionArg { + mode: None, + name: Some(name), + data_type, + default_expr: None, + }) + }; + self.expect_token(&Token::LParen)?; + let args = self.parse_comma_separated0(parse_function_param, Token::RParen)?; + self.expect_token(&Token::RParen)?; + + let return_type = if self.parse_keyword(Keyword::RETURNS) { + Some(self.parse_data_type()?) + } else { + None + }; + + self.expect_keyword_is(Keyword::AS)?; + self.expect_keyword_is(Keyword::BEGIN)?; + let function_body = Some(CreateFunctionBody::MultiStatement(self.parse_statements()?)); Review Comment: does something like in [this suggestion](https://github.com/apache/datafusion-sqlparser-rs/pull/1808#discussion_r2040592844) work just as well? its currently unclear to me why the semicolon handling is a special case of an `IfCondition` statement -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: github-unsubscr...@datafusion.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: github-unsubscr...@datafusion.apache.org For additional commands, e-mail: github-h...@datafusion.apache.org