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
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
);