STET

agent_patch

runs/2026-02-21__03-36-16__gpt-5-1-codex-mini/flux-pr-1414/flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/agent-logs/agent.patch

14854 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/ast/dml.rs b/app/src/ast/dml.rs
index c0e58e2..792ce15 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/ast/dml.rs
+++ b/app/src/ast/dml.rs
@@ -22,11 +22,11 @@ use sqlparser_derive::{Visit, VisitMut};
 pub use super::ddl::{ColumnDef, TableConstraint};
 
 use super::{
-    display_comma_separated, display_separated, ClusteredBy, CommentDef, Expr, FileFormat,
-    FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident,
-    InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert, OneOrManyWithParens,
-    OrderByExpr, Query, RowAccessPolicy, SelectItem, SqlOption, SqliteOnConflict, TableEngine,
-    TableWithJoins, Tag, WrappedCollection,
+    display_comma_separated, display_separated, ClusteredBy, CommentDef, CreateTableWithOption,
+    Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat,
+    Ident, InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert,
+    OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem, SqlOption,
+    SqliteOnConflict, TableEngine, TableWithJoins, Tag, WrappedCollection,
 };
 
 /// CREATE INDEX statement.
@@ -116,7 +116,7 @@ pub struct CreateTable {
     pub hive_distribution: HiveDistributionStyle,
     pub hive_formats: Option<HiveFormat>,
     pub table_properties: Vec<SqlOption>,
-    pub with_options: Vec<SqlOption>,
+    pub with_options: Vec<CreateTableWithOption>,
     pub file_format: Option<FileFormat>,
     pub location: Option<String>,
     pub query: Option<Box<Query>>,
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/ast/helpers/stmt_create_table.rs b/app/src/ast/helpers/stmt_create_table.rs
index 82532b2..8b26c50 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/ast/helpers/stmt_create_table.rs
+++ b/app/src/ast/helpers/stmt_create_table.rs
@@ -9,9 +9,10 @@ use sqlparser_derive::{Visit, VisitMut};
 
 use super::super::dml::CreateTable;
 use crate::ast::{
-    ClusteredBy, ColumnDef, CommentDef, Expr, FileFormat, HiveDistributionStyle, HiveFormat, Ident,
-    ObjectName, OnCommit, OneOrManyWithParens, Query, RowAccessPolicy, SqlOption, Statement,
-    TableConstraint, TableEngine, Tag, WrappedCollection,
+    ClusteredBy, ColumnDef, CommentDef, CreateTableWithOption, Expr, FileFormat,
+    HiveDistributionStyle, HiveFormat, Ident, ObjectName, OnCommit, OneOrManyWithParens,
+    Query, RowAccessPolicy, SqlOption, Statement, TableConstraint, TableEngine, Tag,
+    WrappedCollection,
 };
 use crate::parser::ParserError;
 
@@ -60,7 +61,7 @@ pub struct CreateTableBuilder {
     pub hive_distribution: HiveDistributionStyle,
     pub hive_formats: Option<HiveFormat>,
     pub table_properties: Vec<SqlOption>,
-    pub with_options: Vec<SqlOption>,
+    pub with_options: Vec<CreateTableWithOption>,
     pub file_format: Option<FileFormat>,
     pub location: Option<String>,
     pub query: Option<Box<Query>>,
@@ -200,7 +201,7 @@ impl CreateTableBuilder {
         self
     }
 
-    pub fn with_options(mut self, with_options: Vec<SqlOption>) -> Self {
+    pub fn with_options(mut self, with_options: Vec<CreateTableWithOption>) -> Self {
         self.with_options = with_options;
         self
     }
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/ast/mod.rs b/app/src/ast/mod.rs
index 480442b..cb2985e 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/ast/mod.rs
+++ b/app/src/ast/mod.rs
@@ -69,6 +69,7 @@ pub use self::value::{
 use crate::ast::helpers::stmt_data_loading::{
     DataLoadingOptions, StageLoadSelectItem, StageParamsObject,
 };
+use crate::tokenizer::Token;
 #[cfg(feature = "visitor")]
 pub use visitor::*;
 
@@ -5739,6 +5740,114 @@ impl fmt::Display for SqlOption {
     }
 }
 
+/// CREATE TABLE `WITH` options, including MSSQL-specific clauses (e.g. `CLUSTERED INDEX`).
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum CreateTableWithOption {
+    /// Generic `WITH` option that uses `name = value` syntax.
+    SqlOption(SqlOption),
+    /// MSSQL `CLUSTERED COLUMNSTORE INDEX` option.
+    ClusteredColumnstoreIndex,
+    /// MSSQL `CLUSTERED INDEX (...)` option.
+    ClusteredIndex { columns: Vec<Expr> },
+    /// MSSQL `HEAP` option.
+    Heap,
+    /// MSSQL `PARTITION (...)` option (captures the token stream inside the parentheses).
+    Partition(Vec<Token>),
+}
+
+impl fmt::Display for CreateTableWithOption {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            CreateTableWithOption::SqlOption(option) => write!(f, "{option}"),
+            CreateTableWithOption::ClusteredColumnstoreIndex => {
+                f.write_str("CLUSTERED COLUMNSTORE INDEX")
+            }
+            CreateTableWithOption::ClusteredIndex { columns } => {
+                write!(
+                    f,
+                    "CLUSTERED INDEX ({})",
+                    display_comma_separated(columns)
+                )
+            }
+            CreateTableWithOption::Heap => f.write_str("HEAP"),
+            CreateTableWithOption::Partition(tokens) => {
+                f.write_str("PARTITION (")?;
+                write_token_sequence(tokens, f)?;
+                f.write_str(")")
+            }
+        }
+    }
+}
+
+impl From<SqlOption> for CreateTableWithOption {
+    fn from(sql_option: SqlOption) -> Self {
+        CreateTableWithOption::SqlOption(sql_option)
+    }
+}
+
+fn write_token_sequence(tokens: &[Token], f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    let mut prev: Option<&Token> = None;
+    for token in tokens {
+        if should_insert_space(prev, token) {
+            f.write_str(" ")?;
+        }
+        write!(f, "{token}")?;
+        prev = Some(token);
+    }
+    Ok(())
+}
+
+fn should_insert_space(prev: Option<&Token>, current: &Token) -> bool {
+    let prev = match prev {
+        Some(prev) => prev,
+        None => return false,
+    };
+
+    if matches!(
+        current,
+        Token::Comma
+            | Token::Period
+            | Token::Colon
+            | Token::DoubleColon
+            | Token::Eq
+            | Token::Neq
+            | Token::Lt
+            | Token::Gt
+            | Token::LtEq
+            | Token::GtEq
+            | Token::DoubleEq
+            | Token::Spaceship
+            | Token::Plus
+            | Token::Minus
+            | Token::Mul
+            | Token::Div
+            | Token::DuckIntDiv
+            | Token::StringConcat
+            | Token::Mod
+            | Token::RParen
+            | Token::RBracket
+            | Token::RBrace
+            | Token::SemiColon
+            | Token::Backslash
+            | Token::Arrow
+            | Token::LongArrow
+            | Token::HashArrow
+    ) {
+        return false;
+    }
+
+    if matches!(
+        prev,
+        Token::LParen | Token::LBracket | Token::LBrace | Token::Period | Token::Colon | Token::DoubleColon
+    ) {
+        return false;
+    }
+
+    true
+}
+
 #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/parser/mod.rs b/app/src/parser/mod.rs
index b39685c..30d179f 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -4443,7 +4443,7 @@ impl<'a> Parser<'a> {
         let name = self.parse_object_name(allow_unquoted_hyphen)?;
         let columns = self.parse_view_columns()?;
         let mut options = CreateTableOptions::None;
-        let with_options = self.parse_options(Keyword::WITH)?;
+        let with_options = self.parse_create_table_with_options()?;
         if !with_options.is_empty() {
             options = CreateTableOptions::With(with_options);
         }
@@ -6419,6 +6419,77 @@ impl<'a> Parser<'a> {
         }
     }
 
+    pub fn parse_create_table_with_options(
+        &mut self,
+    ) -> Result<Vec<CreateTableWithOption>, ParserError> {
+        if self.parse_keyword(Keyword::WITH) {
+            self.expect_token(&Token::LParen)?;
+            let options = self
+                .parse_comma_separated(Parser::parse_create_table_with_option)?;
+            self.expect_token(&Token::RParen)?;
+            Ok(options)
+        } else {
+            Ok(vec![])
+        }
+    }
+
+    pub fn parse_create_table_with_option(&mut self) -> Result<CreateTableWithOption, ParserError> {
+        if dialect_of!(self is MsSqlDialect) {
+            if self.parse_keywords(&[
+                Keyword::CLUSTERED,
+                Keyword::COLUMNSTORE,
+                Keyword::INDEX,
+            ]) {
+                return Ok(CreateTableWithOption::ClusteredColumnstoreIndex);
+            }
+            if self.parse_keywords(&[Keyword::CLUSTERED, Keyword::INDEX]) {
+                self.expect_token(&Token::LParen)?;
+                let columns = if self.peek_token().token == Token::RParen {
+                    vec![]
+                } else {
+                    self.parse_comma_separated(Parser::parse_expr)?
+                };
+                self.expect_token(&Token::RParen)?;
+                return Ok(CreateTableWithOption::ClusteredIndex { columns });
+            }
+            if self.parse_keyword(Keyword::HEAP) {
+                return Ok(CreateTableWithOption::Heap);
+            }
+            if self.parse_keyword(Keyword::PARTITION) {
+                let tokens = self.parse_parenthesized_token_sequence()?;
+                return Ok(CreateTableWithOption::Partition(tokens));
+            }
+        }
+
+        let option = self.parse_sql_option()?;
+        Ok(option.into())
+    }
+
+    fn parse_parenthesized_token_sequence(&mut self) -> Result<Vec<Token>, ParserError> {
+        self.expect_token(&Token::LParen)?;
+        let mut tokens = vec![];
+        let mut depth = 1;
+        while depth > 0 {
+            let next = self.next_token();
+            match next.token {
+                Token::EOF => return self.expected("')'", next),
+                Token::LParen => {
+                    depth += 1;
+                    tokens.push(Token::LParen);
+                }
+                Token::RParen => {
+                    depth -= 1;
+                    if depth == 0 {
+                        break;
+                    }
+                    tokens.push(Token::RParen);
+                }
+                token => tokens.push(token),
+            }
+        }
+        Ok(tokens)
+    }
+
     pub fn parse_index_type(&mut self) -> Result<IndexType, ParserError> {
         if self.parse_keyword(Keyword::BTREE) {
             Ok(IndexType::BTree)
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_common.rs b/app/tests/sqlparser_common.rs
index bebd33d..fa71598 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_common.rs
+++ b/app/tests/sqlparser_common.rs
@@ -3640,11 +3640,13 @@ fn parse_create_table_with_options() {
                     SqlOption {
                         name: "foo".into(),
                         value: Expr::Value(Value::SingleQuotedString("bar".into())),
-                    },
+                    }
+                    .into(),
                     SqlOption {
                         name: "a".into(),
                         value: Expr::Value(number("123")),
-                    },
+                    }
+                    .into(),
                 ],
                 with_options
             );
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_mssql.rs b/app/tests/sqlparser_mssql.rs
index 5c2ec87..75400d5 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_mssql.rs
+++ b/app/tests/sqlparser_mssql.rs
@@ -199,6 +199,29 @@ fn parse_mssql_top_paren() {
     assert!(!top.percent);
 }
 
+#[test]
+fn parse_mssql_create_table_with_table_opts() {
+    let sql = "CREATE TABLE dbo.test (id INT) WITH (HEAP, CLUSTERED INDEX (id), CLUSTERED COLUMNSTORE INDEX, PARTITION ([OrderDateKey] RANGE RIGHT FOR VALUES (20000101,20010101)))";
+    let canonical = "CREATE TABLE dbo.test (id INT) WITH (HEAP, CLUSTERED INDEX (id), CLUSTERED COLUMNSTORE INDEX, PARTITION ([OrderDateKey] RANGE RIGHT FOR VALUES (20000101, 20010101)))";
+    let stmt = ms().one_statement_parses_to(sql, canonical);
+    match stmt {
+        Statement::CreateTable(CreateTable { with_options, .. }) => {
+            assert_eq!(with_options.len(), 4);
+            assert!(matches!(with_options[0], CreateTableWithOption::Heap));
+            match &with_options[1] {
+                CreateTableWithOption::ClusteredIndex { columns } => assert_eq!(columns, &vec![Expr::Identifier(Ident::new("id"))]),
+                other => panic!("expected clustered index, got {other:?}"),
+            }
+            assert!(matches!(with_options[2], CreateTableWithOption::ClusteredColumnstoreIndex));
+            assert_eq!(
+                with_options[3].to_string(),
+                "PARTITION ([OrderDateKey] RANGE RIGHT FOR VALUES (20000101, 20010101))"
+            );
+        }
+        _ => unreachable!(),
+    }
+}
+
 #[test]
 fn parse_mssql_top_percent() {
     let sql = "SELECT TOP (5) PERCENT * FROM foo";
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_postgres.rs b/app/tests/sqlparser_postgres.rs
index 1ebb5d5..5673f4e 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_postgres.rs
+++ b/app/tests/sqlparser_postgres.rs
@@ -4485,11 +4485,13 @@ fn parse_create_table_with_options() {
                     SqlOption {
                         name: "foo".into(),
                         value: Expr::Value(Value::SingleQuotedString("bar".into())),
-                    },
+                    }
+                    .into(),
                     SqlOption {
                         name: "a".into(),
                         value: Expr::Value(number("123")),
-                    },
+                    }
+                    .into(),
                 ],
                 with_options
             );