Skip to content

Commit 54b2829

Browse files
committed
Add support for inline table valued functions for SQL Server
1 parent 2182f7e commit 54b2829

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
@@ -2313,6 +2313,9 @@ impl fmt::Display for CreateFunction {
23132313
if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
23142314
write!(f, " RETURN {function_body}")?;
23152315
}
2316+
if let Some(CreateFunctionBody::AsReturn(function_body)) = &self.function_body {
2317+
write!(f, " AS RETURN {function_body}")?;
2318+
}
23162319
if let Some(using) = &self.using {
23172320
write!(f, " {using}")?;
23182321
}

src/ast/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8660,6 +8660,18 @@ pub enum CreateFunctionBody {
86608660
///
86618661
/// [PostgreSQL]: https://www.postgresql.org/docs/current/sql-createfunction.html
86628662
Return(Expr),
8663+
8664+
/// Function body expression using the 'AS RETURN' keywords
8665+
///
8666+
/// Example:
8667+
/// ```sql
8668+
/// CREATE FUNCTION myfunc(a INT, b INT)
8669+
/// RETURNS TABLE
8670+
/// AS RETURN (SELECT a + b AS sum);
8671+
/// ```
8672+
///
8673+
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql
8674+
AsReturn(Expr),
86638675
}
86648676

86658677
#[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
@@ -5207,15 +5207,26 @@ impl<'a> Parser<'a> {
52075207

52085208
self.expect_keyword_is(Keyword::AS)?;
52095209

5210-
let begin_token = self.expect_keyword(Keyword::BEGIN)?;
5211-
let statements = self.parse_statement_list(&[Keyword::END])?;
5212-
let end_token = self.expect_keyword(Keyword::END)?;
5210+
let function_body = if self.peek_keyword(Keyword::BEGIN) {
5211+
let begin_token = self.expect_keyword(Keyword::BEGIN)?;
5212+
let statements = self.parse_statement_list(&[Keyword::END])?;
5213+
let end_token = self.expect_keyword(Keyword::END)?;
52135214

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

52205231
Ok(Statement::CreateFunction(CreateFunction {
52215232
or_alter,
@@ -9766,8 +9777,12 @@ impl<'a> Parser<'a> {
97669777
Ok(DataType::AnyType)
97679778
}
97689779
Keyword::TABLE => {
9769-
let columns = self.parse_returns_table_columns()?;
9770-
Ok(DataType::Table(columns))
9780+
if self.peek_keyword(Keyword::AS) {
9781+
Ok(DataType::Table(Vec::<ColumnDef>::new()))
9782+
} else {
9783+
let columns = self.parse_returns_table_columns()?;
9784+
Ok(DataType::Table(columns))
9785+
}
97719786
}
97729787
Keyword::SIGNED => {
97739788
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)