STET

agent_patch

runs/2026-02-28__18-27-22__gpt-5-3-codex/flux-pr-1414/flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/agent-logs/agent.patch

14071 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/dml.rs b/app/src/ast/dml.rs
index c0e58e2..ae5e0de 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/dml.rs
+++ b/app/src/ast/dml.rs
@@ -25,8 +25,8 @@ 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,
+    OrderByExpr, Query, RowAccessPolicy, SelectItem, SqlOption, SqlTableOption,
+    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<SqlTableOption>,
     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-02-28__18-27-22__gpt-5-3-codex/app/src/ast/helpers/stmt_create_table.rs b/app/src/ast/helpers/stmt_create_table.rs
index 82532b2..cb629f5 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/helpers/stmt_create_table.rs
+++ b/app/src/ast/helpers/stmt_create_table.rs
@@ -10,8 +10,8 @@ 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,
+    ObjectName, OnCommit, OneOrManyWithParens, Query, RowAccessPolicy, SqlOption,
+    SqlTableOption, Statement, TableConstraint, TableEngine, Tag, WrappedCollection,
 };
 use crate::parser::ParserError;
 
@@ -60,7 +60,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<SqlTableOption>,
     pub file_format: Option<FileFormat>,
     pub location: Option<String>,
     pub query: Option<Box<Query>>,
@@ -200,7 +200,7 @@ impl CreateTableBuilder {
         self
     }
 
-    pub fn with_options(mut self, with_options: Vec<SqlOption>) -> Self {
+    pub fn with_options(mut self, with_options: Vec<SqlTableOption>) -> Self {
         self.with_options = with_options;
         self
     }
diff --git a/tmp/agent-patch-flux-pr-1414.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 480442b..b9350c4 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/mod.rs
+++ b/app/src/ast/mod.rs
@@ -2104,6 +2104,69 @@ impl fmt::Display for CreateTableOptions {
     }
 }
 
+/// A `CREATE TABLE ... WITH (...)` option.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum SqlTableOption {
+    /// Standard key-value option, e.g. `fillfactor = 70`.
+    KeyValue(SqlOption),
+    /// MSSQL option: `CLUSTERED INDEX (c1 [ASC|DESC], ...)`.
+    ClusteredIndex(Vec<OrderByExpr>),
+    /// MSSQL option: `CLUSTERED COLUMNSTORE INDEX`.
+    ClusteredColumnstoreIndex,
+    /// MSSQL option: `HEAP`.
+    Heap,
+    /// MSSQL option: `PARTITION (col RANGE {LEFT|RIGHT} FOR VALUES (...))`.
+    Partition {
+        column: Ident,
+        range_direction: PartitionRangeDirection,
+        for_values: Vec<Expr>,
+    },
+}
+
+impl fmt::Display for SqlTableOption {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            SqlTableOption::KeyValue(option) => write!(f, "{option}"),
+            SqlTableOption::ClusteredIndex(columns) => {
+                write!(f, "CLUSTERED INDEX ({})", display_comma_separated(columns))
+            }
+            SqlTableOption::ClusteredColumnstoreIndex => {
+                write!(f, "CLUSTERED COLUMNSTORE INDEX")
+            }
+            SqlTableOption::Heap => write!(f, "HEAP"),
+            SqlTableOption::Partition {
+                column,
+                range_direction,
+                for_values,
+            } => write!(
+                f,
+                "PARTITION ({column} RANGE {range_direction} FOR VALUES ({}))",
+                display_comma_separated(for_values)
+            ),
+        }
+    }
+}
+
+/// MSSQL `PARTITION` range direction in `CREATE TABLE ... WITH (...)`.
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum PartitionRangeDirection {
+    Left,
+    Right,
+}
+
+impl fmt::Display for PartitionRangeDirection {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            PartitionRangeDirection::Left => write!(f, "LEFT"),
+            PartitionRangeDirection::Right => write!(f, "RIGHT"),
+        }
+    }
+}
+
 /// A `FROM` clause within a `DELETE` statement.
 ///
 /// Syntax
diff --git a/tmp/agent-patch-flux-pr-1414.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 b39685c..4c53950 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -5617,7 +5617,7 @@ impl<'a> Parser<'a> {
         let clustered_by = self.parse_optional_clustered_by()?;
         let hive_formats = self.parse_hive_formats()?;
         // PostgreSQL supports `WITH ( options )`, before `AS`
-        let with_options = self.parse_options(Keyword::WITH)?;
+        let with_options = self.parse_create_table_with_options()?;
         let table_properties = self.parse_options(Keyword::TBLPROPERTIES)?;
 
         let engine = if self.parse_keyword(Keyword::ENGINE) {
@@ -6486,6 +6486,75 @@ impl<'a> Parser<'a> {
         Ok(SqlOption { name, value })
     }
 
+    pub fn parse_create_table_with_options(&mut self) -> Result<Vec<SqlTableOption>, 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![])
+        }
+    }
+
+    fn parse_create_table_with_option(&mut self) -> Result<SqlTableOption, ParserError> {
+        if dialect_of!(self is MsSqlDialect | GenericDialect) {
+            if self.parse_keyword(Keyword::CLUSTERED) {
+                if self.parse_keyword(Keyword::INDEX) {
+                    self.expect_token(&Token::LParen)?;
+                    let columns = self.parse_comma_separated(Parser::parse_order_by_expr)?;
+                    self.expect_token(&Token::RParen)?;
+                    return Ok(SqlTableOption::ClusteredIndex(columns));
+                }
+
+                if self.next_token_if_word("COLUMNSTORE") && self.parse_keyword(Keyword::INDEX) {
+                    return Ok(SqlTableOption::ClusteredColumnstoreIndex);
+                }
+
+                return self.expected("INDEX or COLUMNSTORE INDEX", self.peek_token());
+            }
+
+            if self.next_token_if_word("HEAP") {
+                return Ok(SqlTableOption::Heap);
+            }
+
+            if self.parse_keyword(Keyword::PARTITION) {
+                self.expect_token(&Token::LParen)?;
+                let column = self.parse_identifier(false)?;
+                self.expect_keyword(Keyword::RANGE)?;
+                let range_direction = if self.parse_keyword(Keyword::LEFT) {
+                    PartitionRangeDirection::Left
+                } else if self.parse_keyword(Keyword::RIGHT) {
+                    PartitionRangeDirection::Right
+                } else {
+                    return self.expected("LEFT or RIGHT", self.peek_token());
+                };
+                self.expect_keywords(&[Keyword::FOR, Keyword::VALUES])?;
+                self.expect_token(&Token::LParen)?;
+                let for_values = self.parse_comma_separated(Parser::parse_expr)?;
+                self.expect_token(&Token::RParen)?;
+                self.expect_token(&Token::RParen)?;
+                return Ok(SqlTableOption::Partition {
+                    column,
+                    range_direction,
+                    for_values,
+                });
+            }
+        }
+
+        Ok(SqlTableOption::KeyValue(self.parse_sql_option()?))
+    }
+
+    fn next_token_if_word(&mut self, expected: &str) -> bool {
+        if let Token::Word(w) = self.peek_token().token {
+            if w.value.eq_ignore_ascii_case(expected) {
+                self.next_token();
+                return true;
+            }
+        }
+        false
+    }
+
     pub fn parse_partition(&mut self) -> Result<Partition, ParserError> {
         self.expect_token(&Token::LParen)?;
         let partitions = self.parse_comma_separated(Parser::parse_expr)?;
diff --git a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_common.rs b/app/tests/sqlparser_common.rs
index bebd33d..cf7412e 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_common.rs
+++ b/app/tests/sqlparser_common.rs
@@ -3637,14 +3637,14 @@ fn parse_create_table_with_options() {
         Statement::CreateTable(CreateTable { with_options, .. }) => {
             assert_eq!(
                 vec![
-                    SqlOption {
+                    SqlTableOption::KeyValue(SqlOption {
                         name: "foo".into(),
                         value: Expr::Value(Value::SingleQuotedString("bar".into())),
-                    },
-                    SqlOption {
+                    }),
+                    SqlTableOption::KeyValue(SqlOption {
                         name: "a".into(),
                         value: Expr::Value(number("123")),
-                    },
+                    }),
                 ],
                 with_options
             );
diff --git a/tmp/agent-patch-flux-pr-1414.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 5c2ec87..5a3c012 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_mssql.rs
+++ b/app/tests/sqlparser_mssql.rs
@@ -653,6 +653,50 @@ fn parse_use() {
     }
 }
 
+#[test]
+fn parse_create_table_with_mssql_with_options() {
+    let sql = "CREATE TABLE t (c INT) WITH (CLUSTERED INDEX (c DESC), CLUSTERED COLUMNSTORE INDEX, HEAP, PARTITION (c RANGE RIGHT FOR VALUES (10, 20)), foo = 'bar')";
+    match ms().verified_stmt(sql) {
+        Statement::CreateTable(CreateTable { with_options, .. }) => {
+            assert_eq!(
+                with_options,
+                vec![
+                    SqlTableOption::ClusteredIndex(vec![OrderByExpr {
+                        expr: Expr::Identifier(Ident::new("c")),
+                        asc: Some(false),
+                        nulls_first: None,
+                        with_fill: None,
+                    }]),
+                    SqlTableOption::ClusteredColumnstoreIndex,
+                    SqlTableOption::Heap,
+                    SqlTableOption::Partition {
+                        column: Ident::new("c"),
+                        range_direction: PartitionRangeDirection::Right,
+                        for_values: vec![
+                            Expr::Value(number("10")),
+                            Expr::Value(number("20")),
+                        ],
+                    },
+                    SqlTableOption::KeyValue(SqlOption {
+                        name: Ident::new("foo"),
+                        value: Expr::Value(Value::SingleQuotedString("bar".to_owned())),
+                    }),
+                ]
+            );
+        }
+        _ => unreachable!(),
+    }
+}
+
+#[test]
+fn parse_create_table_with_mssql_partition_left() {
+    let sql = "CREATE TABLE t (c INT) WITH (PARTITION (c RANGE LEFT FOR VALUES (1)))";
+    let _ = ms_and_generic().one_statement_parses_to(
+        sql,
+        "CREATE TABLE t (c INT) WITH (PARTITION (c RANGE LEFT FOR VALUES (1)))",
+    );
+}
+
 fn ms() -> TestedDialects {
     TestedDialects {
         dialects: vec![Box::new(MsSqlDialect {})],
diff --git a/tmp/agent-patch-flux-pr-1414.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 1ebb5d5..3bebb0e 100644
--- a/tmp/agent-patch-flux-pr-1414.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_postgres.rs
+++ b/app/tests/sqlparser_postgres.rs
@@ -4482,14 +4482,14 @@ fn parse_create_table_with_options() {
         Statement::CreateTable(CreateTable { with_options, .. }) => {
             assert_eq!(
                 vec![
-                    SqlOption {
+                    SqlTableOption::KeyValue(SqlOption {
                         name: "foo".into(),
                         value: Expr::Value(Value::SingleQuotedString("bar".into())),
-                    },
-                    SqlOption {
+                    }),
+                    SqlTableOption::KeyValue(SqlOption {
                         name: "a".into(),
                         value: Expr::Value(number("123")),
-                    },
+                    }),
                 ],
                 with_options
             );