agent_patch
runs/2026-02-28__18-27-22__gpt-5-4/flux-pr-1839/flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/agent-logs/agent.patch
13926 bytes
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/ddl.rs b/app/src/ast/ddl.rs
index a8a1fdb..0ee8e67 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/ddl.rs
+++ b/app/src/ast/ddl.rs
@@ -2258,6 +2258,8 @@ pub struct CreateFunction {
pub if_not_exists: bool,
pub name: ObjectName,
pub args: Option<Vec<OperateFunctionArg>>,
+ /// Named return table variable for MSSQL multi-statement table-valued functions.
+ pub return_table_name: Option<Ident>,
pub return_type: Option<DataType>,
/// The expression that defines the function.
///
@@ -2330,7 +2332,11 @@ impl fmt::Display for CreateFunction {
write!(f, "({})", display_comma_separated(args))?;
}
if let Some(return_type) = &self.return_type {
- write!(f, " RETURNS {return_type}")?;
+ write!(f, " RETURNS")?;
+ if let Some(return_table_name) = &self.return_table_name {
+ write!(f, " {return_table_name}")?;
+ }
+ write!(f, " {return_type}")?;
}
if let Some(determinism_specifier) = &self.determinism_specifier {
write!(f, " {determinism_specifier}")?;
@@ -2372,6 +2378,9 @@ impl fmt::Display for CreateFunction {
if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
write!(f, " AS {bes}")?;
}
+ if let Some(CreateFunctionBody::AsReturnQuery(query)) = &self.function_body {
+ write!(f, " AS RETURN {query}")?;
+ }
Ok(())
}
}
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/mod.rs b/app/src/ast/mod.rs
index e18251e..c982c4f 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/mod.rs
+++ b/app/src/ast/mod.rs
@@ -8769,6 +8769,16 @@ pub enum CreateFunctionBody {
///
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql
AsBeginEnd(BeginEndStatements),
+ /// MSSQL inline table-valued function body using `RETURN <query>`.
+ ///
+ /// Example:
+ /// ```sql
+ /// CREATE FUNCTION my_inline_tvf()
+ /// RETURNS TABLE
+ /// AS
+ /// RETURN SELECT 1 AS id
+ /// ```
+ AsReturnQuery(Box<Query>),
/// Function body expression using the 'RETURN' keyword.
///
/// Example:
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs b/app/src/parser/mod.rs
index 47b321d..923802e 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -5069,6 +5069,7 @@ impl<'a> Parser<'a> {
temporary,
name,
args: Some(args),
+ return_table_name: None,
return_type,
behavior: body.behavior,
called_on_null: body.called_on_null,
@@ -5106,6 +5107,7 @@ impl<'a> Parser<'a> {
using,
if_not_exists: false,
args: None,
+ return_table_name: None,
return_type: None,
behavior: None,
called_on_null: None,
@@ -5179,6 +5181,7 @@ impl<'a> Parser<'a> {
if_not_exists,
name,
args: Some(args),
+ return_table_name: None,
return_type,
function_body,
language,
@@ -5204,19 +5207,31 @@ impl<'a> Parser<'a> {
let (name, args) = self.parse_create_function_name_and_params()?;
self.expect_keyword(Keyword::RETURNS)?;
+ let return_table_name = match &self.peek_token().token {
+ Token::AtSign => Some(self.parse_identifier()?),
+ Token::Word(word) if word.value.starts_with('@') => Some(self.parse_identifier()?),
+ _ => None,
+ };
let return_type = Some(self.parse_data_type()?);
- self.expect_keyword_is(Keyword::AS)?;
+ let _ = self.parse_keyword(Keyword::AS);
- 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 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)?;
- let function_body = Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements {
- begin_token: AttachedToken(begin_token),
- statements,
- end_token: AttachedToken(end_token),
- }));
+ Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements {
+ begin_token: AttachedToken(begin_token),
+ statements,
+ end_token: AttachedToken(end_token),
+ }))
+ } else {
+ self.expect_keyword_is(Keyword::RETURN)?;
+ Some(CreateFunctionBody::AsReturnQuery(
+ self.parse_mssql_inline_function_return_query()?.into(),
+ ))
+ };
Ok(Statement::CreateFunction(CreateFunction {
or_alter,
@@ -5225,6 +5240,7 @@ impl<'a> Parser<'a> {
if_not_exists: false,
name,
args: Some(args),
+ return_table_name,
return_type,
function_body,
language: None,
@@ -5238,6 +5254,16 @@ impl<'a> Parser<'a> {
}))
}
+ fn parse_mssql_inline_function_return_query(&mut self) -> Result<Query, ParserError> {
+ if self.consume_token(&Token::LParen) {
+ let query = self.parse_query()?;
+ self.expect_token(&Token::RParen)?;
+ Ok(query)
+ } else {
+ self.parse_query()
+ }
+ }
+
fn parse_create_function_name_and_params(
&mut self,
) -> Result<(ObjectName, Vec<OperateFunctionArg>), ParserError> {
@@ -9841,10 +9867,28 @@ impl<'a> Parser<'a> {
fn parse_returns_table_column(&mut self) -> Result<ColumnDef, ParserError> {
let name = self.parse_identifier()?;
let data_type = self.parse_data_type()?;
+ let mut options = vec![];
+ loop {
+ if self.parse_keyword(Keyword::CONSTRAINT) {
+ let name = Some(self.parse_identifier()?);
+ if let Some(option) = self.parse_optional_column_option()? {
+ options.push(ColumnOptionDef { name, option });
+ } else {
+ return self.expected(
+ "constraint details after CONSTRAINT <name>",
+ self.peek_token(),
+ );
+ }
+ } else if let Some(option) = self.parse_optional_column_option()? {
+ options.push(ColumnOptionDef { name: None, option });
+ } else {
+ break;
+ };
+ }
Ok(ColumnDef {
name,
data_type,
- options: Vec::new(), // No constraints expected here
+ options,
})
}
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_bigquery.rs b/app/tests/sqlparser_bigquery.rs
index 8f54f3c..8aa8ca2 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_bigquery.rs
+++ b/app/tests/sqlparser_bigquery.rs
@@ -2144,6 +2144,7 @@ fn test_bigquery_create_function() {
Ident::new("myfunction"),
]),
args: Some(vec![OperateFunctionArg::with_name("x", DataType::Float64),]),
+ return_table_name: None,
return_type: Some(DataType::Float64),
function_body: Some(CreateFunctionBody::AsAfterOptions(Expr::Value(
number("42").with_empty_span()
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_hive.rs b/app/tests/sqlparser_hive.rs
index 14dcbff..ccdb0c3 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_hive.rs
+++ b/app/tests/sqlparser_hive.rs
@@ -399,6 +399,7 @@ fn parse_create_function() {
name,
function_body,
using,
+ return_table_name: _,
..
}) => {
assert!(temporary);
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mssql.rs b/app/tests/sqlparser_mssql.rs
index 7b3769e..55efc28 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mssql.rs
+++ b/app/tests/sqlparser_mssql.rs
@@ -222,6 +222,7 @@ fn parse_create_function() {
default_expr: None,
},
]),
+ return_table_name: None,
return_type: Some(DataType::Int(None)),
function_body: Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements {
begin_token: AttachedToken::empty(),
@@ -288,6 +289,59 @@ fn parse_create_function() {
END\
";
let _ = ms().verified_stmt(create_function_with_return_expression);
+
+ let inline_table_valued_function = "\
+ CREATE FUNCTION some_inline_tvf(@foo INT) \
+ RETURNS TABLE \
+ RETURN SELECT @foo AS foo\
+ ";
+ match ms().verified_stmt(inline_table_valued_function) {
+ Statement::CreateFunction(CreateFunction {
+ name,
+ args,
+ return_table_name,
+ return_type: Some(DataType::Table(columns)),
+ function_body: Some(CreateFunctionBody::AsReturnQuery(query)),
+ ..
+ }) => {
+ assert_eq!(name, ObjectName::from(vec![Ident::new("some_inline_tvf")]));
+ assert_eq!(args, Some(vec![OperateFunctionArg::with_name("@foo", DataType::Int(None))]));
+ assert_eq!(return_table_name, None);
+ assert!(columns.is_empty());
+ assert_eq!(query.to_string(), "SELECT @foo AS foo");
+ }
+ _ => unreachable!(),
+ }
+
+ let multi_statement_table_valued_function = "\
+ CREATE FUNCTION some_multi_tvf(@foo INT) \
+ RETURNS @result TABLE (id INT PRIMARY KEY, name NVARCHAR(50) NOT NULL) \
+ BEGIN \
+ INSERT INTO @result SELECT @foo, 'x'; \
+ RETURN; \
+ END\
+ ";
+ match ms().verified_stmt(multi_statement_table_valued_function) {
+ Statement::CreateFunction(CreateFunction {
+ return_table_name,
+ return_type: Some(DataType::Table(columns)),
+ function_body: Some(CreateFunctionBody::AsBeginEnd(_)),
+ ..
+ }) => {
+ assert_eq!(return_table_name, Some(Ident::new("@result")));
+ assert_eq!(columns.len(), 2);
+ assert_eq!(columns[0].to_string(), "id INT PRIMARY KEY");
+ assert_eq!(columns[1].to_string(), "name NVARCHAR(50) NOT NULL");
+ }
+ _ => unreachable!(),
+ }
+
+ let inline_table_valued_function_with_as = "\
+ CREATE FUNCTION some_inline_tvf_with_as() \
+ RETURNS TABLE \
+ AS RETURN (SELECT 1 AS id)\
+ ";
+ let _ = ms().verified_stmt(inline_table_valued_function_with_as);
}
#[test]
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_postgres.rs b/app/tests/sqlparser_postgres.rs
index 682c0d6..ea81744 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_postgres.rs
+++ b/app/tests/sqlparser_postgres.rs
@@ -4135,6 +4135,7 @@ $$"#;
DataType::Varchar(None),
),
]),
+ return_table_name: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4173,6 +4174,7 @@ $$"#;
DataType::Int(None)
)
]),
+ return_table_name: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4215,6 +4217,7 @@ $$"#;
DataType::Int(None)
),
]),
+ return_table_name: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4257,6 +4260,7 @@ $$"#;
DataType::Int(None)
),
]),
+ return_table_name: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4292,6 +4296,7 @@ $$"#;
),
OperateFunctionArg::with_name("b", DataType::Varchar(None)),
]),
+ return_table_name: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4330,6 +4335,7 @@ fn parse_create_function() {
OperateFunctionArg::unnamed(DataType::Integer(None)),
OperateFunctionArg::unnamed(DataType::Integer(None)),
]),
+ return_table_name: None,
return_type: Some(DataType::Integer(None)),
language: Some("SQL".into()),
behavior: Some(FunctionBehavior::Immutable),
@@ -5873,6 +5879,7 @@ fn parse_trigger_related_functions() {
if_not_exists: false,
name: ObjectName::from(vec![Ident::new("emp_stamp")]),
args: Some(vec![]),
+ return_table_name: None,
return_type: Some(DataType::Trigger),
function_body: Some(
CreateFunctionBody::AsBeforeOptions(