STET

agent_patch

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

41515 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1501.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 81bddcd..848e6bd 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/mod.rs
+++ b/app/src/ast/mod.rs
@@ -2773,41 +2773,45 @@ pub enum Statement {
     /// ```sql
     /// SHOW COLUMNS
     /// ```
-    ///
-    /// Note: this is a MySQL-specific 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']
+    /// SHOW DATABASES
     /// ```
-    ShowDatabases { filter: Option<ShowStatementFilter> },
+    ShowDatabases {
+        terse: bool,
+        history: bool,
+        show_options: ShowStatementOptions,
+    },
     /// ```sql
-    /// SHOW SCHEMAS [LIKE 'pattern']
+    /// SHOW SCHEMAS
     /// ```
-    ShowSchemas { filter: Option<ShowStatementFilter> },
+    ShowSchemas {
+        terse: bool,
+        history: bool,
+        show_options: ShowStatementOptions,
+    },
     /// ```sql
     /// SHOW TABLES
     /// ```
     ShowTables {
+        terse: bool,
+        history: bool,
         extended: bool,
         full: bool,
-        clause: Option<ShowClause>,
-        db_name: Option<Ident>,
-        filter: Option<ShowStatementFilter>,
+        external: bool,
+        show_options: ShowStatementOptions,
     },
     /// ```sql
     /// SHOW VIEWS
     /// ```
     ShowViews {
+        terse: bool,
         materialized: bool,
-        clause: Option<ShowClause>,
-        db_name: Option<Ident>,
-        filter: Option<ShowStatementFilter>,
+        show_options: ShowStatementOptions,
     },
     /// ```sql
     /// SHOW COLLATION
@@ -4387,79 +4391,72 @@ 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}COLUMNS{show_options}",
                     extended = if *extended { "EXTENDED " } else { "" },
                     full = if *full { "FULL " } else { "" },
-                    table_name = table_name,
                 )?;
-                if let Some(filter) = filter {
-                    write!(f, " {filter}")?;
-                }
                 Ok(())
             }
-            Statement::ShowDatabases { filter } => {
-                write!(f, "SHOW DATABASES")?;
-                if let Some(filter) = filter {
-                    write!(f, " {filter}")?;
-                }
+            Statement::ShowDatabases {
+                terse,
+                history,
+                show_options,
+            } => {
+                write!(
+                    f,
+                    "SHOW {terse}DATABASES{history}{show_options}",
+                    terse = if *terse { "TERSE " } else { "" },
+                    history = if *history { " HISTORY" } else { "" },
+                )?;
                 Ok(())
             }
-            Statement::ShowSchemas { filter } => {
-                write!(f, "SHOW SCHEMAS")?;
-                if let Some(filter) = filter {
-                    write!(f, " {filter}")?;
-                }
+            Statement::ShowSchemas {
+                terse,
+                history,
+                show_options,
+            } => {
+                write!(
+                    f,
+                    "SHOW {terse}SCHEMAS{history}{show_options}",
+                    terse = if *terse { "TERSE " } else { "" },
+                    history = if *history { " HISTORY" } else { "" },
+                )?;
                 Ok(())
             }
             Statement::ShowTables {
+                terse,
+                history,
                 extended,
                 full,
-                clause: show_clause,
-                db_name,
-                filter,
+                external,
+                show_options,
             } => {
                 write!(
                     f,
-                    "SHOW {extended}{full}TABLES",
+                    "SHOW {terse}{extended}{full}{external}TABLES{history}{show_options}",
+                    terse = if *terse { "TERSE " } else { "" },
                     extended = if *extended { "EXTENDED " } else { "" },
                     full = if *full { "FULL " } else { "" },
+                    external = if *external { "EXTERNAL " } else { "" },
+                    history = if *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}")?;
-                }
                 Ok(())
             }
             Statement::ShowViews {
+                terse,
                 materialized,
-                clause: show_clause,
-                db_name,
-                filter,
+                show_options,
             } => {
                 write!(
                     f,
-                    "SHOW {}VIEWS",
-                    if *materialized { "MATERIALIZED " } else { "" }
+                    "SHOW {terse}{materialized}VIEWS{show_options}",
+                    terse = if *terse { "TERSE " } else { "" },
+                    materialized = 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}")?;
-                }
-                if let Some(filter) = filter {
-                    write!(f, " {filter}")?;
-                }
                 Ok(())
             }
             Statement::ShowFunctions { filter } => {
@@ -6172,14 +6169,14 @@ 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 {
+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"),
@@ -7357,6 +7354,108 @@ impl Display for UtilityOption {
     }
 }
 
+/// Represents the different options available for `SHOW`
+/// statements to filter the results. Example from Snowflake:
+/// <https://docs.snowflake.com/en/sql-reference/sql/show-tables>
+#[derive(Debug, 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 starts_with: Option<Value>,
+    pub limit: Option<Expr>,
+    pub limit_from: Option<Value>,
+    pub filter_position: Option<ShowStatementFilterPosition>,
+}
+
+impl Display for ShowStatementOptions {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let (like_in_infix, like_in_suffix) = match &self.filter_position {
+            Some(ShowStatementFilterPosition::Infix(filter)) => {
+                (format!(" {filter}"), "".to_string())
+            }
+            Some(ShowStatementFilterPosition::Suffix(filter)) => {
+                ("".to_string(), format!(" {filter}"))
+            }
+            None => ("".to_string(), "".to_string()),
+        };
+        write!(
+            f,
+            "{like_in_infix}{show_in}{starts_with}{limit}{from}{like_in_suffix}",
+            show_in = match &self.show_in {
+                Some(i) => format!(" {i}"),
+                None => String::new(),
+            },
+            starts_with = match &self.starts_with {
+                Some(s) => format!(" STARTS WITH {s}"),
+                None => String::new(),
+            },
+            limit = match &self.limit {
+                Some(l) => format!(" LIMIT {l}"),
+                None => String::new(),
+            },
+            from = match &self.limit_from {
+                Some(f) => format!(" FROM {f}"),
+                None => String::new(),
+            }
+        )?;
+        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 ShowStatementFilterPosition {
+    Infix(ShowStatementFilter), // For example: SHOW COLUMNS LIKE '%name%' IN TABLE tbl
+    Suffix(ShowStatementFilter), // For example: SHOW COLUMNS IN tbl LIKE '%name%'
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum ShowStatementInParentType {
+    Account,
+    Database,
+    Schema,
+    Table,
+    View,
+}
+
+impl fmt::Display for ShowStatementInParentType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            ShowStatementInParentType::Account => write!(f, "ACCOUNT"),
+            ShowStatementInParentType::Database => write!(f, "DATABASE"),
+            ShowStatementInParentType::Schema => write!(f, "SCHEMA"),
+            ShowStatementInParentType::Table => write!(f, "TABLE"),
+            ShowStatementInParentType::View => write!(f, "VIEW"),
+        }
+    }
+}
+
+#[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 parent_type: Option<ShowStatementInParentType>,
+    pub parent_name: Option<ObjectName>,
+}
+
+impl fmt::Display for ShowStatementIn {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.clause)?;
+        if let Some(parent_type) = &self.parent_type {
+            write!(f, " {}", parent_type)?;
+        }
+        if let Some(parent_name) = &self.parent_name {
+            write!(f, " {}", parent_name)?;
+        }
+        Ok(())
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/dialect/mod.rs b/app/src/dialect/mod.rs
index c8c11bc..f37c0d8 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/dialect/mod.rs
+++ b/app/src/dialect/mod.rs
@@ -622,6 +622,12 @@ pub trait Dialect: Debug + Any {
     fn supports_boolean_literals(&self) -> bool {
         true
     }
+
+    /// Returns true if this dialect supports the `LIKE 'pattern'` option in
+    /// a `SHOW` statement before the `IN` option
+    fn supports_show_like_before_in(&self) -> bool {
+        false
+    }
 }
 
 /// 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-3-codex/app/src/dialect/snowflake.rs b/app/src/dialect/snowflake.rs
index d9331d9..98e8f5e 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/dialect/snowflake.rs
+++ b/app/src/dialect/snowflake.rs
@@ -203,6 +203,12 @@ impl Dialect for SnowflakeDialect {
     fn allow_extract_single_quotes(&self) -> bool {
         true
     }
+
+    /// Snowflake expects the `LIKE` option before the `IN` option,
+    /// for example: <https://docs.snowflake.com/en/sql-reference/sql/show-views#syntax>
+    fn supports_show_like_before_in(&self) -> bool {
+        true
+    }
 }
 
 /// Parse snowflake create table statement.
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/keywords.rs b/app/src/keywords.rs
index 982cea8..9cdc90c 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/keywords.rs
+++ b/app/src/keywords.rs
@@ -76,6 +76,7 @@ define_keywords!(
     ABS,
     ABSOLUTE,
     ACCESS,
+    ACCOUNT,
     ACTION,
     ADD,
     ADMIN,
@@ -91,6 +92,7 @@ define_keywords!(
     AND,
     ANTI,
     ANY,
+    APPLICATION,
     APPLY,
     ARCHIVE,
     ARE,
@@ -710,6 +712,7 @@ define_keywords!(
     STABLE,
     STAGE,
     START,
+    STARTS,
     STATEMENT,
     STATIC,
     STATISTICS,
@@ -746,6 +749,7 @@ define_keywords!(
     TEMP,
     TEMPORARY,
     TERMINATED,
+    TERSE,
     TEXT,
     TEXTFILE,
     THEN,
diff --git a/tmp/agent-patch-flux-pr-1501.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 d3f4320..7f6961a 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -3205,6 +3205,22 @@ impl<'a> Parser<'a> {
             })
     }
 
+    /// Look for all of the expected keywords in sequence, without consuming them
+    fn peek_keyword(&mut self, expected: Keyword) -> bool {
+        let index = self.index;
+        let matched = self.parse_keyword(expected);
+        self.index = index;
+        matched
+    }
+
+    /// Look for all of the expected keywords in sequence, without consuming them
+    fn peek_keywords(&mut self, expected: &[Keyword]) -> bool {
+        let index = self.index;
+        let matched = self.parse_keywords(expected);
+        self.index = index;
+        matched
+    }
+
     /// Return the first non-whitespace token that has not yet been processed
     /// (or None if reached end-of-file) and mark it as processed. OK to call
     /// repeatedly after reaching EOF.
@@ -9611,21 +9627,23 @@ impl<'a> Parser<'a> {
     }
 
     pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
+        let terse = self.parse_keyword(Keyword::TERSE);
         let extended = self.parse_keyword(Keyword::EXTENDED);
         let full = self.parse_keyword(Keyword::FULL);
         let session = self.parse_keyword(Keyword::SESSION);
         let global = self.parse_keyword(Keyword::GLOBAL);
+        let external = self.parse_keyword(Keyword::EXTERNAL);
         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)?)
+            Ok(self.parse_show_tables(terse, extended, full, external)?)
         } else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
-            Ok(self.parse_show_views(true)?)
+            Ok(self.parse_show_views(terse, true)?)
         } else if self.parse_keyword(Keyword::VIEWS) {
-            Ok(self.parse_show_views(false)?)
+            Ok(self.parse_show_views(terse, false)?)
         } else if self.parse_keyword(Keyword::FUNCTIONS) {
             Ok(self.parse_show_functions()?)
         } else if extended || full {
@@ -9653,9 +9671,9 @@ impl<'a> Parser<'a> {
                 global,
             })
         } else if self.parse_keyword(Keyword::DATABASES) {
-            self.parse_show_databases()
+            self.parse_show_databases(terse)
         } else if self.parse_keyword(Keyword::SCHEMAS) {
-            self.parse_show_schemas()
+            self.parse_show_schemas(terse)
         } else {
             Ok(Statement::ShowVariable {
                 variable: self.parse_identifiers()?,
@@ -9663,15 +9681,23 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_show_databases(&mut self) -> Result<Statement, ParserError> {
+    fn parse_show_databases(&mut self, terse: bool) -> Result<Statement, ParserError> {
+        let history = self.parse_keyword(Keyword::HISTORY);
+        let show_options = self.parse_show_stmt_options()?;
         Ok(Statement::ShowDatabases {
-            filter: self.parse_show_statement_filter()?,
+            terse,
+            history,
+            show_options,
         })
     }
 
-    fn parse_show_schemas(&mut self) -> Result<Statement, ParserError> {
+    fn parse_show_schemas(&mut self, terse: bool) -> Result<Statement, ParserError> {
+        let history = self.parse_keyword(Keyword::HISTORY);
+        let show_options = self.parse_show_stmt_options()?;
         Ok(Statement::ShowSchemas {
-            filter: self.parse_show_statement_filter()?,
+            terse,
+            history,
+            show_options,
         })
     }
 
@@ -9705,58 +9731,43 @@ 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 show_options = self.parse_show_stmt_options()?;
         Ok(Statement::ShowColumns {
             extended,
             full,
-            table_name,
-            filter,
+            show_options,
         })
     }
 
-    pub fn parse_show_tables(
+    fn parse_show_tables(
         &mut self,
+        terse: bool,
         extended: bool,
         full: 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 = !external && self.parse_keyword(Keyword::HISTORY);
+        let show_options = self.parse_show_stmt_options()?;
         Ok(Statement::ShowTables {
+            terse,
+            history,
             extended,
             full,
-            clause,
-            db_name,
-            filter,
+            external,
+            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,
+        terse: bool,
+        materialized: bool,
+    ) -> Result<Statement, ParserError> {
+        let show_options = self.parse_show_stmt_options()?;
         Ok(Statement::ShowViews {
             materialized,
-            clause,
-            db_name,
-            filter,
+            terse,
+            show_options,
         })
     }
 
@@ -12395,6 +12406,124 @@ impl<'a> Parser<'a> {
         }
         false
     }
+
+    fn parse_show_stmt_options(&mut self) -> Result<ShowStatementOptions, ParserError> {
+        let show_in;
+        let mut filter_position = None;
+        if self.dialect.supports_show_like_before_in() {
+            if let Some(filter) = self.parse_show_statement_filter()? {
+                filter_position = Some(ShowStatementFilterPosition::Infix(filter));
+            }
+            show_in = self.maybe_parse_show_stmt_in()?;
+        } else {
+            show_in = self.maybe_parse_show_stmt_in()?;
+            if let Some(filter) = self.parse_show_statement_filter()? {
+                filter_position = Some(ShowStatementFilterPosition::Suffix(filter));
+            }
+        }
+        let starts_with = self.maybe_parse_show_stmt_starts_with()?;
+        let limit = self.maybe_parse_show_stmt_limit()?;
+        let from = self.maybe_parse_show_stmt_from()?;
+        Ok(ShowStatementOptions {
+            filter_position,
+            show_in,
+            starts_with,
+            limit,
+            limit_from: from,
+        })
+    }
+
+    fn maybe_parse_show_stmt_in(&mut self) -> Result<Option<ShowStatementIn>, ParserError> {
+        let clause = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
+            Some(Keyword::FROM) => ShowStatementInClause::FROM,
+            Some(Keyword::IN) => ShowStatementInClause::IN,
+            None => return Ok(None),
+            _ => return self.expected("FROM or IN", self.peek_token()),
+        };
+
+        let (parent_type, parent_name) = match self.parse_one_of_keywords(&[
+            Keyword::ACCOUNT,
+            Keyword::DATABASE,
+            Keyword::SCHEMA,
+            Keyword::TABLE,
+            Keyword::VIEW,
+        ]) {
+            // If we see these next keywords it means we don't have a parent name
+            Some(Keyword::DATABASE)
+                if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH])
+                    | self.peek_keyword(Keyword::LIMIT) =>
+            {
+                (Some(ShowStatementInParentType::Database), None)
+            }
+            Some(Keyword::SCHEMA)
+                if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH])
+                    | self.peek_keyword(Keyword::LIMIT) =>
+            {
+                (Some(ShowStatementInParentType::Schema), None)
+            }
+            Some(parent_kw) => {
+                // The parent name here is still optional, for example:
+                // SHOW TABLES IN ACCOUNT, so parsing the object name
+                // may fail because the statement ends.
+                let parent_name = self.maybe_parse(|p| p.parse_object_name(false))?;
+                match parent_kw {
+                    Keyword::ACCOUNT => (Some(ShowStatementInParentType::Account), parent_name),
+                    Keyword::DATABASE => (Some(ShowStatementInParentType::Database), parent_name),
+                    Keyword::SCHEMA => (Some(ShowStatementInParentType::Schema), parent_name),
+                    Keyword::TABLE => (Some(ShowStatementInParentType::Table), parent_name),
+                    Keyword::VIEW => (Some(ShowStatementInParentType::View), parent_name),
+                    _ => {
+                        return self.expected(
+                            "one of ACCOUNT, DATABASE, SCHEMA, TABLE or VIEW",
+                            self.peek_token(),
+                        )
+                    }
+                }
+            }
+            None => {
+                // Parsing MySQL style FROM tbl_name FROM db_name
+                // which is equivalent to FROM tbl_name.db_name
+                let mut parent_name = self.parse_object_name(false)?;
+                if self
+                    .parse_one_of_keywords(&[Keyword::FROM, Keyword::IN])
+                    .is_some()
+                {
+                    parent_name.0.insert(0, self.parse_identifier(false)?);
+                }
+                (None, Some(parent_name))
+            }
+        };
+
+        Ok(Some(ShowStatementIn {
+            clause,
+            parent_type,
+            parent_name,
+        }))
+    }
+
+    fn maybe_parse_show_stmt_starts_with(&mut self) -> Result<Option<Value>, ParserError> {
+        if self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) {
+            Ok(Some(self.parse_value()?))
+        } else {
+            Ok(None)
+        }
+    }
+
+    fn maybe_parse_show_stmt_limit(&mut self) -> Result<Option<Expr>, ParserError> {
+        if self.parse_keyword(Keyword::LIMIT) {
+            Ok(self.parse_limit()?)
+        } else {
+            Ok(None)
+        }
+    }
+
+    fn maybe_parse_show_stmt_from(&mut self) -> Result<Option<Value>, ParserError> {
+        if self.parse_keyword(Keyword::FROM) {
+            Ok(Some(self.parse_value()?))
+        } else {
+            Ok(None)
+        }
+    }
 }
 
 impl Word {
diff --git a/tmp/agent-patch-flux-pr-1501.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 bef0f53..d08e19d 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_common.rs
+++ b/app/tests/sqlparser_common.rs
@@ -11395,23 +11395,43 @@ fn test_try_convert() {
 
 #[test]
 fn test_show_dbs_schemas_tables_views() {
-    verified_stmt("SHOW DATABASES");
-    verified_stmt("SHOW DATABASES LIKE '%abc'");
-    verified_stmt("SHOW SCHEMAS");
-    verified_stmt("SHOW SCHEMAS LIKE '%abc'");
-    verified_stmt("SHOW TABLES");
-    verified_stmt("SHOW TABLES IN db1");
-    verified_stmt("SHOW TABLES IN db1 'abc'");
-    verified_stmt("SHOW VIEWS");
-    verified_stmt("SHOW VIEWS IN db1");
-    verified_stmt("SHOW VIEWS IN db1 'abc'");
-    verified_stmt("SHOW VIEWS FROM db1");
-    verified_stmt("SHOW VIEWS FROM db1 'abc'");
-    verified_stmt("SHOW MATERIALIZED VIEWS");
-    verified_stmt("SHOW MATERIALIZED VIEWS IN db1");
-    verified_stmt("SHOW MATERIALIZED VIEWS IN db1 'abc'");
-    verified_stmt("SHOW MATERIALIZED VIEWS FROM db1");
-    verified_stmt("SHOW MATERIALIZED VIEWS FROM db1 'abc'");
+    // These statements are parsed the same by all dialects
+    let stmts = vec![
+        "SHOW DATABASES",
+        "SHOW SCHEMAS",
+        "SHOW TABLES",
+        "SHOW VIEWS",
+        "SHOW TABLES IN db1",
+        "SHOW VIEWS FROM db1",
+        "SHOW MATERIALIZED VIEWS",
+        "SHOW MATERIALIZED VIEWS IN db1",
+        "SHOW MATERIALIZED VIEWS FROM db1",
+    ];
+    for stmt in stmts {
+        verified_stmt(stmt);
+    }
+
+    // These statements are parsed the same by all dialects
+    // except for how the parser interprets the location of
+    // LIKE option (infix/suffix)
+    let stmts = vec!["SHOW DATABASES LIKE '%abc'", "SHOW SCHEMAS LIKE '%abc'"];
+    for stmt in stmts {
+        all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt(stmt);
+        all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt(stmt);
+    }
+
+    // These statements are only parsed by dialects that
+    // support the LIKE option in the suffix
+    let stmts = vec![
+        "SHOW TABLES IN db1 'abc'",
+        "SHOW VIEWS IN db1 'abc'",
+        "SHOW VIEWS FROM db1 'abc'",
+        "SHOW MATERIALIZED VIEWS IN db1 'abc'",
+        "SHOW MATERIALIZED VIEWS FROM db1 'abc'",
+    ];
+    for stmt in stmts {
+        all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt(stmt);
+    }
 }
 
 #[test]
diff --git a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_mysql.rs b/app/tests/sqlparser_mysql.rs
index 44b2ac6..8269ead 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_mysql.rs
+++ b/app/tests/sqlparser_mysql.rs
@@ -223,14 +223,22 @@ fn parse_flush() {
 
 #[test]
 fn parse_show_columns() {
-    let table_name = ObjectName(vec![Ident::new("mytable")]);
     assert_eq!(
         mysql_and_generic().verified_stmt("SHOW COLUMNS FROM mytable"),
         Statement::ShowColumns {
             extended: false,
             full: false,
-            table_name: table_name.clone(),
-            filter: None,
+            show_options: ShowStatementOptions {
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    parent_type: None,
+                    parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
+                }),
+                filter_position: None,
+                limit_from: None,
+                limit: None,
+                starts_with: None,
+            }
         }
     );
     assert_eq!(
@@ -238,8 +246,17 @@ 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,
+                    parent_type: None,
+                    parent_name: Some(ObjectName(vec![Ident::new("mydb"), Ident::new("mytable")])),
+                }),
+                filter_position: None,
+                limit_from: None,
+                limit: None,
+                starts_with: None,
+            }
         }
     );
     assert_eq!(
@@ -247,8 +264,17 @@ 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,
+                    parent_type: None,
+                    parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
+                }),
+                filter_position: None,
+                limit_from: None,
+                limit: None,
+                starts_with: None,
+            }
         }
     );
     assert_eq!(
@@ -256,8 +282,17 @@ 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,
+                    parent_type: None,
+                    parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
+                }),
+                filter_position: None,
+                limit_from: None,
+                limit: None,
+                starts_with: None,
+            }
         }
     );
     assert_eq!(
@@ -265,8 +300,19 @@ 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,
+                    parent_type: None,
+                    parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
+                }),
+                filter_position: Some(ShowStatementFilterPosition::Suffix(
+                    ShowStatementFilter::Like("pattern".into())
+                )),
+                limit_from: None,
+                limit: None,
+                starts_with: None,
+            }
         }
     );
     assert_eq!(
@@ -274,18 +320,27 @@ 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,
+                    parent_type: None,
+                    parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
+                }),
+                filter_position: Some(ShowStatementFilterPosition::Suffix(
+                    ShowStatementFilter::Where(mysql_and_generic().verified_expr("1 = 2"))
+                )),
+                limit_from: None,
+                limit: None,
+                starts_with: None,
+            }
         }
     );
     mysql_and_generic()
         .one_statement_parses_to("SHOW FIELDS FROM mytable", "SHOW COLUMNS FROM mytable");
     mysql_and_generic()
-        .one_statement_parses_to("SHOW COLUMNS IN mytable", "SHOW COLUMNS FROM mytable");
+        .one_statement_parses_to("SHOW COLUMNS IN mytable", "SHOW COLUMNS IN mytable");
     mysql_and_generic()
-        .one_statement_parses_to("SHOW FIELDS IN mytable", "SHOW COLUMNS FROM mytable");
+        .one_statement_parses_to("SHOW FIELDS IN mytable", "SHOW COLUMNS IN mytable");
     mysql_and_generic().one_statement_parses_to(
         "SHOW COLUMNS FROM mytable FROM mydb",
         "SHOW COLUMNS FROM mydb.mytable",
@@ -327,63 +382,111 @@ fn parse_show_tables() {
     assert_eq!(
         mysql_and_generic().verified_stmt("SHOW TABLES"),
         Statement::ShowTables {
+            terse: false,
+            history: false,
             extended: false,
             full: false,
-            clause: None,
-            db_name: None,
-            filter: None,
+            external: false,
+            show_options: ShowStatementOptions {
+                starts_with: None,
+                limit: None,
+                limit_from: None,
+                show_in: None,
+                filter_position: None
+            }
         }
     );
     assert_eq!(
         mysql_and_generic().verified_stmt("SHOW TABLES FROM mydb"),
         Statement::ShowTables {
+            terse: false,
+            history: false,
             extended: false,
             full: false,
-            clause: Some(ShowClause::FROM),
-            db_name: Some(Ident::new("mydb")),
-            filter: None,
+            external: false,
+            show_options: ShowStatementOptions {
+                starts_with: None,
+                limit: None,
+                limit_from: None,
+                show_in: Some(ShowStatementIn {
+                    clause: ShowStatementInClause::FROM,
+                    parent_type: None,
+                    parent_name: Some(ObjectName(vec![Ident::new("mydb")])),
+                }),
+                filter_position: None
+            }
         }
     );
     assert_eq!(
         mysql_and_generic().verified_stmt("SHOW EXTENDED TABLES"),
         Statement::ShowTables {
+            terse: false,
+            history: false,
             extended: true,
             full: false,
-            clause: None,
-            db_name: None,
-            filter: None,
+            external: false,
+            show_options: ShowStatementOptions {
+                starts_with: None,
+                limit: None,
+                limit_from: None,
+                show_in: None,
+                filter_position: None
+            }
         }
     );
     assert_eq!(
         mysql_and_generic().verified_stmt("SHOW FULL TABLES"),
         Statement::ShowTables {
+            terse: false,
+            history: false,
             extended: false,
             full: true,
-            clause: None,
-            db_name: None,
-            filter: None,
+            external: false,
+            show_options: ShowStatementOptions {
+                starts_with: None,
+                limit: None,
+                limit_from: None,
+                show_in: None,
+                filter_position: None
+            }
         }
     );
     assert_eq!(
         mysql_and_generic().verified_stmt("SHOW TABLES LIKE 'pattern'"),
         Statement::ShowTables {
+            terse: false,
+            history: false,
             extended: false,
             full: false,
-            clause: None,
-            db_name: None,
-            filter: Some(ShowStatementFilter::Like("pattern".into())),
+            external: false,
+            show_options: ShowStatementOptions {
+                starts_with: None,
+                limit: None,
+                limit_from: None,
+                show_in: None,
+                filter_position: Some(ShowStatementFilterPosition::Suffix(
+                    ShowStatementFilter::Like("pattern".into())
+                ))
+            }
         }
     );
     assert_eq!(
         mysql_and_generic().verified_stmt("SHOW TABLES WHERE 1 = 2"),
         Statement::ShowTables {
+            terse: false,
+            history: false,
             extended: false,
             full: false,
-            clause: None,
-            db_name: None,
-            filter: Some(ShowStatementFilter::Where(
-                mysql_and_generic().verified_expr("1 = 2")
-            )),
+            external: false,
+            show_options: ShowStatementOptions {
+                starts_with: None,
+                limit: None,
+                limit_from: None,
+                show_in: None,
+                filter_position: Some(ShowStatementFilterPosition::Suffix(
+                    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-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_snowflake.rs b/app/tests/sqlparser_snowflake.rs
index c17c7b9..1f1c00e 100644
--- a/tmp/agent-patch-flux-pr-1501.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_snowflake.rs
+++ b/app/tests/sqlparser_snowflake.rs
@@ -2781,3 +2781,68 @@ fn test_parentheses_overflow() {
         snowflake_with_recursion_limit(max_nesting_level).parse_sql_statements(sql.as_str());
     assert_eq!(parsed.err(), Some(ParserError::RecursionLimitExceeded));
 }
+
+#[test]
+fn test_show_databases() {
+    snowflake().verified_stmt("SHOW DATABASES");
+    snowflake().verified_stmt("SHOW DATABASES HISTORY");
+    snowflake().verified_stmt("SHOW DATABASES LIKE '%abc%'");
+    snowflake().verified_stmt("SHOW DATABASES STARTS WITH 'demo_db'");
+    snowflake().verified_stmt("SHOW DATABASES LIMIT 12");
+    snowflake()
+        .verified_stmt("SHOW DATABASES HISTORY LIKE '%aa' STARTS WITH 'demo' LIMIT 20 FROM 'abc'");
+    snowflake().verified_stmt("SHOW DATABASES IN ACCOUNT abc");
+}
+
+#[test]
+fn test_parse_show_schemas() {
+    snowflake().verified_stmt("SHOW SCHEMAS");
+    snowflake().verified_stmt("SHOW SCHEMAS IN ACCOUNT");
+    snowflake().verified_stmt("SHOW SCHEMAS IN ACCOUNT abc");
+    snowflake().verified_stmt("SHOW SCHEMAS IN DATABASE");
+    snowflake().verified_stmt("SHOW SCHEMAS IN DATABASE xyz");
+    snowflake().verified_stmt("SHOW SCHEMAS HISTORY LIKE '%xa%'");
+    snowflake().verified_stmt("SHOW SCHEMAS STARTS WITH 'abc' LIMIT 20");
+    snowflake().verified_stmt("SHOW SCHEMAS IN DATABASE STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
+}
+
+#[test]
+fn test_parse_show_tables() {
+    snowflake().verified_stmt("SHOW TABLES");
+    snowflake().verified_stmt("SHOW TABLES IN ACCOUNT");
+    snowflake().verified_stmt("SHOW TABLES IN DATABASE");
+    snowflake().verified_stmt("SHOW TABLES IN DATABASE xyz");
+    snowflake().verified_stmt("SHOW TABLES IN SCHEMA");
+    snowflake().verified_stmt("SHOW TABLES IN SCHEMA xyz");
+    snowflake().verified_stmt("SHOW TABLES HISTORY LIKE '%xa%'");
+    snowflake().verified_stmt("SHOW TABLES STARTS WITH 'abc' LIMIT 20");
+    snowflake().verified_stmt("SHOW TABLES IN SCHEMA STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
+    snowflake().verified_stmt("SHOW EXTERNAL TABLES");
+    snowflake().verified_stmt("SHOW EXTERNAL TABLES IN ACCOUNT");
+    snowflake().verified_stmt("SHOW EXTERNAL TABLES IN DATABASE");
+    snowflake().verified_stmt("SHOW EXTERNAL TABLES IN DATABASE xyz");
+    snowflake().verified_stmt("SHOW EXTERNAL TABLES IN SCHEMA");
+    snowflake().verified_stmt("SHOW EXTERNAL TABLES IN SCHEMA xyz");
+    snowflake().verified_stmt("SHOW EXTERNAL TABLES STARTS WITH 'abc' LIMIT 20");
+    snowflake()
+        .verified_stmt("SHOW EXTERNAL TABLES IN SCHEMA STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
+}
+
+#[test]
+fn test_show_views() {
+    snowflake().verified_stmt("SHOW VIEWS");
+    snowflake().verified_stmt("SHOW VIEWS IN ACCOUNT");
+    snowflake().verified_stmt("SHOW VIEWS IN DATABASE");
+    snowflake().verified_stmt("SHOW VIEWS IN DATABASE xyz");
+    snowflake().verified_stmt("SHOW VIEWS IN SCHEMA");
+    snowflake().verified_stmt("SHOW VIEWS IN SCHEMA xyz");
+    snowflake().verified_stmt("SHOW VIEWS STARTS WITH 'abc' LIMIT 20");
+    snowflake().verified_stmt("SHOW VIEWS IN SCHEMA STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
+}
+
+#[test]
+fn test_parse_show_columns_sql() {
+    snowflake().verified_stmt("SHOW COLUMNS IN TABLE");
+    snowflake().verified_stmt("SHOW COLUMNS IN TABLE abc");
+    snowflake().verified_stmt("SHOW COLUMNS LIKE '%xyz%' IN TABLE abc");
+}