iffyio commented on code in PR #1839: URL: https://github.com/apache/datafusion-sqlparser-rs/pull/1839#discussion_r2096898613
########## src/parser/mod.rs: ########## @@ -5204,19 +5204,79 @@ impl<'a> Parser<'a> { let (name, args) = self.parse_create_function_name_and_params()?; self.expect_keyword(Keyword::RETURNS)?; - let return_type = Some(self.parse_data_type()?); - self.expect_keyword_is(Keyword::AS)?; + let return_table = self.maybe_parse(|p| { + let return_table_name = p.parse_identifier()?; + + if !p.peek_keyword(Keyword::TABLE) { + parser_err!( + "Expected TABLE keyword after return type", + p.peek_token().span.start + )? + } + + let table_column_defs = match p.parse_data_type()? { + DataType::Table(maybe_table_column_defs) => match maybe_table_column_defs { + Some(table_column_defs) => { + if table_column_defs.is_empty() { + parser_err!( + "Expected table column definitions after TABLE keyword", + p.peek_token().span.start + )? + } + + table_column_defs + } + None => parser_err!( + "Expected table column definitions after TABLE keyword", + p.peek_token().span.start + )?, + }, + _ => parser_err!( + "Expected table data type after TABLE keyword", + p.peek_token().span.start + )?, + }; + + Ok(DataType::NamedTable { + name: ObjectName(vec![ObjectNamePart::Identifier(return_table_name)]), + columns: table_column_defs, + }) + })?; + + let return_type = if return_table.is_some() { + return_table + } else { + Some(self.parse_data_type()?) + }; - let begin_token = self.expect_keyword(Keyword::BEGIN)?; - let statements = self.parse_statement_list(&[Keyword::END])?; - let end_token = self.expect_keyword(Keyword::END)?; + let _ = self.parse_keyword(Keyword::AS); - let function_body = Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements { - begin_token: AttachedToken(begin_token), - statements, - end_token: AttachedToken(end_token), - })); + let function_body = if self.peek_keyword(Keyword::BEGIN) { + let begin_token = self.expect_keyword(Keyword::BEGIN)?; + let statements = self.parse_statement_list(&[Keyword::END])?; + let end_token = self.expect_keyword(Keyword::END)?; + + Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements { + begin_token: AttachedToken(begin_token), + statements, + end_token: AttachedToken(end_token), + })) + } else if self.parse_keyword(Keyword::RETURN) { + if self.peek_token() == Token::LParen { + Some(CreateFunctionBody::AsReturnExpr(self.parse_expr()?)) + } else if self.peek_keyword(Keyword::SELECT) { + let select = self.parse_select()?; + Some(CreateFunctionBody::AsReturnSelect(select)) + } else { + parser_err!( + "Expected a subquery (or bare SELECT statement) after RETURN", + self.peek_token().span.start + )? + } Review Comment: can we add a test for this behavior? (e.g. one that passes a regular expression and the verifies that the parser rejects it) ########## src/parser/mod.rs: ########## @@ -5204,19 +5204,79 @@ impl<'a> Parser<'a> { let (name, args) = self.parse_create_function_name_and_params()?; self.expect_keyword(Keyword::RETURNS)?; - let return_type = Some(self.parse_data_type()?); - self.expect_keyword_is(Keyword::AS)?; + let return_table = self.maybe_parse(|p| { + let return_table_name = p.parse_identifier()?; + + if !p.peek_keyword(Keyword::TABLE) { + parser_err!( + "Expected TABLE keyword after return type", + p.peek_token().span.start + )? + } + + let table_column_defs = match p.parse_data_type()? { + DataType::Table(maybe_table_column_defs) => match maybe_table_column_defs { + Some(table_column_defs) => { + if table_column_defs.is_empty() { + parser_err!( + "Expected table column definitions after TABLE keyword", + p.peek_token().span.start + )? + } + + table_column_defs + } + None => parser_err!( + "Expected table column definitions after TABLE keyword", + p.peek_token().span.start + )?, + }, + _ => parser_err!( + "Expected table data type after TABLE keyword", + p.peek_token().span.start + )?, + }; Review Comment: ```suggestion DataType::Table(Some(table_column_defs)) !if table_column_defs.is_empty() => table_column_defs, _ => parser_err!( "Expected table data type after TABLE keyword", p.peek_token().span.start )?, }; ``` looks like this condition can be simplified? Also could we add a negative test to assert the behavior on invalid data_types, noticed it seems to be lacking coverage in the PR tests ########## src/parser/mod.rs: ########## @@ -5204,19 +5204,79 @@ impl<'a> Parser<'a> { let (name, args) = self.parse_create_function_name_and_params()?; self.expect_keyword(Keyword::RETURNS)?; - let return_type = Some(self.parse_data_type()?); - self.expect_keyword_is(Keyword::AS)?; + let return_table = self.maybe_parse(|p| { + let return_table_name = p.parse_identifier()?; + + if !p.peek_keyword(Keyword::TABLE) { + parser_err!( + "Expected TABLE keyword after return type", + p.peek_token().span.start + )? + } Review Comment: ```suggestion p.expect_keyword(Keyword::TABLE)?; ``` -- 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