agent_patch
runs/2026-02-28__18-27-22__gpt-5-4/flux-pr-2172/flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/agent-logs/agent.patch
26459 bytes
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/query.rs b/app/src/ast/query.rs
index 08448ca..7515b71 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/query.rs
+++ b/app/src/ast/query.rs
@@ -348,8 +348,10 @@ pub struct Select {
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
pub optimizer_hint: Option<OptimizerHint>,
- /// `SELECT [DISTINCT] ...`
+ /// `SELECT [ALL | DISTINCT | DISTINCTROW | DISTINCT ON (...)] ...`
pub distinct: Option<Distinct>,
+ /// MySQL-specific `SELECT` modifiers.
+ pub modifiers: Vec<SelectModifier>,
/// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
pub top: Option<Top>,
/// Whether the top was located before `ALL`/`DISTINCT`
@@ -435,6 +437,10 @@ impl fmt::Display for Select {
f.write_str(" ")?;
distinct.fmt(f)?;
}
+ if !self.modifiers.is_empty() {
+ f.write_str(" ")?;
+ display_separated(&self.modifiers, " ").fmt(f)?;
+ }
if let Some(ref top) = self.top {
if !self.top_before_distinct {
f.write_str(" ")?;
@@ -3351,11 +3357,17 @@ impl fmt::Display for NonBlock {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
-/// `DISTINCT` or `DISTINCT ON (...)` modifiers for `SELECT` lists.
+/// `ALL`, `DISTINCT`, `DISTINCTROW`, or `DISTINCT ON (...)` modifiers for `SELECT` lists.
pub enum Distinct {
+ /// `ALL` (keep duplicate rows)
+ All,
+
/// `DISTINCT` (remove duplicate rows)
Distinct,
+ /// `DISTINCTROW` (MySQL synonym for `DISTINCT`)
+ DistinctRow,
+
/// `DISTINCT ON (...)` (Postgres extension)
On(Vec<Expr>),
}
@@ -3363,7 +3375,9 @@ pub enum Distinct {
impl fmt::Display for Distinct {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
+ Distinct::All => write!(f, "ALL"),
Distinct::Distinct => write!(f, "DISTINCT"),
+ Distinct::DistinctRow => write!(f, "DISTINCTROW"),
Distinct::On(col_names) => {
let col_names = display_comma_separated(col_names);
write!(f, "DISTINCT ON ({col_names})")
@@ -3372,6 +3386,42 @@ impl fmt::Display for Distinct {
}
}
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+/// MySQL `SELECT` modifiers.
+pub enum SelectModifier {
+ /// `HIGH_PRIORITY`
+ HighPriority,
+ /// `STRAIGHT_JOIN`
+ StraightJoin,
+ /// `SQL_SMALL_RESULT`
+ SqlSmallResult,
+ /// `SQL_BIG_RESULT`
+ SqlBigResult,
+ /// `SQL_BUFFER_RESULT`
+ SqlBufferResult,
+ /// `SQL_NO_CACHE`
+ SqlNoCache,
+ /// `SQL_CALC_FOUND_ROWS`
+ SqlCalcFoundRows,
+}
+
+impl fmt::Display for SelectModifier {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let keyword = match self {
+ SelectModifier::HighPriority => "HIGH_PRIORITY",
+ SelectModifier::StraightJoin => "STRAIGHT_JOIN",
+ SelectModifier::SqlSmallResult => "SQL_SMALL_RESULT",
+ SelectModifier::SqlBigResult => "SQL_BIG_RESULT",
+ SelectModifier::SqlBufferResult => "SQL_BUFFER_RESULT",
+ SelectModifier::SqlNoCache => "SQL_NO_CACHE",
+ SelectModifier::SqlCalcFoundRows => "SQL_CALC_FOUND_ROWS",
+ };
+ f.write_str(keyword)
+ }
+}
+
#[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-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/spans.rs b/app/src/ast/spans.rs
index 60c983f..1233f93 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/spans.rs
+++ b/app/src/ast/spans.rs
@@ -2238,6 +2238,7 @@ impl Spanned for Select {
select_token,
optimizer_hint: _,
distinct: _, // todo
+ modifiers: _, // todo, mysql specific
top: _, // todo, mysql specific
projection,
exclude: _,
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/keywords.rs b/app/src/keywords.rs
index 964e4b3..9d3d652 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/keywords.rs
+++ b/app/src/keywords.rs
@@ -333,6 +333,7 @@ define_keywords!(
DISCARD,
DISCONNECT,
DISTINCT,
+ DISTINCTROW,
DISTRIBUTE,
DIV,
DO,
@@ -953,6 +954,11 @@ define_keywords!(
SPECIFICTYPE,
SPGIST,
SQL,
+ SQL_BIG_RESULT,
+ SQL_BUFFER_RESULT,
+ SQL_CALC_FOUND_ROWS,
+ SQL_NO_CACHE,
+ SQL_SMALL_RESULT,
SQLEXCEPTION,
SQLSTATE,
SQLWARNING,
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs b/app/src/parser/mod.rs
index 5fa224f..0e5827b 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -4923,32 +4923,95 @@ impl<'a> Parser<'a> {
}
}
- /// Parse either `ALL`, `DISTINCT` or `DISTINCT ON (...)`. Returns [`None`] if `ALL` is parsed
- /// and results in a [`ParserError`] if both `ALL` and `DISTINCT` are found.
- pub fn parse_all_or_distinct(&mut self) -> Result<Option<Distinct>, ParserError> {
- let loc = self.peek_token().span.start;
- let all = self.parse_keyword(Keyword::ALL);
- let distinct = self.parse_keyword(Keyword::DISTINCT);
- if !distinct {
- return Ok(None);
- }
- if all {
- return parser_err!("Cannot specify both ALL and DISTINCT".to_string(), loc);
+ /// Parse `SELECT` duplicate-row modifiers and MySQL-specific `SELECT` modifiers.
+ pub fn parse_select_modifiers(
+ &mut self,
+ ) -> Result<(Option<Distinct>, Vec<SelectModifier>), ParserError> {
+ let mut distinct = None;
+ let mut modifiers = vec![];
+
+ loop {
+ let next_distinct = if self.parse_keyword(Keyword::ALL) {
+ Some(Distinct::All)
+ } else if self.parse_keyword(Keyword::DISTINCTROW) {
+ Some(Distinct::DistinctRow)
+ } else if self.parse_keyword(Keyword::DISTINCT) {
+ if self.parse_keyword(Keyword::ON) {
+ self.expect_token(&Token::LParen)?;
+ let col_names = if self.consume_token(&Token::RParen) {
+ self.prev_token();
+ Vec::new()
+ } else {
+ self.parse_comma_separated(Parser::parse_expr)?
+ };
+ self.expect_token(&Token::RParen)?;
+ Some(Distinct::On(col_names))
+ } else {
+ Some(Distinct::Distinct)
+ }
+ } else {
+ None
+ };
+
+ if let Some(next_distinct) = next_distinct {
+ Self::set_select_distinct(
+ &mut distinct,
+ next_distinct,
+ self.get_current_token().clone(),
+ )?;
+ continue;
+ }
+
+ if !dialect_of!(self is MySqlDialect) {
+ break;
+ }
+
+ let modifier = if self.parse_keyword(Keyword::HIGH_PRIORITY) {
+ Some(SelectModifier::HighPriority)
+ } else if self.parse_keyword(Keyword::STRAIGHT_JOIN) {
+ Some(SelectModifier::StraightJoin)
+ } else if self.parse_keyword(Keyword::SQL_SMALL_RESULT) {
+ Some(SelectModifier::SqlSmallResult)
+ } else if self.parse_keyword(Keyword::SQL_BIG_RESULT) {
+ Some(SelectModifier::SqlBigResult)
+ } else if self.parse_keyword(Keyword::SQL_BUFFER_RESULT) {
+ Some(SelectModifier::SqlBufferResult)
+ } else if self.parse_keyword(Keyword::SQL_NO_CACHE) {
+ Some(SelectModifier::SqlNoCache)
+ } else if self.parse_keyword(Keyword::SQL_CALC_FOUND_ROWS) {
+ Some(SelectModifier::SqlCalcFoundRows)
+ } else {
+ None
+ };
+
+ if let Some(modifier) = modifier {
+ modifiers.push(modifier);
+ continue;
+ }
+
+ break;
}
- let on = self.parse_keyword(Keyword::ON);
- if !on {
- return Ok(Some(Distinct::Distinct));
+
+ Ok((distinct, modifiers))
+ }
+
+ fn set_select_distinct(
+ distinct: &mut Option<Distinct>,
+ next_distinct: Distinct,
+ token: TokenWithSpan,
+ ) -> Result<(), ParserError> {
+ if let Some(existing) = distinct.as_ref() {
+ let msg = if matches!(existing, Distinct::All) || matches!(next_distinct, Distinct::All)
+ {
+ "Cannot specify both ALL and DISTINCT".to_string()
+ } else {
+ "Cannot specify multiple DISTINCT modifiers".to_string()
+ };
+ return parser_err!(msg, token.span.start);
}
- self.expect_token(&Token::LParen)?;
- let col_names = if self.consume_token(&Token::RParen) {
- self.prev_token();
- Vec::new()
- } else {
- self.parse_comma_separated(Parser::parse_expr)?
- };
- self.expect_token(&Token::RParen)?;
- Ok(Some(Distinct::On(col_names)))
+ *distinct = Some(next_distinct);
+ Ok(())
}
/// Parse a SQL CREATE statement
@@ -13861,6 +13924,7 @@ impl<'a> Parser<'a> {
select_token: AttachedToken(from_token),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![],
@@ -13896,7 +13960,7 @@ impl<'a> Parser<'a> {
top = Some(self.parse_top()?);
top_before_distinct = true;
}
- let distinct = self.parse_all_or_distinct()?;
+ let (distinct, modifiers) = self.parse_select_modifiers()?;
if !self.dialect.supports_top_before_distinct() && self.parse_keyword(Keyword::TOP) {
top = Some(self.parse_top()?);
}
@@ -14044,6 +14108,7 @@ impl<'a> Parser<'a> {
select_token: AttachedToken(select_token),
optimizer_hint,
distinct,
+ modifiers,
top,
top_before_distinct,
projection,
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_bigquery.rs b/app/tests/sqlparser_bigquery.rs
index fb28b4d..5556f90 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_bigquery.rs
+++ b/app/tests/sqlparser_bigquery.rs
@@ -2683,6 +2683,7 @@ fn test_export_data() {
)),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
@@ -2788,6 +2789,7 @@ fn test_export_data() {
)),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_clickhouse.rs b/app/tests/sqlparser_clickhouse.rs
index ac31a27..f4f28ac 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_clickhouse.rs
+++ b/app/tests/sqlparser_clickhouse.rs
@@ -43,6 +43,7 @@ fn parse_map_access_expr() {
distinct: None,
optimizer_hint: None,
select_token: AttachedToken::empty(),
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![UnnamedExpr(Expr::CompoundFieldAccess {
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_common.rs b/app/tests/sqlparser_common.rs
index e6a48c7..a44a89c 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_common.rs
+++ b/app/tests/sqlparser_common.rs
@@ -473,6 +473,7 @@ fn parse_update_set_from() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
@@ -1074,7 +1075,9 @@ fn parse_select_distinct_missing_paren() {
#[test]
fn parse_select_all() {
- one_statement_parses_to("SELECT ALL name FROM customer", "SELECT name FROM customer");
+ let select = verified_only_select("SELECT ALL name FROM customer");
+ assert_eq!(select.distinct, Some(Distinct::All));
+ one_statement_parses_to("SELECT ALL name FROM customer", "SELECT ALL name FROM customer");
}
#[test]
@@ -5809,6 +5812,7 @@ fn test_parse_named_window() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
@@ -6540,6 +6544,7 @@ fn parse_interval_and_or_xor() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![UnnamedExpr(Expr::Identifier(Ident {
@@ -8917,6 +8922,7 @@ fn lateral_function() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions::default())],
exclude: None,
@@ -9919,6 +9925,7 @@ fn parse_merge() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::Wildcard(
@@ -12323,6 +12330,7 @@ fn parse_unload() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![UnnamedExpr(Expr::Identifier(Ident::new("cola"))),],
@@ -12632,6 +12640,7 @@ fn parse_connect_by() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
@@ -12715,6 +12724,7 @@ fn parse_connect_by() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
@@ -13649,6 +13659,7 @@ fn test_extract_seconds_ok() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![UnnamedExpr(Expr::Extract {
@@ -14830,9 +14841,9 @@ fn test_load_extension() {
#[test]
fn test_select_top() {
let dialects = all_dialects_where(|d| d.supports_top_before_distinct());
- dialects.one_statement_parses_to("SELECT ALL * FROM tbl", "SELECT * FROM tbl");
+ dialects.one_statement_parses_to("SELECT ALL * FROM tbl", "SELECT ALL * FROM tbl");
dialects.verified_stmt("SELECT TOP 3 * FROM tbl");
- dialects.one_statement_parses_to("SELECT TOP 3 ALL * FROM tbl", "SELECT TOP 3 * FROM tbl");
+ dialects.one_statement_parses_to("SELECT TOP 3 ALL * FROM tbl", "SELECT TOP 3 ALL * FROM tbl");
dialects.verified_stmt("SELECT TOP 3 DISTINCT * FROM tbl");
dialects.verified_stmt("SELECT TOP 3 DISTINCT a, b, c FROM tbl");
}
@@ -15789,6 +15800,7 @@ fn test_select_from_first() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
projection,
exclude: None,
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_duckdb.rs b/app/tests/sqlparser_duckdb.rs
index 7cc710d..3304a76 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_duckdb.rs
+++ b/app/tests/sqlparser_duckdb.rs
@@ -268,6 +268,7 @@ fn test_select_union_by_name() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions::default())],
exclude: None,
@@ -300,6 +301,7 @@ fn test_select_union_by_name() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions::default())],
exclude: None,
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mssql.rs b/app/tests/sqlparser_mssql.rs
index d770008..7c4282a 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mssql.rs
+++ b/app/tests/sqlparser_mssql.rs
@@ -143,6 +143,7 @@ fn parse_create_procedure() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Value(
@@ -1351,6 +1352,7 @@ fn parse_substring_in_select() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: Some(Distinct::Distinct),
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Substring {
@@ -1509,6 +1511,7 @@ fn parse_mssql_declare() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::BinaryOp {
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mysql.rs b/app/tests/sqlparser_mysql.rs
index 2c94279..71da34c 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mysql.rs
+++ b/app/tests/sqlparser_mysql.rs
@@ -1437,6 +1437,7 @@ fn parse_escaped_quote_identifiers_with_escape() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident {
@@ -1493,6 +1494,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident {
@@ -1541,6 +1543,7 @@ fn parse_escaped_backticks_with_escape() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident {
@@ -1593,6 +1596,7 @@ fn parse_escaped_backticks_with_no_escape() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident {
@@ -2413,6 +2417,7 @@ fn parse_select_with_numeric_prefix_column_name() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident::new(
@@ -2588,6 +2593,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
@@ -3222,6 +3228,7 @@ fn parse_substring_in_select() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: Some(Distinct::Distinct),
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Substring {
@@ -3280,6 +3287,38 @@ fn parse_substring_in_select() {
}
}
+#[test]
+fn parse_mysql_select_modifiers() {
+ let select = mysql().verified_only_select(
+ "SELECT HIGH_PRIORITY SQL_BUFFER_RESULT ALL SQL_NO_CACHE SQL_CALC_FOUND_ROWS id FROM t",
+ );
+ assert_eq!(select.distinct, Some(Distinct::All));
+ assert_eq!(
+ select.modifiers,
+ vec![
+ SelectModifier::HighPriority,
+ SelectModifier::SqlBufferResult,
+ SelectModifier::SqlNoCache,
+ SelectModifier::SqlCalcFoundRows,
+ ]
+ );
+ mysql().one_statement_parses_to(
+ "SELECT HIGH_PRIORITY SQL_BUFFER_RESULT ALL SQL_NO_CACHE SQL_CALC_FOUND_ROWS id FROM t",
+ "SELECT ALL HIGH_PRIORITY SQL_BUFFER_RESULT SQL_NO_CACHE SQL_CALC_FOUND_ROWS id FROM t",
+ );
+}
+
+#[test]
+fn parse_mysql_distinctrow() {
+ let select = mysql().verified_only_select("SELECT SQL_SMALL_RESULT DISTINCTROW id FROM t");
+ assert_eq!(select.distinct, Some(Distinct::DistinctRow));
+ assert_eq!(select.modifiers, vec![SelectModifier::SqlSmallResult]);
+ mysql().one_statement_parses_to(
+ "SELECT SQL_SMALL_RESULT DISTINCTROW id FROM t",
+ "SELECT DISTINCTROW SQL_SMALL_RESULT id FROM t",
+ );
+}
+
#[test]
fn parse_show_variables() {
mysql_and_generic().verified_stmt("SHOW VARIABLES");
@@ -3546,6 +3585,7 @@ fn parse_hex_string_introducer() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Prefixed {
diff --git a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_postgres.rs b/app/tests/sqlparser_postgres.rs
index 1f91bff..d3d36f8 100644
--- a/tmp/agent-patch-flux-pr-2172.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_postgres.rs
+++ b/app/tests/sqlparser_postgres.rs
@@ -1293,6 +1293,7 @@ fn parse_copy_to() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![
@@ -3074,6 +3075,7 @@ fn parse_array_subquery_expr() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Value(
@@ -3101,6 +3103,7 @@ fn parse_array_subquery_expr() {
select_token: AttachedToken::empty(),
optimizer_hint: None,
distinct: None,
+ modifiers: vec![],
top: None,
top_before_distinct: false,
projection: vec![SelectItem::UnnamedExpr(Expr::Value(