Skip to content

Commit 3475d4b

Browse files
committed
Add support for inline table valued functions for SQL Server
1 parent ae587dc commit 3475d4b

File tree

5 files changed

+55
-11
lines changed

5 files changed

+55
-11
lines changed

src/ast/data_type.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub enum DataType {
4848
/// Table type in [PostgreSQL], e.g. CREATE FUNCTION RETURNS TABLE(...).
4949
///
5050
/// [PostgreSQL]: https://www.postgresql.org/docs/15/sql-createfunction.html
51+
/// [MsSQL]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#c-create-a-multi-statement-table-valued-function
5152
Table(Vec<ColumnDef>),
5253
/// Fixed-length character type, e.g. CHARACTER(10).
5354
Character(Option<CharacterLength>),
@@ -716,7 +717,12 @@ impl fmt::Display for DataType {
716717
DataType::Unspecified => Ok(()),
717718
DataType::Trigger => write!(f, "TRIGGER"),
718719
DataType::AnyType => write!(f, "ANY TYPE"),
719-
DataType::Table(fields) => write!(f, "TABLE({})", display_comma_separated(fields)),
720+
DataType::Table(fields) => {
721+
if fields.is_empty() {
722+
return write!(f, "TABLE");
723+
}
724+
write!(f, "TABLE({})", display_comma_separated(fields))
725+
}
720726
DataType::GeometricType(kind) => write!(f, "{}", kind),
721727
}
722728
}

src/ast/ddl.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,6 +2346,9 @@ impl fmt::Display for CreateFunction {
23462346
if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
23472347
write!(f, " RETURN {function_body}")?;
23482348
}
2349+
if let Some(CreateFunctionBody::AsReturn(function_body)) = &self.function_body {
2350+
write!(f, " AS RETURN {function_body}")?;
2351+
}
23492352
if let Some(using) = &self.using {
23502353
write!(f, " {using}")?;
23512354
}

src/ast/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8778,6 +8778,18 @@ pub enum CreateFunctionBody {
87788778
///
87798779
/// [PostgreSQL]: https://www.postgresql.org/docs/current/sql-createfunction.html
87808780
Return(Expr),
8781+
8782+
/// Function body expression using the 'AS RETURN' keywords
8783+
///
8784+
/// Example:
8785+
/// ```sql
8786+
/// CREATE FUNCTION myfunc(a INT, b INT)
8787+
/// RETURNS TABLE
8788+
/// AS RETURN (SELECT a + b AS sum);
8789+
/// ```
8790+
///
8791+
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql
8792+
AsReturn(Expr),
87818793
}
87828794

87838795
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]

src/parser/mod.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5211,15 +5211,26 @@ impl<'a> Parser<'a> {
52115211

52125212
self.expect_keyword_is(Keyword::AS)?;
52135213

5214-
let begin_token = self.expect_keyword(Keyword::BEGIN)?;
5215-
let statements = self.parse_statement_list(&[Keyword::END])?;
5216-
let end_token = self.expect_keyword(Keyword::END)?;
5214+
let function_body = if self.peek_keyword(Keyword::BEGIN) {
5215+
let begin_token = self.expect_keyword(Keyword::BEGIN)?;
5216+
let statements = self.parse_statement_list(&[Keyword::END])?;
5217+
let end_token = self.expect_keyword(Keyword::END)?;
52175218

5218-
let function_body = Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements {
5219-
begin_token: AttachedToken(begin_token),
5220-
statements,
5221-
end_token: AttachedToken(end_token),
5222-
}));
5219+
Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements {
5220+
begin_token: AttachedToken(begin_token),
5221+
statements,
5222+
end_token: AttachedToken(end_token),
5223+
}))
5224+
} else if self.peek_keyword(Keyword::RETURN) {
5225+
self.expect_keyword(Keyword::RETURN)?;
5226+
let expr = self.parse_expr()?;
5227+
if !matches!(expr, Expr::Subquery(_)) {
5228+
parser_err!("Expected a subquery after RETURN", expr.span().start)?;
5229+
}
5230+
Some(CreateFunctionBody::AsReturn(expr))
5231+
} else {
5232+
parser_err!("Unparsable function body", self.peek_token().span.start)?
5233+
};
52235234

52245235
Ok(Statement::CreateFunction(CreateFunction {
52255236
or_alter,
@@ -9787,8 +9798,12 @@ impl<'a> Parser<'a> {
97879798
Ok(DataType::AnyType)
97889799
}
97899800
Keyword::TABLE => {
9790-
let columns = self.parse_returns_table_columns()?;
9791-
Ok(DataType::Table(columns))
9801+
if self.peek_keyword(Keyword::AS) {
9802+
Ok(DataType::Table(Vec::<ColumnDef>::new()))
9803+
} else {
9804+
let columns = self.parse_returns_table_columns()?;
9805+
Ok(DataType::Table(columns))
9806+
}
97929807
}
97939808
Keyword::SIGNED => {
97949809
if self.parse_keyword(Keyword::INTEGER) {

tests/sqlparser_mssql.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,14 @@ fn parse_create_function() {
288288
END\
289289
";
290290
let _ = ms().verified_stmt(create_function_with_return_expression);
291+
292+
let create_inline_table_value_function = "\
293+
CREATE FUNCTION some_inline_tvf(@foo INT, @bar VARCHAR(256)) \
294+
RETURNS TABLE \
295+
AS \
296+
RETURN (SELECT 1 AS col_1)\
297+
";
298+
let _ = ms().verified_stmt(create_inline_table_value_function);
291299
}
292300

293301
#[test]

0 commit comments

Comments
 (0)