agent_patch
runs/2026-02-21__03-36-16__gpt-5-1-codex-mini/flux-pr-1501/flux-pr-1501.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/agent-logs/agent.patch
33827 bytes
diff --git a/tmp/agent-patch-flux-pr-1501.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 81bddcd..db086c7 100644
--- a/tmp/agent-patch-flux-pr-1501.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
@@ -2778,36 +2778,30 @@ pub enum Statement {
ShowColumns {
extended: bool,
full: bool,
- #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
- table_name: ObjectName,
- filter: Option<ShowStatementFilter>,
+ options: ShowStatementOptions,
},
/// ```sql
/// SHOW DATABASES [LIKE 'pattern']
/// ```
- ShowDatabases { filter: Option<ShowStatementFilter> },
+ ShowDatabases { options: ShowStatementOptions },
/// ```sql
/// SHOW SCHEMAS [LIKE 'pattern']
/// ```
- ShowSchemas { filter: Option<ShowStatementFilter> },
+ ShowSchemas { options: ShowStatementOptions },
/// ```sql
/// SHOW TABLES
/// ```
ShowTables {
extended: bool,
full: bool,
- clause: Option<ShowClause>,
- db_name: Option<Ident>,
- filter: Option<ShowStatementFilter>,
+ options: ShowStatementOptions,
},
/// ```sql
/// SHOW VIEWS
/// ```
ShowViews {
materialized: bool,
- clause: Option<ShowClause>,
- db_name: Option<Ident>,
- filter: Option<ShowStatementFilter>,
+ options: ShowStatementOptions,
},
/// ```sql
/// SHOW COLLATION
@@ -3319,6 +3313,44 @@ pub enum Statement {
},
}
+fn fmt_show_options(f: &mut fmt::Formatter<'_>, options: &ShowStatementOptions) -> fmt::Result {
+ if options.like_first {
+ if let Some(filter) = &options.filter {
+ write!(f, " {filter}")?;
+ }
+ if let Some(scope) = &options.scope {
+ write!(f, " {scope}")?;
+ }
+ } else {
+ if let Some(scope) = &options.scope {
+ write!(f, " {scope}")?;
+ }
+ if let Some(filter) = &options.filter {
+ write!(f, " {filter}")?;
+ }
+ }
+
+ if let Some(starts_with) = &options.starts_with {
+ write!(
+ f,
+ " STARTS WITH '{}'",
+ value::escape_single_quote_string(starts_with)
+ )?;
+ }
+
+ if let Some(limit) = &options.limit {
+ write!(f, " {limit}")?;
+ }
+
+ if let Some(privileges) = &options.with_privileges {
+ if !privileges.is_empty() {
+ write!(f, " WITH PRIVILEGES {}", display_comma_separated(privileges))?;
+ }
+ }
+
+ Ok(())
+}
+
impl fmt::Display for Statement {
// Clippy thinks this function is too complicated, but it is painful to
// split up without extracting structs for each `Statement` variant.
@@ -4384,82 +4416,77 @@ impl fmt::Display for Statement {
write!(f, "SHOW CREATE {obj_type} {obj_name}",)?;
Ok(())
}
- Statement::ShowColumns {
- extended,
- full,
- table_name,
- filter,
- } => {
+ Statement::ShowColumns { extended, full, options } => {
write!(
f,
- "SHOW {extended}{full}COLUMNS FROM {table_name}",
+ "SHOW {extended}{full}COLUMNS",
extended = if *extended { "EXTENDED " } else { "" },
full = if *full { "FULL " } else { "" },
- table_name = table_name,
)?;
- if let Some(filter) = filter {
- write!(f, " {filter}")?;
- }
+ fmt_show_options(f, options)?;
Ok(())
}
- Statement::ShowDatabases { filter } => {
- write!(f, "SHOW DATABASES")?;
- if let Some(filter) = filter {
- write!(f, " {filter}")?;
+ Statement::ShowDatabases { options } => {
+ write!(f, "SHOW")?;
+ if options.modifiers.terse {
+ write!(f, " TERSE")?;
}
+ write!(f, " DATABASES")?;
+ if options.modifiers.history {
+ write!(f, " HISTORY")?;
+ }
+ fmt_show_options(f, options)?;
Ok(())
}
- Statement::ShowSchemas { filter } => {
- write!(f, "SHOW SCHEMAS")?;
- if let Some(filter) = filter {
- write!(f, " {filter}")?;
+ Statement::ShowSchemas { options } => {
+ write!(f, "SHOW")?;
+ if options.modifiers.terse {
+ write!(f, " TERSE")?;
}
+ write!(f, " SCHEMAS")?;
+ if options.modifiers.history {
+ write!(f, " HISTORY")?;
+ }
+ fmt_show_options(f, options)?;
Ok(())
}
Statement::ShowTables {
extended,
full,
- clause: show_clause,
- db_name,
- filter,
+ options,
} => {
+ write!(f, "SHOW")?;
+ if options.modifiers.terse {
+ write!(f, " TERSE")?;
+ }
+ if options.modifiers.external {
+ write!(f, " EXTERNAL")?;
+ }
write!(
f,
- "SHOW {extended}{full}TABLES",
+ " {extended}{full}TABLES",
extended = if *extended { "EXTENDED " } else { "" },
full = if *full { "FULL " } else { "" },
)?;
- if let Some(show_clause) = show_clause {
- write!(f, " {show_clause}")?;
- }
- if let Some(db_name) = db_name {
- write!(f, " {db_name}")?;
- }
- if let Some(filter) = filter {
- write!(f, " {filter}")?;
+ if options.modifiers.history {
+ write!(f, " HISTORY")?;
}
+ fmt_show_options(f, options)?;
Ok(())
}
Statement::ShowViews {
materialized,
- clause: show_clause,
- db_name,
- filter,
+ options,
} => {
- write!(
- f,
- "SHOW {}VIEWS",
- if *materialized { "MATERIALIZED " } else { "" }
- )?;
- if let Some(show_clause) = show_clause {
- write!(f, " {show_clause}")?;
- }
- if let Some(db_name) = db_name {
- write!(f, " {db_name}")?;
+ write!(f, "SHOW")?;
+ if options.modifiers.terse {
+ write!(f, " TERSE")?;
}
- if let Some(filter) = filter {
- write!(f, " {filter}")?;
+ if *materialized {
+ write!(f, " MATERIALIZED")?;
}
+ write!(f, " VIEWS")?;
+ fmt_show_options(f, options)?;
Ok(())
}
Statement::ShowFunctions { filter } => {
@@ -6172,18 +6199,139 @@ impl fmt::Display for ShowStatementFilter {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
-pub enum ShowClause {
- IN,
- FROM,
+pub struct ShowStatementOptions {
+ pub scope: Option<ShowScope>,
+ pub filter: Option<ShowStatementFilter>,
+ pub starts_with: Option<String>,
+ pub limit: Option<ShowLimit>,
+ pub with_privileges: Option<Vec<Ident>>,
+ pub modifiers: ShowStatementModifiers,
+ pub like_first: bool,
}
-impl fmt::Display for ShowClause {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use ShowClause::*;
+impl Default for ShowStatementOptions {
+ fn default() -> Self {
+ ShowStatementOptions {
+ scope: None,
+ filter: None,
+ starts_with: None,
+ limit: None,
+ with_privileges: None,
+ modifiers: ShowStatementModifiers::default(),
+ like_first: false,
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ShowStatementModifiers {
+ pub terse: bool,
+ pub history: bool,
+ pub external: bool,
+}
+
+impl Default for ShowStatementModifiers {
+ fn default() -> Self {
+ Self {
+ terse: false,
+ history: false,
+ external: false,
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ShowScope {
+ pub segments: Vec<ShowScopeSegment>,
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ShowScopeSegment {
+ pub keywords: Vec<ShowScopeKeyword>,
+ pub object_name: Option<ObjectName>,
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum ShowScopeKeyword {
+ From,
+ In,
+ Account,
+ Database,
+ Schema,
+ Table,
+ View,
+ Application,
+ ApplicationPackage,
+}
+
+impl fmt::Display for ShowScopeKeyword {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use ShowScopeKeyword::*;
+
match self {
- FROM => write!(f, "FROM"),
- IN => write!(f, "IN"),
+ From => write!(f, "FROM"),
+ In => write!(f, "IN"),
+ Account => write!(f, "ACCOUNT"),
+ Database => write!(f, "DATABASE"),
+ Schema => write!(f, "SCHEMA"),
+ Table => write!(f, "TABLE"),
+ View => write!(f, "VIEW"),
+ Application => write!(f, "APPLICATION"),
+ ApplicationPackage => write!(f, "APPLICATION PACKAGE"),
+ }
+ }
+}
+
+impl fmt::Display for ShowScopeSegment {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let Some(first) = self.keywords.first() {
+ write!(f, "{first}")?;
+ for keyword in self.keywords.iter().skip(1) {
+ write!(f, " {keyword}")?;
+ }
+ }
+ if let Some(name) = &self.object_name {
+ write!(f, " {name}")?;
+ }
+ Ok(())
+ }
+}
+
+impl fmt::Display for ShowScope {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for (idx, segment) in self.segments.iter().enumerate() {
+ if idx > 0 {
+ f.write_char(' ')?;
+ }
+ write!(f, "{segment}")?;
}
+ Ok(())
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ShowLimit {
+ pub count: u64,
+ pub from: Option<String>,
+}
+
+impl fmt::Display for ShowLimit {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "LIMIT {}", self.count)?;
+ if let Some(from) = &self.from {
+ write!(f, " FROM '{}'", value::escape_single_quote_string(from))?;
+ }
+ Ok(())
}
}
diff --git a/tmp/agent-patch-flux-pr-1501.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 d3f4320..bc159c4 100644
--- a/tmp/agent-patch-flux-pr-1501.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
@@ -9615,64 +9615,71 @@ impl<'a> Parser<'a> {
let full = self.parse_keyword(Keyword::FULL);
let session = self.parse_keyword(Keyword::SESSION);
let global = self.parse_keyword(Keyword::GLOBAL);
- if self
- .parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS])
- .is_some()
- {
- Ok(self.parse_show_columns(extended, full)?)
- } else if self.parse_keyword(Keyword::TABLES) {
- Ok(self.parse_show_tables(extended, full)?)
- } else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
- Ok(self.parse_show_views(true)?)
- } else if self.parse_keyword(Keyword::VIEWS) {
- Ok(self.parse_show_views(false)?)
- } else if self.parse_keyword(Keyword::FUNCTIONS) {
- Ok(self.parse_show_functions()?)
- } else if extended || full {
- Err(ParserError::ParserError(
+
+ match self.peek_show_keyword() {
+ Keyword::COLUMNS | Keyword::FIELDS => return self.parse_show_columns(extended, full),
+ Keyword::TABLES => return self.parse_show_tables(extended, full),
+ Keyword::VIEWS => return self.parse_show_views(),
+ _ => {}
+ }
+
+ if extended || full {
+ return Err(ParserError::ParserError(
"EXTENDED/FULL are not supported with this type of SHOW query".to_string(),
- ))
+ ));
+ }
+
+ if self.parse_keyword(Keyword::FUNCTIONS) {
+ return self.parse_show_functions();
} else if self.parse_one_of_keywords(&[Keyword::CREATE]).is_some() {
- Ok(self.parse_show_create()?)
+ return self.parse_show_create();
} else if self.parse_keyword(Keyword::COLLATION) {
- Ok(self.parse_show_collation()?)
+ return self.parse_show_collation();
} else if self.parse_keyword(Keyword::VARIABLES)
&& dialect_of!(self is MySqlDialect | GenericDialect)
{
- Ok(Statement::ShowVariables {
+ return Ok(Statement::ShowVariables {
filter: self.parse_show_statement_filter()?,
session,
global,
- })
+ });
} else if self.parse_keyword(Keyword::STATUS)
&& dialect_of!(self is MySqlDialect | GenericDialect)
{
- Ok(Statement::ShowStatus {
+ return Ok(Statement::ShowStatus {
filter: self.parse_show_statement_filter()?,
session,
global,
- })
+ });
} else if self.parse_keyword(Keyword::DATABASES) {
- self.parse_show_databases()
+ return self.parse_show_databases();
} else if self.parse_keyword(Keyword::SCHEMAS) {
- self.parse_show_schemas()
- } else {
- Ok(Statement::ShowVariable {
- variable: self.parse_identifiers()?,
- })
+ return self.parse_show_schemas();
}
+
+ Ok(Statement::ShowVariable {
+ variable: self.parse_identifiers()?,
+ })
}
fn parse_show_databases(&mut self) -> Result<Statement, ParserError> {
- Ok(Statement::ShowDatabases {
- filter: self.parse_show_statement_filter()?,
- })
+ let terse = self.parse_keyword(Keyword::TERSE);
+ self.expect_keyword(Keyword::DATABASES)?;
+ let history = self.parse_keyword(Keyword::HISTORY);
+ let mut options = self.parse_show_statement_options()?;
+ options.modifiers.terse = terse;
+ options.modifiers.history = history;
+ Ok(Statement::ShowDatabases { options })
}
fn parse_show_schemas(&mut self) -> Result<Statement, ParserError> {
- Ok(Statement::ShowSchemas {
- filter: self.parse_show_statement_filter()?,
- })
+ let terse = self.parse_keyword(Keyword::TERSE);
+ self.expect_keyword(Keyword::SCHEMAS)?;
+ let history = self.parse_keyword(Keyword::HISTORY);
+ let mut options = self.parse_show_statement_options()?;
+ options.modifiers.terse = terse;
+ options.modifiers.history = history;
+ Ok(Statement::ShowSchemas { options })
}
pub fn parse_show_create(&mut self) -> Result<Statement, ParserError> {
@@ -9705,23 +9712,11 @@ impl<'a> Parser<'a> {
extended: bool,
full: bool,
) -> Result<Statement, ParserError> {
- self.expect_one_of_keywords(&[Keyword::FROM, Keyword::IN])?;
- let object_name = self.parse_object_name(false)?;
- let table_name = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
- Some(_) => {
- let db_name = vec![self.parse_identifier(false)?];
- let ObjectName(table_name) = object_name;
- let object_name = db_name.into_iter().chain(table_name).collect();
- ObjectName(object_name)
- }
- None => object_name,
- };
- let filter = self.parse_show_statement_filter()?;
+ let options = self.parse_show_statement_options()?;
Ok(Statement::ShowColumns {
extended,
full,
- table_name,
- filter,
+ options,
})
}
@@ -9730,33 +9725,30 @@ impl<'a> Parser<'a> {
extended: bool,
full: bool,
) -> Result<Statement, ParserError> {
- let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
- Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
- Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
- _ => (None, None),
- };
- let filter = self.parse_show_statement_filter()?;
+ let terse = self.parse_keyword(Keyword::TERSE);
+ let external = self.parse_keyword(Keyword::EXTERNAL);
+ self.expect_keyword(Keyword::TABLES)?;
+ let history = self.parse_keyword(Keyword::HISTORY);
+ let mut options = self.parse_show_statement_options()?;
+ options.modifiers.terse = terse;
+ options.modifiers.external = external;
+ options.modifiers.history = history;
Ok(Statement::ShowTables {
extended,
full,
- clause,
- db_name,
- filter,
+ options,
})
}
- fn parse_show_views(&mut self, materialized: bool) -> Result<Statement, ParserError> {
- let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
- Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
- Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
- _ => (None, None),
- };
- let filter = self.parse_show_statement_filter()?;
+ fn parse_show_views(&mut self) -> Result<Statement, ParserError> {
+ let terse = self.parse_keyword(Keyword::TERSE);
+ let materialized = self.parse_keyword(Keyword::MATERIALIZED);
+ self.expect_keyword(Keyword::VIEWS)?;
+ let mut options = self.parse_show_statement_options()?;
+ options.modifiers.terse = terse;
Ok(Statement::ShowViews {
materialized,
- clause,
- db_name,
- filter,
+ options,
})
}
@@ -9793,6 +9785,135 @@ impl<'a> Parser<'a> {
}
}
+ fn parse_show_statement_options(&mut self) -> Result<ShowStatementOptions, ParserError> {
+ let like_first = self.dialect.show_like_before_in();
+ let (filter, scope) = self.parse_show_filter_and_scope(like_first)?;
+ let starts_with = self.parse_show_starts_with()?;
+ let limit = self.parse_show_limit()?;
+ let with_privileges = self.parse_show_privileges()?;
+ Ok(ShowStatementOptions {
+ scope,
+ filter,
+ starts_with,
+ limit,
+ with_privileges,
+ modifiers: ShowStatementModifiers::default(),
+ like_first,
+ })
+ }
+
+ fn parse_show_filter_and_scope(
+ &mut self,
+ like_first: bool,
+ ) -> Result<(Option<ShowStatementFilter>, Option<ShowScope>), ParserError> {
+ if like_first {
+ let filter = self.parse_show_statement_filter()?;
+ let scope = self.parse_show_scope()?;
+ Ok((filter, scope))
+ } else {
+ let scope = self.parse_show_scope()?;
+ let filter = self.parse_show_statement_filter()?;
+ Ok((filter, scope))
+ }
+ }
+
+ fn parse_show_scope(&mut self) -> Result<Option<ShowScope>, ParserError> {
+ let mut segments = Vec::new();
+ loop {
+ let primary_keyword = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
+ Some(Keyword::FROM) => ShowScopeKeyword::From,
+ Some(Keyword::IN) => ShowScopeKeyword::In,
+ _ => break,
+ };
+ let mut keywords = vec![primary_keyword];
+ loop {
+ if self.parse_keyword(Keyword::ACCOUNT) {
+ keywords.push(ShowScopeKeyword::Account);
+ } else if self.parse_keyword(Keyword::DATABASE) {
+ keywords.push(ShowScopeKeyword::Database);
+ } else if self.parse_keyword(Keyword::SCHEMA) {
+ keywords.push(ShowScopeKeyword::Schema);
+ } else if self.parse_keyword(Keyword::TABLE) {
+ keywords.push(ShowScopeKeyword::Table);
+ } else if self.parse_keyword(Keyword::VIEW) {
+ keywords.push(ShowScopeKeyword::View);
+ } else if self.parse_keyword(Keyword::APPLICATION) {
+ if self.parse_keyword(Keyword::PACKAGE) {
+ keywords.push(ShowScopeKeyword::ApplicationPackage);
+ } else {
+ keywords.push(ShowScopeKeyword::Application);
+ }
+ } else {
+ break;
+ }
+ }
+ let object_name = self.maybe_parse(|parser| parser.parse_object_name(false))?;
+ segments.push(ShowScopeSegment {
+ keywords,
+ object_name,
+ });
+ }
+ if segments.is_empty() {
+ Ok(None)
+ } else {
+ Ok(Some(ShowScope { segments }))
+ }
+ }
+
+ fn parse_show_starts_with(&mut self) -> Result<Option<String>, ParserError> {
+ if self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) {
+ Ok(Some(self.parse_literal_string()?))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn parse_show_limit(&mut self) -> Result<Option<ShowLimit>, ParserError> {
+ if self.parse_keyword(Keyword::LIMIT) {
+ let count = self.parse_literal_uint()?;
+ let from = if self.parse_keyword(Keyword::FROM) {
+ Some(self.parse_literal_string()?)
+ } else {
+ None
+ };
+ Ok(Some(ShowLimit { count, from }))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn parse_show_privileges(&mut self) -> Result<Option<Vec<Ident>>, ParserError> {
+ if self.parse_keywords(&[Keyword::WITH, Keyword::PRIVILEGES]) {
+ let mut privileges = Vec::new();
+ loop {
+ privileges.push(self.parse_identifier(false)?);
+ if !self.consume_token(&Token::Comma) {
+ break;
+ }
+ }
+ Ok(Some(privileges))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn peek_show_keyword(&self) -> Keyword {
+ let mut offset = 0;
+ loop {
+ let token = self.peek_nth_token(offset).token;
+ match token {
+ Token::Word(word) => match word.keyword {
+ Keyword::TERSE | Keyword::EXTERNAL | Keyword::MATERIALIZED => {
+ offset += 1;
+ continue;
+ }
+ kw => return kw,
+ },
+ _ => return Keyword::NoKeyword,
+ }
+ }
+ }
+
pub fn parse_use(&mut self) -> Result<Statement, ParserError> {
// Determine which keywords are recognized by the current dialect
let parsed_keyword = if dialect_of!(self is HiveDialect) {
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_mysql.rs b/app/tests/sqlparser_mysql.rs
index 44b2ac6..0404047 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_mysql.rs
+++ b/app/tests/sqlparser_mysql.rs
@@ -31,6 +31,34 @@ use test_utils::*;
#[macro_use]
mod test_utils;
+fn show_options(
+ scope: Option<ShowScope>,
+ filter: Option<ShowStatementFilter>,
+) -> ShowStatementOptions {
+ ShowStatementOptions {
+ scope,
+ filter,
+ ..Default::default()
+ }
+}
+
+fn scope_from(name: ObjectName) -> ShowScope {
+ ShowScope {
+ segments: vec![ShowScopeSegment {
+ keywords: vec![ShowScopeKeyword::From],
+ object_name: Some(name),
+ }],
+ }
+}
+
+fn scope_in(name: ObjectName) -> ShowScope {
+ ShowScope {
+ segments: vec![ShowScopeSegment {
+ keywords: vec![ShowScopeKeyword::In],
+ object_name: Some(name),
+ }],
+ }
+}
#[test]
fn parse_identifiers() {
mysql().verified_stmt("SELECT $a$, àà");
@@ -229,8 +257,7 @@ fn parse_show_columns() {
Statement::ShowColumns {
extended: false,
full: false,
- table_name: table_name.clone(),
- filter: None,
+ options: show_options(Some(scope_from(table_name.clone())), None),
}
);
assert_eq!(
@@ -238,8 +265,13 @@ fn parse_show_columns() {
Statement::ShowColumns {
extended: false,
full: false,
- table_name: ObjectName(vec![Ident::new("mydb"), Ident::new("mytable")]),
- filter: None,
+ options: show_options(
+ Some(scope_from(ObjectName(vec![
+ Ident::new("mydb"),
+ Ident::new("mytable"),
+ ]))),
+ None
+ ),
}
);
assert_eq!(
@@ -247,8 +279,7 @@ fn parse_show_columns() {
Statement::ShowColumns {
extended: true,
full: false,
- table_name: table_name.clone(),
- filter: None,
+ options: show_options(Some(scope_from(table_name.clone())), None),
}
);
assert_eq!(
@@ -256,8 +287,7 @@ fn parse_show_columns() {
Statement::ShowColumns {
extended: false,
full: true,
- table_name: table_name.clone(),
- filter: None,
+ options: show_options(Some(scope_from(table_name.clone())), None),
}
);
assert_eq!(
@@ -265,8 +295,10 @@ fn parse_show_columns() {
Statement::ShowColumns {
extended: false,
full: false,
- table_name: table_name.clone(),
- filter: Some(ShowStatementFilter::Like("pattern".into())),
+ options: show_options(
+ Some(scope_from(table_name.clone())),
+ Some(ShowStatementFilter::Like("pattern".into()))
+ ),
}
);
assert_eq!(
@@ -274,10 +306,12 @@ fn parse_show_columns() {
Statement::ShowColumns {
extended: false,
full: false,
- table_name,
- filter: Some(ShowStatementFilter::Where(
- mysql_and_generic().verified_expr("1 = 2")
- )),
+ options: show_options(
+ Some(scope_from(table_name.clone())),
+ Some(ShowStatementFilter::Where(
+ mysql_and_generic().verified_expr("1 = 2")
+ ))
+ ),
}
);
mysql_and_generic()
@@ -329,9 +363,7 @@ fn parse_show_tables() {
Statement::ShowTables {
extended: false,
full: false,
- clause: None,
- db_name: None,
- filter: None,
+ options: ShowStatementOptions::default(),
}
);
assert_eq!(
@@ -339,9 +371,10 @@ fn parse_show_tables() {
Statement::ShowTables {
extended: false,
full: false,
- clause: Some(ShowClause::FROM),
- db_name: Some(Ident::new("mydb")),
- filter: None,
+ options: show_options(
+ Some(scope_from(ObjectName(vec![Ident::new("mydb")]))),
+ None
+ ),
}
);
assert_eq!(
@@ -349,9 +382,7 @@ fn parse_show_tables() {
Statement::ShowTables {
extended: true,
full: false,
- clause: None,
- db_name: None,
- filter: None,
+ options: ShowStatementOptions::default(),
}
);
assert_eq!(
@@ -359,9 +390,7 @@ fn parse_show_tables() {
Statement::ShowTables {
extended: false,
full: true,
- clause: None,
- db_name: None,
- filter: None,
+ options: ShowStatementOptions::default(),
}
);
assert_eq!(
@@ -369,9 +398,7 @@ fn parse_show_tables() {
Statement::ShowTables {
extended: false,
full: false,
- clause: None,
- db_name: None,
- filter: Some(ShowStatementFilter::Like("pattern".into())),
+ options: show_options(None, Some(ShowStatementFilter::Like("pattern".into()))),
}
);
assert_eq!(
@@ -379,11 +406,12 @@ fn parse_show_tables() {
Statement::ShowTables {
extended: false,
full: false,
- clause: None,
- db_name: None,
- filter: Some(ShowStatementFilter::Where(
- mysql_and_generic().verified_expr("1 = 2")
- )),
+ options: show_options(
+ None,
+ Some(ShowStatementFilter::Where(
+ mysql_and_generic().verified_expr("1 = 2")
+ ))
+ ),
}
);
mysql_and_generic().verified_stmt("SHOW TABLES IN mydb");
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_snowflake.rs b/app/tests/sqlparser_snowflake.rs
index c17c7b9..fbf9c6f 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-03-05__17-48-34__gpt-5-1-codex-mini/app/tests/sqlparser_snowflake.rs
+++ b/app/tests/sqlparser_snowflake.rs
@@ -1247,6 +1247,74 @@ fn test_array_agg_func() {
}
}
+#[test]
+fn parse_snowflake_show_tables_like_in_database() {
+ let stmt = snowflake()
+ .verified_stmt("SHOW TABLES LIKE 'foo' IN DATABASE mydb");
+ assert_eq!(
+ stmt,
+ Statement::ShowTables {
+ extended: false,
+ full: false,
+ options: ShowStatementOptions {
+ scope: Some(ShowScope {
+ segments: vec![ShowScopeSegment {
+ keywords: vec![
+ ShowScopeKeyword::In,
+ ShowScopeKeyword::Database
+ ],
+ object_name: Some(ObjectName(vec![Ident::new("mydb")])),
+ }],
+ }),
+ filter: Some(ShowStatementFilter::Like("foo".into())),
+ like_first: true,
+ ..Default::default()
+ },
+ }
+ );
+}
+
+#[test]
+fn parse_snowflake_show_databases_with_privileges() {
+ let stmt = snowflake().verified_stmt("SHOW DATABASES WITH PRIVILEGES USAGE, CREATE");
+ assert_eq!(
+ stmt,
+ Statement::ShowDatabases {
+ options: ShowStatementOptions {
+ with_privileges: Some(vec![Ident::new("USAGE"), Ident::new("CREATE")]),
+ like_first: true,
+ ..Default::default()
+ },
+ }
+ );
+}
+
+#[test]
+fn parse_snowflake_show_columns_in_table() {
+ let stmt = snowflake().verified_stmt("SHOW COLUMNS LIKE 'baz' IN TABLE mytable");
+ assert_eq!(
+ stmt,
+ Statement::ShowColumns {
+ extended: false,
+ full: false,
+ options: ShowStatementOptions {
+ scope: Some(ShowScope {
+ segments: vec![ShowScopeSegment {
+ keywords: vec![
+ ShowScopeKeyword::In,
+ ShowScopeKeyword::Table
+ ],
+ object_name: Some(ObjectName(vec![Ident::new("mytable")])),
+ }],
+ }),
+ filter: Some(ShowStatementFilter::Like("baz".into())),
+ like_first: true,
+ ..Default::default()
+ },
+ }
+ );
+}
+
fn snowflake() -> TestedDialects {
TestedDialects::new(vec![Box::new(SnowflakeDialect {})])
}