agent_patch
runs/2026-02-28__18-27-22__gpt-5-3-codex/flux-pr-1839/flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/agent-logs/agent.patch
13247 bytes
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/ddl.rs b/app/src/ast/ddl.rs
index a8a1fdb..1c1b427 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/ddl.rs
+++ b/app/src/ast/ddl.rs
@@ -2258,6 +2258,13 @@ pub struct CreateFunction {
pub if_not_exists: bool,
pub name: ObjectName,
pub args: Option<Vec<OperateFunctionArg>>,
+ /// Named table variable in SQL Server table-valued functions.
+ ///
+ /// Example:
+ /// ```sql
+ /// RETURNS @result TABLE(id INT)
+ /// ```
+ pub return_table: Option<Ident>,
pub return_type: Option<DataType>,
/// The expression that defines the function.
///
@@ -2330,7 +2337,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}")?;
+ if let Some(return_table) = &self.return_table {
+ write!(f, " RETURNS {return_table} {return_type}")?;
+ } else {
+ write!(f, " RETURNS {return_type}")?;
+ }
}
if let Some(determinism_specifier) = &self.determinism_specifier {
write!(f, " {determinism_specifier}")?;
@@ -2356,6 +2367,9 @@ impl fmt::Display for CreateFunction {
if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
write!(f, " RETURN {function_body}")?;
}
+ if let Some(CreateFunctionBody::ReturnQuery(function_body)) = &self.function_body {
+ write!(f, " RETURN {function_body}")?;
+ }
if let Some(using) = &self.using {
write!(f, " {using}")?;
}
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/mod.rs b/app/src/ast/mod.rs
index e18251e..f8d528f 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/mod.rs
+++ b/app/src/ast/mod.rs
@@ -8780,6 +8780,17 @@ pub enum CreateFunctionBody {
///
/// [PostgreSQL]: https://www.postgresql.org/docs/current/sql-createfunction.html
Return(Expr),
+ /// Function body query using the `RETURN` keyword.
+ ///
+ /// Example:
+ /// ```sql
+ /// CREATE FUNCTION my_tvf()
+ /// RETURNS TABLE
+ /// RETURN SELECT 1 AS id;
+ /// ```
+ ///
+ /// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql
+ ReturnQuery(Box<Query>),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/parser/mod.rs b/app/src/parser/mod.rs
index 47b321d..70ba582 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/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: 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: 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: None,
return_type,
function_body,
language,
@@ -5204,19 +5207,36 @@ impl<'a> Parser<'a> {
let (name, args) = self.parse_create_function_name_and_params()?;
self.expect_keyword(Keyword::RETURNS)?;
+ let mut return_table = None;
+ if self.peek_token().token == Token::Word(_) {
+ let table_name = self.parse_identifier()?;
+ if self.peek_keyword(Keyword::TABLE) {
+ return_table = Some(table_name);
+ } else {
+ self.prev_token();
+ }
+ }
let return_type = Some(self.parse_data_type()?);
- self.expect_keyword_is(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 _ = 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 {
+ self.expect_keyword(Keyword::RETURN)?;
+ if self.peek_sub_query() {
+ Some(CreateFunctionBody::ReturnQuery(Box::new(self.parse_query()?)))
+ } else {
+ Some(CreateFunctionBody::Return(self.parse_expr()?))
+ }
+ };
Ok(Statement::CreateFunction(CreateFunction {
or_alter,
@@ -5225,6 +5245,7 @@ impl<'a> Parser<'a> {
if_not_exists: false,
name,
args: Some(args),
+ return_table,
return_type,
function_body,
language: None,
@@ -9839,20 +9860,19 @@ 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()?;
- Ok(ColumnDef {
- name,
- data_type,
- options: Vec::new(), // No constraints expected here
- })
+ self.parse_column_def()
}
fn parse_returns_table_columns(&mut self) -> Result<Vec<ColumnDef>, ParserError> {
- self.expect_token(&Token::LParen)?;
- let columns = self.parse_comma_separated(Parser::parse_returns_table_column)?;
- self.expect_token(&Token::RParen)?;
- Ok(columns)
+ if self.consume_token(&Token::LParen) {
+ let columns = self.parse_comma_separated(Parser::parse_returns_table_column)?;
+ self.expect_token(&Token::RParen)?;
+ Ok(columns)
+ } else if dialect_of!(self is MsSqlDialect) {
+ Ok(vec![])
+ } else {
+ self.expected("a list of columns in parentheses", self.peek_token())
+ }
}
pub fn parse_string_values(&mut self) -> Result<Vec<String>, ParserError> {
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_bigquery.rs b/app/tests/sqlparser_bigquery.rs
index 8f54f3c..a408821 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/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: 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-3-codex/app/tests/sqlparser_mssql.rs b/app/tests/sqlparser_mssql.rs
index 7b3769e..ffefd14 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_mssql.rs
+++ b/app/tests/sqlparser_mssql.rs
@@ -222,6 +222,7 @@ fn parse_create_function() {
default_expr: None,
},
]),
+ return_table: None,
return_type: Some(DataType::Int(None)),
function_body: Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements {
begin_token: AttachedToken::empty(),
@@ -288,6 +289,68 @@ fn parse_create_function() {
END\
";
let _ = ms().verified_stmt(create_function_with_return_expression);
+
+ let inline_table_valued_function = "\
+ CREATE FUNCTION some_tvf(@foo INT) \
+ RETURNS TABLE \
+ AS \
+ RETURN SELECT @foo AS foo\
+ ";
+ let stmt = ms().verified_stmt(inline_table_valued_function);
+ match stmt {
+ Statement::CreateFunction(CreateFunction {
+ return_table,
+ return_type,
+ function_body,
+ ..
+ }) => {
+ assert_eq!(return_table, None);
+ assert_eq!(return_type, Some(DataType::Table(vec![])));
+ assert!(matches!(function_body, Some(CreateFunctionBody::ReturnQuery(_))));
+ }
+ _ => unreachable!(),
+ }
+
+ let inline_table_valued_function_without_as = "\
+ CREATE FUNCTION some_tvf(@foo INT) \
+ RETURNS TABLE \
+ RETURN SELECT @foo AS foo\
+ ";
+ let _ = ms().verified_stmt(inline_table_valued_function_without_as);
+
+ let multi_statement_table_valued_function = "\
+ CREATE FUNCTION some_tvf(@foo INT) \
+ RETURNS @result TABLE(id INT NOT NULL, name VARCHAR(20) NULL) \
+ BEGIN \
+ INSERT INTO @result \
+ SELECT @foo, 'x'; \
+ RETURN; \
+ END\
+ ";
+ let stmt = ms().verified_stmt(multi_statement_table_valued_function);
+ match stmt {
+ Statement::CreateFunction(CreateFunction {
+ return_table,
+ return_type,
+ function_body,
+ ..
+ }) => {
+ assert_eq!(return_table, Some(Ident::new("@result")));
+ match return_type {
+ Some(DataType::Table(columns)) => {
+ assert_eq!(columns.len(), 2);
+ assert!(!columns[0].options.is_empty());
+ assert!(!columns[1].options.is_empty());
+ }
+ _ => unreachable!(),
+ }
+ assert!(matches!(
+ function_body,
+ Some(CreateFunctionBody::AsBeginEnd(_))
+ ));
+ }
+ _ => unreachable!(),
+ }
}
#[test]
diff --git a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_postgres.rs b/app/tests/sqlparser_postgres.rs
index 682c0d6..9ef5109 100644
--- a/tmp/agent-patch-flux-pr-1839.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_postgres.rs
+++ b/app/tests/sqlparser_postgres.rs
@@ -4135,6 +4135,7 @@ $$"#;
DataType::Varchar(None),
),
]),
+ return_table: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4173,6 +4174,7 @@ $$"#;
DataType::Int(None)
)
]),
+ return_table: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4215,6 +4217,7 @@ $$"#;
DataType::Int(None)
),
]),
+ return_table: None,
return_type: Some(DataType::Boolean),
language: Some("plpgsql".into()),
behavior: None,
@@ -4257,6 +4260,7 @@ $$"#;
DataType::Int(None)
),
]),
+ return_table: 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: 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: 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: None,
return_type: Some(DataType::Trigger),
function_body: Some(
CreateFunctionBody::AsBeforeOptions(