STET

agent_patch

runs/2026-02-28__18-27-22__gpt-5-4/flux-pr-1501/flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/agent-logs/agent.patch

38606 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/mod.rs b/app/src/ast/mod.rs
index 81bddcd..cf7ec8b 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/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>,
+        show_options: ShowStatementOptions,
     },
     /// ```sql
     /// SHOW DATABASES [LIKE 'pattern']
     /// ```
-    ShowDatabases { filter: Option<ShowStatementFilter> },
+    ShowDatabases { show_options: ShowStatementOptions },
     /// ```sql
     /// SHOW SCHEMAS [LIKE 'pattern']
     /// ```
-    ShowSchemas { filter: Option<ShowStatementFilter> },
+    ShowSchemas { show_options: ShowStatementOptions },
     /// ```sql
     /// SHOW TABLES
     /// ```
     ShowTables {
         extended: bool,
         full: bool,
-        clause: Option<ShowClause>,
-        db_name: Option<Ident>,
-        filter: Option<ShowStatementFilter>,
+        show_options: ShowStatementOptions,
     },
     /// ```sql
     /// SHOW VIEWS
     /// ```
     ShowViews {
         materialized: bool,
-        clause: Option<ShowClause>,
-        db_name: Option<Ident>,
-        filter: Option<ShowStatementFilter>,
+        show_options: ShowStatementOptions,
     },
     /// ```sql
     /// SHOW COLLATION
@@ -4387,78 +4381,77 @@ impl fmt::Display for Statement {
             Statement::ShowColumns {
                 extended,
                 full,
-                table_name,
-                filter,
+                show_options,
             } => {
                 write!(
                     f,
-                    "SHOW {extended}{full}COLUMNS FROM {table_name}",
+                    "SHOW {extended}{full}{terse}COLUMNS{history}",
                     extended = if *extended { "EXTENDED " } else { "" },
                     full = if *full { "FULL " } else { "" },
-                    table_name = table_name,
+                    terse = if show_options.terse { "TERSE " } else { "" },
+                    history = if show_options.history { " HISTORY" } else { "" },
                 )?;
-                if let Some(filter) = filter {
-                    write!(f, " {filter}")?;
+                if !show_options.is_empty_postfix() {
+                    write!(f, " {show_options}")?;
                 }
                 Ok(())
             }
-            Statement::ShowDatabases { filter } => {
-                write!(f, "SHOW DATABASES")?;
-                if let Some(filter) = filter {
-                    write!(f, " {filter}")?;
+            Statement::ShowDatabases { show_options } => {
+                write!(
+                    f,
+                    "SHOW {terse}DATABASES{history}",
+                    terse = if show_options.terse { "TERSE " } else { "" },
+                    history = if show_options.history { " HISTORY" } else { "" },
+                )?;
+                if !show_options.is_empty_postfix() {
+                    write!(f, " {show_options}")?;
                 }
                 Ok(())
             }
-            Statement::ShowSchemas { filter } => {
-                write!(f, "SHOW SCHEMAS")?;
-                if let Some(filter) = filter {
-                    write!(f, " {filter}")?;
+            Statement::ShowSchemas { show_options } => {
+                write!(
+                    f,
+                    "SHOW {terse}SCHEMAS{history}",
+                    terse = if show_options.terse { "TERSE " } else { "" },
+                    history = if show_options.history { " HISTORY" } else { "" },
+                )?;
+                if !show_options.is_empty_postfix() {
+                    write!(f, " {show_options}")?;
                 }
                 Ok(())
             }
             Statement::ShowTables {
                 extended,
                 full,
-                clause: show_clause,
-                db_name,
-                filter,
+                show_options,
             } => {
                 write!(
                     f,
-                    "SHOW {extended}{full}TABLES",
+                    "SHOW {extended}{full}{terse}{external}TABLES{history}",
                     extended = if *extended { "EXTENDED " } else { "" },
                     full = if *full { "FULL " } else { "" },
+                    terse = if show_options.terse { "TERSE " } else { "" },
+                    external = if show_options.external { "EXTERNAL " } else { "" },
+                    history = if show_options.history { " HISTORY" } 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 !show_options.is_empty_postfix() {
+                    write!(f, " {show_options}")?;
                 }
                 Ok(())
             }
             Statement::ShowViews {
                 materialized,
-                clause: show_clause,
-                db_name,
-                filter,
+                show_options,
             } => {
                 write!(
                     f,
-                    "SHOW {}VIEWS",
-                    if *materialized { "MATERIALIZED " } else { "" }
+                    "SHOW {terse}{}{history}",
+                    if *materialized { "MATERIALIZED VIEWS" } else { "VIEWS" },
+                    terse = if show_options.terse { "TERSE " } else { "" },
+                    history = if show_options.history { " HISTORY" } 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 !show_options.is_empty_postfix() {
+                    write!(f, " {show_options}")?;
                 }
                 Ok(())
             }
@@ -6169,17 +6162,92 @@ impl fmt::Display for ShowStatementFilter {
     }
 }
 
+#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ShowStatementOptions {
+    pub show_in: Option<ShowStatementIn>,
+    pub filter: Option<ShowStatementFilter>,
+    pub filter_position: Option<ShowStatementFilterPosition>,
+    pub starts_with: Option<String>,
+    pub limit: Option<ShowStatementLimit>,
+    pub terse: bool,
+    pub history: bool,
+    pub external: bool,
+}
+
+impl ShowStatementOptions {
+    pub fn is_empty_postfix(&self) -> bool {
+        self.show_in.is_none()
+            && self.filter.is_none()
+            && self.starts_with.is_none()
+            && self.limit.is_none()
+    }
+}
+
+impl fmt::Display for ShowStatementOptions {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let filter_first =
+            matches!(self.filter_position, Some(ShowStatementFilterPosition::BeforeIn));
+
+        if filter_first {
+            if let Some(filter) = &self.filter {
+                write!(f, "{filter}")?;
+                if self.show_in.is_some() || self.starts_with.is_some() || self.limit.is_some() {
+                    write!(f, " ")?;
+                }
+            }
+            if let Some(show_in) = &self.show_in {
+                write!(f, "{show_in}")?;
+                if self.starts_with.is_some() || self.limit.is_some() {
+                    write!(f, " ")?;
+                }
+            }
+        } else {
+            if let Some(show_in) = &self.show_in {
+                write!(f, "{show_in}")?;
+                if self.filter.is_some() || self.starts_with.is_some() || self.limit.is_some() {
+                    write!(f, " ")?;
+                }
+            }
+            if let Some(filter) = &self.filter {
+                write!(f, "{filter}")?;
+                if self.starts_with.is_some() || self.limit.is_some() {
+                    write!(f, " ")?;
+                }
+            }
+        }
+
+        if let Some(starts_with) = &self.starts_with {
+            write!(
+                f,
+                "STARTS WITH '{}'",
+                value::escape_single_quote_string(starts_with)
+            )?;
+            if self.limit.is_some() {
+                write!(f, " ")?;
+            }
+        }
+
+        if let Some(limit) = &self.limit {
+            write!(f, "{limit}")?;
+        }
+
+        Ok(())
+    }
+}
+
 #[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 {
+pub enum ShowStatementInClause {
     IN,
     FROM,
 }
 
-impl fmt::Display for ShowClause {
+impl fmt::Display for ShowStatementInClause {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use ShowClause::*;
+        use ShowStatementInClause::*;
         match self {
             FROM => write!(f, "FROM"),
             IN => write!(f, "IN"),
@@ -6187,6 +6255,83 @@ impl fmt::Display for ShowClause {
     }
 }
 
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ShowStatementIn {
+    pub clause: ShowStatementInClause,
+    pub scope: ShowStatementInScope,
+}
+
+impl fmt::Display for ShowStatementIn {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{} {}", self.clause, self.scope)
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum ShowStatementInScope {
+    Account,
+    Database(Option<ObjectName>),
+    Schema(Option<ObjectName>),
+    Table(Option<ObjectName>),
+    View(Option<ObjectName>),
+    Application(ObjectName),
+    ApplicationPackage(ObjectName),
+    Object(ObjectName),
+}
+
+impl fmt::Display for ShowStatementInScope {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::Account => write!(f, "ACCOUNT"),
+            Self::Database(None) => write!(f, "DATABASE"),
+            Self::Database(Some(name)) => write!(f, "DATABASE {name}"),
+            Self::Schema(None) => write!(f, "SCHEMA"),
+            Self::Schema(Some(name)) => write!(f, "SCHEMA {name}"),
+            Self::Table(None) => write!(f, "TABLE"),
+            Self::Table(Some(name)) => write!(f, "TABLE {name}"),
+            Self::View(None) => write!(f, "VIEW"),
+            Self::View(Some(name)) => write!(f, "VIEW {name}"),
+            Self::Application(name) => write!(f, "APPLICATION {name}"),
+            Self::ApplicationPackage(name) => write!(f, "APPLICATION PACKAGE {name}"),
+            Self::Object(name) => write!(f, "{name}"),
+        }
+    }
+}
+
+#[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 ShowStatementFilterPosition {
+    BeforeIn,
+    AfterIn,
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ShowStatementLimit {
+    pub rows: u64,
+    pub from: Option<String>,
+}
+
+impl fmt::Display for ShowStatementLimit {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "LIMIT {}", self.rows)?;
+        if let Some(from) = &self.from {
+            write!(
+                f,
+                " FROM '{}'",
+                value::escape_single_quote_string(from)
+            )?;
+        }
+        Ok(())
+    }
+}
+
 /// Sqlite specific syntax
 ///
 /// See [Sqlite documentation](https://sqlite.org/lang_conflict.html)
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/dialect/mod.rs b/app/src/dialect/mod.rs
index c8c11bc..8d8ab29 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/dialect/mod.rs
+++ b/app/src/dialect/mod.rs
@@ -49,7 +49,7 @@ pub use self::postgresql::PostgreSqlDialect;
 pub use self::redshift::RedshiftSqlDialect;
 pub use self::snowflake::SnowflakeDialect;
 pub use self::sqlite::SQLiteDialect;
-use crate::ast::{ColumnOption, Expr, Statement};
+use crate::ast::{ColumnOption, Expr, ShowStatementFilterPosition, Statement};
 pub use crate::keywords;
 use crate::keywords::Keyword;
 use crate::parser::{Parser, ParserError};
@@ -622,6 +622,12 @@ pub trait Dialect: Debug + Any {
     fn supports_boolean_literals(&self) -> bool {
         true
     }
+
+    /// Controls the canonical ordering of SHOW statement filters relative to
+    /// `IN`/`FROM` clauses when both are present.
+    fn show_statement_filter_position(&self) -> ShowStatementFilterPosition {
+        ShowStatementFilterPosition::AfterIn
+    }
 }
 
 /// This represents the operators for which precedence must be defined
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/dialect/snowflake.rs b/app/src/dialect/snowflake.rs
index d9331d9..8b4efec 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/dialect/snowflake.rs
+++ b/app/src/dialect/snowflake.rs
@@ -25,7 +25,8 @@ use crate::ast::helpers::stmt_data_loading::{
 use crate::ast::{
     ColumnOption, ColumnPolicy, ColumnPolicyProperty, Ident, IdentityParameters, IdentityProperty,
     IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, ObjectName,
-    RowAccessPolicy, Statement, TagsColumnOption, WrappedCollection,
+    RowAccessPolicy, ShowStatementFilterPosition, Statement, TagsColumnOption,
+    WrappedCollection,
 };
 use crate::dialect::{Dialect, Precedence};
 use crate::keywords::Keyword;
@@ -96,6 +97,10 @@ impl Dialect for SnowflakeDialect {
         true
     }
 
+    fn show_statement_filter_position(&self) -> ShowStatementFilterPosition {
+        ShowStatementFilterPosition::BeforeIn
+    }
+
     fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
         if parser.parse_keyword(Keyword::CREATE) {
             // possibly CREATE STAGE
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs b/app/src/parser/mod.rs
index d3f4320..9e5f98a 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -9613,24 +9613,31 @@ impl<'a> Parser<'a> {
     pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
         let extended = self.parse_keyword(Keyword::EXTENDED);
         let full = self.parse_keyword(Keyword::FULL);
+        let terse = self.parse_custom_keyword("TERSE");
+        let external = self.parse_keyword(Keyword::EXTERNAL);
         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)?)
+            Ok(self.parse_show_columns(extended, full, terse)?)
         } else if self.parse_keyword(Keyword::TABLES) {
-            Ok(self.parse_show_tables(extended, full)?)
+            Ok(self.parse_show_tables(extended, full, terse, external)?)
         } else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
-            Ok(self.parse_show_views(true)?)
+            Ok(self.parse_show_views(true, terse)?)
         } else if self.parse_keyword(Keyword::VIEWS) {
-            Ok(self.parse_show_views(false)?)
+            Ok(self.parse_show_views(false, terse)?)
         } else if self.parse_keyword(Keyword::FUNCTIONS) {
             Ok(self.parse_show_functions()?)
-        } else if extended || full {
+        } else if self.parse_keyword(Keyword::DATABASES) {
+            self.parse_show_databases(terse)
+        } else if self.parse_keyword(Keyword::SCHEMAS) {
+            self.parse_show_schemas(terse)
+        } else if extended || full || terse || external {
             Err(ParserError::ParserError(
-                "EXTENDED/FULL are not supported with this type of SHOW query".to_string(),
+                "EXTENDED/FULL/TERSE/EXTERNAL are not supported with this type of SHOW query"
+                    .to_string(),
             ))
         } else if self.parse_one_of_keywords(&[Keyword::CREATE]).is_some() {
             Ok(self.parse_show_create()?)
@@ -9652,10 +9659,6 @@ impl<'a> Parser<'a> {
                 session,
                 global,
             })
-        } else if self.parse_keyword(Keyword::DATABASES) {
-            self.parse_show_databases()
-        } else if self.parse_keyword(Keyword::SCHEMAS) {
-            self.parse_show_schemas()
         } else {
             Ok(Statement::ShowVariable {
                 variable: self.parse_identifiers()?,
@@ -9663,16 +9666,20 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_show_databases(&mut self) -> Result<Statement, ParserError> {
-        Ok(Statement::ShowDatabases {
-            filter: self.parse_show_statement_filter()?,
-        })
+    fn parse_show_databases(&mut self, terse: bool) -> Result<Statement, ParserError> {
+        let history = self.parse_keyword(Keyword::HISTORY);
+        let mut show_options = self.parse_show_statement_options(false, false)?;
+        show_options.terse = terse;
+        show_options.history = history;
+        Ok(Statement::ShowDatabases { show_options })
     }
 
-    fn parse_show_schemas(&mut self) -> Result<Statement, ParserError> {
-        Ok(Statement::ShowSchemas {
-            filter: self.parse_show_statement_filter()?,
-        })
+    fn parse_show_schemas(&mut self, terse: bool) -> Result<Statement, ParserError> {
+        let history = self.parse_keyword(Keyword::HISTORY);
+        let mut show_options = self.parse_show_statement_options(true, true)?;
+        show_options.terse = terse;
+        show_options.history = history;
+        Ok(Statement::ShowSchemas { show_options })
     }
 
     pub fn parse_show_create(&mut self) -> Result<Statement, ParserError> {
@@ -9704,24 +9711,52 @@ impl<'a> Parser<'a> {
         &mut self,
         extended: bool,
         full: bool,
+        terse: 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 mut show_options = ShowStatementOptions {
+            terse,
+            ..self.parse_show_statement_options(true, true)?
+        };
+
+        if let Some(ShowStatementIn {
+            clause,
+            scope: ShowStatementInScope::Object(object_name),
+        }) = &mut show_options.show_in
+        {
+            if !dialect_of!(self is SnowflakeDialect) {
+                *clause = ShowStatementInClause::FROM;
+            }
+            if matches!(clause, ShowStatementInClause::FROM | ShowStatementInClause::IN)
+                && self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]).is_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)
+                let ObjectName(table_name) = object_name.clone();
+                *object_name = ObjectName(db_name.into_iter().chain(table_name).collect());
             }
-            None => object_name,
-        };
-        let filter = self.parse_show_statement_filter()?;
+        }
+
+        if show_options.show_in.is_none() && !dialect_of!(self is SnowflakeDialect) {
+            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,
+            };
+            show_options.show_in = Some(ShowStatementIn {
+                clause: ShowStatementInClause::FROM,
+                scope: ShowStatementInScope::Object(table_name),
+            });
+        }
+
         Ok(Statement::ShowColumns {
             extended,
             full,
-            table_name,
-            filter,
+            show_options,
         })
     }
 
@@ -9729,34 +9764,29 @@ impl<'a> Parser<'a> {
         &mut self,
         extended: bool,
         full: bool,
+        terse: bool,
+        external: 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 history = self.parse_keyword(Keyword::HISTORY);
+        let mut show_options = self.parse_show_statement_options(true, true)?;
+        show_options.terse = terse;
+        show_options.external = external;
+        show_options.history = history;
         Ok(Statement::ShowTables {
             extended,
             full,
-            clause,
-            db_name,
-            filter,
+            show_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, materialized: bool, terse: bool) -> Result<Statement, ParserError> {
+        let history = self.parse_keyword(Keyword::HISTORY);
+        let mut show_options = self.parse_show_statement_options(true, true)?;
+        show_options.terse = terse;
+        show_options.history = history;
         Ok(Statement::ShowViews {
             materialized,
-            clause,
-            db_name,
-            filter,
+            show_options,
         })
     }
 
@@ -9793,6 +9823,109 @@ impl<'a> Parser<'a> {
         }
     }
 
+    fn parse_show_statement_options(
+        &mut self,
+        allow_scope: bool,
+        allow_object_scope: bool,
+    ) -> Result<ShowStatementOptions, ParserError> {
+        let mut show_options = ShowStatementOptions::default();
+        let filter_position = self.dialect.show_statement_filter_position();
+
+        show_options.filter = self.parse_show_statement_filter()?;
+
+        if allow_scope {
+            show_options.show_in = self.parse_show_statement_in(allow_object_scope)?;
+        }
+
+        if show_options.filter.is_none() {
+            show_options.filter = self.parse_show_statement_filter()?;
+        }
+
+        if show_options.filter.is_some() && show_options.show_in.is_some() {
+            show_options.filter_position = Some(filter_position);
+        }
+
+        show_options.starts_with = self.parse_show_starts_with()?;
+        show_options.limit = self.parse_show_limit()?;
+
+        Ok(show_options)
+    }
+
+    fn parse_show_statement_in(
+        &mut self,
+        allow_object_scope: bool,
+    ) -> Result<Option<ShowStatementIn>, ParserError> {
+        let clause = if self.parse_keyword(Keyword::FROM) {
+            Some(ShowStatementInClause::FROM)
+        } else if self.parse_keyword(Keyword::IN) {
+            Some(ShowStatementInClause::IN)
+        } else {
+            None
+        };
+
+        let Some(clause) = clause else {
+            return Ok(None);
+        };
+
+        let scope = if self.parse_custom_keyword("ACCOUNT") {
+            ShowStatementInScope::Account
+        } else if self.parse_keyword(Keyword::DATABASE) {
+            ShowStatementInScope::Database(self.maybe_parse(|p| p.parse_object_name(false))?)
+        } else if self.parse_keyword(Keyword::SCHEMA) {
+            ShowStatementInScope::Schema(self.maybe_parse(|p| p.parse_object_name(false))?)
+        } else if self.parse_keyword(Keyword::TABLE) {
+            ShowStatementInScope::Table(Some(self.parse_object_name(false)?))
+        } else if self.parse_keyword(Keyword::VIEW) {
+            ShowStatementInScope::View(Some(self.parse_object_name(false)?))
+        } else if self.parse_custom_keyword("APPLICATION") {
+            if self.parse_custom_keyword("PACKAGE") {
+                ShowStatementInScope::ApplicationPackage(self.parse_object_name(false)?)
+            } else {
+                ShowStatementInScope::Application(self.parse_object_name(false)?)
+            }
+        } else if allow_object_scope {
+            ShowStatementInScope::Object(self.parse_object_name(false)?)
+        } else {
+            return self.expected("SHOW scope", self.peek_token());
+        };
+
+        Ok(Some(ShowStatementIn { clause, scope }))
+    }
+
+    fn parse_show_starts_with(&mut self) -> Result<Option<String>, ParserError> {
+        if self.parse_custom_keyword("STARTS") {
+            self.expect_keyword(Keyword::WITH)?;
+            Ok(Some(self.parse_literal_string()?))
+        } else {
+            Ok(None)
+        }
+    }
+
+    fn parse_show_limit(&mut self) -> Result<Option<ShowStatementLimit>, ParserError> {
+        if self.parse_keyword(Keyword::LIMIT) {
+            Ok(Some(ShowStatementLimit {
+                rows: self.parse_literal_uint()?,
+                from: if self.parse_keyword(Keyword::FROM) {
+                    Some(self.parse_literal_string()?)
+                } else {
+                    None
+                },
+            }))
+        } else {
+            Ok(None)
+        }
+    }
+
+    fn parse_custom_keyword(&mut self, expected: &str) -> bool {
+        match self.peek_token().token {
+            Token::Word(w) if w.value.eq_ignore_ascii_case(expected) => {
+                self.next_token();
+                true
+            }
+            _ => false,
+        }
+    }
+
     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-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mysql.rs b/app/tests/sqlparser_mysql.rs
index 44b2ac6..b82bd86 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_mysql.rs
+++ b/app/tests/sqlparser_mysql.rs
@@ -229,8 +229,13 @@ fn parse_show_columns() {
         Statement::ShowColumns {
             extended: false,
             full: false,
-            table_name: table_name.clone(),
-            filter: None,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    scope: ShowStatementInScope::Object(table_name.clone()),
+                }),
+                ..Default::default()
+            },
         }
     );
     assert_eq!(
@@ -238,8 +243,16 @@ fn parse_show_columns() {
         Statement::ShowColumns {
             extended: false,
             full: false,
-            table_name: ObjectName(vec![Ident::new("mydb"), Ident::new("mytable")]),
-            filter: None,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    scope: ShowStatementInScope::Object(ObjectName(vec![
+                        Ident::new("mydb"),
+                        Ident::new("mytable"),
+                    ])),
+                }),
+                ..Default::default()
+            },
         }
     );
     assert_eq!(
@@ -247,8 +260,13 @@ fn parse_show_columns() {
         Statement::ShowColumns {
             extended: true,
             full: false,
-            table_name: table_name.clone(),
-            filter: None,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    scope: ShowStatementInScope::Object(table_name.clone()),
+                }),
+                ..Default::default()
+            },
         }
     );
     assert_eq!(
@@ -256,8 +274,13 @@ fn parse_show_columns() {
         Statement::ShowColumns {
             extended: false,
             full: true,
-            table_name: table_name.clone(),
-            filter: None,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    scope: ShowStatementInScope::Object(table_name.clone()),
+                }),
+                ..Default::default()
+            },
         }
     );
     assert_eq!(
@@ -265,8 +288,15 @@ fn parse_show_columns() {
         Statement::ShowColumns {
             extended: false,
             full: false,
-            table_name: table_name.clone(),
-            filter: Some(ShowStatementFilter::Like("pattern".into())),
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    scope: ShowStatementInScope::Object(table_name.clone()),
+                }),
+                filter: Some(ShowStatementFilter::Like("pattern".into())),
+                filter_position: Some(ShowStatementFilterPosition::AfterIn),
+                ..Default::default()
+            },
         }
     );
     assert_eq!(
@@ -274,10 +304,17 @@ fn parse_show_columns() {
         Statement::ShowColumns {
             extended: false,
             full: false,
-            table_name,
-            filter: Some(ShowStatementFilter::Where(
-                mysql_and_generic().verified_expr("1 = 2")
-            )),
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    scope: ShowStatementInScope::Object(table_name),
+                }),
+                filter: Some(ShowStatementFilter::Where(
+                    mysql_and_generic().verified_expr("1 = 2")
+                )),
+                filter_position: Some(ShowStatementFilterPosition::AfterIn),
+                ..Default::default()
+            },
         }
     );
     mysql_and_generic()
@@ -329,9 +366,7 @@ fn parse_show_tables() {
         Statement::ShowTables {
             extended: false,
             full: false,
-            clause: None,
-            db_name: None,
-            filter: None,
+            show_options: ShowStatementOptions::default(),
         }
     );
     assert_eq!(
@@ -339,9 +374,13 @@ fn parse_show_tables() {
         Statement::ShowTables {
             extended: false,
             full: false,
-            clause: Some(ShowClause::FROM),
-            db_name: Some(Ident::new("mydb")),
-            filter: None,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    scope: ShowStatementInScope::Object(ObjectName(vec![Ident::new("mydb")])),
+                }),
+                ..Default::default()
+            },
         }
     );
     assert_eq!(
@@ -349,9 +388,7 @@ fn parse_show_tables() {
         Statement::ShowTables {
             extended: true,
             full: false,
-            clause: None,
-            db_name: None,
-            filter: None,
+            show_options: ShowStatementOptions::default(),
         }
     );
     assert_eq!(
@@ -359,9 +396,7 @@ fn parse_show_tables() {
         Statement::ShowTables {
             extended: false,
             full: true,
-            clause: None,
-            db_name: None,
-            filter: None,
+            show_options: ShowStatementOptions::default(),
         }
     );
     assert_eq!(
@@ -369,9 +404,10 @@ fn parse_show_tables() {
         Statement::ShowTables {
             extended: false,
             full: false,
-            clause: None,
-            db_name: None,
-            filter: Some(ShowStatementFilter::Like("pattern".into())),
+            show_options: ShowStatementOptions {
+                filter: Some(ShowStatementFilter::Like("pattern".into())),
+                ..Default::default()
+            },
         }
     );
     assert_eq!(
@@ -379,11 +415,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")
-            )),
+            show_options: ShowStatementOptions {
+                filter: Some(ShowStatementFilter::Where(
+                    mysql_and_generic().verified_expr("1 = 2")
+                )),
+                ..Default::default()
+            },
         }
     );
     mysql_and_generic().verified_stmt("SHOW TABLES IN mydb");
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_snowflake.rs b/app/tests/sqlparser_snowflake.rs
index c17c7b9..1bb6bd5 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_snowflake.rs
+++ b/app/tests/sqlparser_snowflake.rs
@@ -114,6 +114,98 @@ fn test_snowflake_create_or_replace_table_copy_grants_cta() {
     }
 }
 
+#[test]
+fn test_snowflake_show_databases() {
+    assert_eq!(
+        snowflake().verified_stmt(
+            "SHOW TERSE DATABASES HISTORY LIKE 'demo%' STARTS WITH 'DEMO' LIMIT 10 FROM 'demo1'"
+        ),
+        Statement::ShowDatabases {
+            show_options: ShowStatementOptions {
+                filter: Some(ShowStatementFilter::Like("demo%".into())),
+                starts_with: Some("DEMO".into()),
+                limit: Some(ShowStatementLimit {
+                    rows: 10,
+                    from: Some("demo1".into()),
+                }),
+                terse: true,
+                history: true,
+                ..Default::default()
+            },
+        }
+    );
+}
+
+#[test]
+fn test_snowflake_show_tables_and_columns() {
+    assert_eq!(
+        snowflake().verified_stmt(
+            "SHOW TERSE EXTERNAL TABLES HISTORY LIKE 'foo%' IN DATABASE my_db STARTS WITH 'FOO' LIMIT 5 FROM 'foo0'"
+        ),
+        Statement::ShowTables {
+            extended: false,
+            full: false,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::IN,
+                    scope: ShowStatementInScope::Database(Some(ObjectName(vec![Ident::new(
+                        "my_db"
+                    )]))),
+                }),
+                filter: Some(ShowStatementFilter::Like("foo%".into())),
+                filter_position: Some(ShowStatementFilterPosition::BeforeIn),
+                starts_with: Some("FOO".into()),
+                limit: Some(ShowStatementLimit {
+                    rows: 5,
+                    from: Some("foo0".into()),
+                }),
+                terse: true,
+                history: true,
+                external: true,
+            },
+        }
+    );
+
+    assert_eq!(
+        snowflake().verified_stmt(
+            "SHOW TERSE COLUMNS LIKE 'id%' IN TABLE my_db.my_table LIMIT 3"
+        ),
+        Statement::ShowColumns {
+            extended: false,
+            full: false,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::IN,
+                    scope: ShowStatementInScope::Table(Some(ObjectName(vec![
+                        Ident::new("my_db"),
+                        Ident::new("my_table"),
+                    ]))),
+                }),
+                filter: Some(ShowStatementFilter::Like("id%".into())),
+                filter_position: Some(ShowStatementFilterPosition::BeforeIn),
+                limit: Some(ShowStatementLimit {
+                    rows: 3,
+                    from: None,
+                }),
+                terse: true,
+                ..Default::default()
+            },
+        }
+    );
+}
+
+#[test]
+fn test_snowflake_show_like_is_canonicalized_before_in() {
+    snowflake().one_statement_parses_to(
+        "SHOW TABLES IN DATABASE my_db LIKE 'foo%'",
+        "SHOW TABLES LIKE 'foo%' IN DATABASE my_db",
+    );
+    snowflake().one_statement_parses_to(
+        "SHOW COLUMNS IN TABLE my_table LIKE 'foo%'",
+        "SHOW COLUMNS LIKE 'foo%' IN TABLE my_table",
+    );
+}
+
 #[test]
 fn test_snowflake_create_table_enable_schema_evolution() {
     let sql = "CREATE TABLE my_table (a number) ENABLE_SCHEMA_EVOLUTION=TRUE";