From 4a533132b58090512c03337111925f8bc7098e97 Mon Sep 17 00:00:00 2001 From: Etgar Perets Date: Thu, 24 Jul 2025 13:27:27 +0300 Subject: [PATCH 1/3] SGA-11783 Added support for SHOW CHARSET --- src/ast/mod.rs | 29 +++++++++++++++++++++++++++++ src/ast/spans.rs | 1 + src/parser/mod.rs | 12 ++++++++++++ tests/sqlparser_mysql.rs | 8 ++++++++ 4 files changed, 50 insertions(+) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 1798223f3..4c274367a 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -3704,6 +3704,20 @@ pub enum Statement { history: bool, show_options: ShowStatementOptions, }, + // ```sql + // SHOW {CHARACTER SET | CHARSET} [like_or_where] + // ``` + // where: + // like_or_where: { + // LIKE 'pattern' + // | WHERE expr + // } + // MySQL specific statement + // + ShowCharset { + is_shorthand: bool, + filter: Option, + }, /// ```sql /// SHOW OBJECTS LIKE 'line%' IN mydb.public /// ``` @@ -5674,6 +5688,21 @@ impl fmt::Display for Statement { } Ok(()) } + Statement::ShowCharset { + is_shorthand, + filter, + } => { + write!(f, "SHOW")?; + if *is_shorthand { + write!(f, " CHARSET")?; + } else { + write!(f, " CHARACTER SET")?; + } + if filter.is_some() { + write!(f, " {}", filter.as_ref().unwrap())?; + } + Ok(()) + } Statement::StartTransaction { modes, begin: syntax_begin, diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 3e82905e1..e7af426c1 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -477,6 +477,7 @@ impl Spanned for Statement { Statement::ShowColumns { .. } => Span::empty(), Statement::ShowTables { .. } => Span::empty(), Statement::ShowCollation { .. } => Span::empty(), + Statement::ShowCharset { .. } => Span::empty(), Statement::Use(u) => u.span(), Statement::StartTransaction { .. } => Span::empty(), Statement::Comment { .. } => Span::empty(), diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 8d5a55da0..be860751e 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12505,6 +12505,10 @@ impl<'a> Parser<'a> { self.parse_show_databases(terse) } else if self.parse_keyword(Keyword::SCHEMAS) { self.parse_show_schemas(terse) + } else if self.parse_keywords(&[Keyword::CHARACTER, Keyword::SET]) { + self.parse_show_charset(false) + } else if self.parse_keyword(Keyword::CHARSET) { + self.parse_show_charset(true) } else { Ok(Statement::ShowVariable { variable: self.parse_identifiers()?, @@ -12512,6 +12516,14 @@ impl<'a> Parser<'a> { } } + fn parse_show_charset(&mut self, is_shorthand: bool) -> Result { + // parse one of keywords + Ok(Statement::ShowCharset { + is_shorthand, + filter: self.parse_show_statement_filter()?, + }) + } + fn parse_show_databases(&mut self, terse: bool) -> Result { let history = self.parse_keyword(Keyword::HISTORY); let show_options = self.parse_show_stmt_options()?; diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 9068ed9c5..da07b9799 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -4143,3 +4143,11 @@ fn parse_json_member_of() { _ => panic!("Unexpected statement {stmt}"), } } + +#[test] +fn parse_show_charset() { + let _ = mysql().verified_stmt("SHOW CHARACTER SET"); + let _ = mysql().verified_stmt("SHOW CHARACTER SET LIKE 'utf8mb4%'"); + let _ = mysql().verified_stmt("SHOW CHARSET WHERE charset = 'utf8mb4%'"); + let _ = mysql().verified_stmt("SHOW CHARSET LIKE 'utf8mb4%'"); +} From 9352477d98d1352e53e663861c7574fce6e6ba3d Mon Sep 17 00:00:00 2001 From: Etgar Perets Date: Sun, 27 Jul 2025 13:32:07 +0300 Subject: [PATCH 2/3] SGA-11783 Address review feedback for SHOW CHARSET Improves the initial `SHOW CHARSET` implementation by: - Using a named struct for the AST node - Adding AST assertion to the parser test - Improving code comments --- src/ast/mod.rs | 56 +++++++++++++++++++++------------------- src/parser/mod.rs | 4 +-- tests/sqlparser_mysql.rs | 15 ++++++++--- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 4c274367a..bdfcdf937 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -3705,19 +3705,11 @@ pub enum Statement { show_options: ShowStatementOptions, }, // ```sql - // SHOW {CHARACTER SET | CHARSET} [like_or_where] + // SHOW {CHARACTER SET | CHARSET} // ``` - // where: - // like_or_where: { - // LIKE 'pattern' - // | WHERE expr - // } - // MySQL specific statement + // [MySQL]: // - ShowCharset { - is_shorthand: bool, - filter: Option, - }, + ShowCharset(ShowCharset), /// ```sql /// SHOW OBJECTS LIKE 'line%' IN mydb.public /// ``` @@ -5688,21 +5680,7 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::ShowCharset { - is_shorthand, - filter, - } => { - write!(f, "SHOW")?; - if *is_shorthand { - write!(f, " CHARSET")?; - } else { - write!(f, " CHARACTER SET")?; - } - if filter.is_some() { - write!(f, " {}", filter.as_ref().unwrap())?; - } - Ok(()) - } + Statement::ShowCharset(show_stm) => show_stm.fmt(f), Statement::StartTransaction { modes, begin: syntax_begin, @@ -9821,6 +9799,32 @@ impl fmt::Display for ShowStatementIn { } } +/// A Show Charset statement +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub struct ShowCharset { + /// The statement can be written as SHOW CHARSET or SHOW CHARACTER SET + /// true means CHARSET was used and false means CHARACTER SET was used + pub is_shorthand: bool, + pub filter: Option, +} + +impl fmt::Display for ShowCharset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "SHOW")?; + if self.is_shorthand { + write!(f, " CHARSET")?; + } else { + write!(f, " CHARACTER SET")?; + } + if self.filter.is_some() { + write!(f, " {}", self.filter.as_ref().unwrap())?; + } + Ok(()) + } +} + #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] diff --git a/src/parser/mod.rs b/src/parser/mod.rs index be860751e..95286be7c 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12518,10 +12518,10 @@ impl<'a> Parser<'a> { fn parse_show_charset(&mut self, is_shorthand: bool) -> Result { // parse one of keywords - Ok(Statement::ShowCharset { + Ok(Statement::ShowCharset(ShowCharset { is_shorthand, filter: self.parse_show_statement_filter()?, - }) + })) } fn parse_show_databases(&mut self, terse: bool) -> Result { diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index da07b9799..82b45740d 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -4146,8 +4146,15 @@ fn parse_json_member_of() { #[test] fn parse_show_charset() { - let _ = mysql().verified_stmt("SHOW CHARACTER SET"); - let _ = mysql().verified_stmt("SHOW CHARACTER SET LIKE 'utf8mb4%'"); - let _ = mysql().verified_stmt("SHOW CHARSET WHERE charset = 'utf8mb4%'"); - let _ = mysql().verified_stmt("SHOW CHARSET LIKE 'utf8mb4%'"); + let res = mysql().verified_stmt("SHOW CHARACTER SET"); + assert_eq!( + res, + Statement::ShowCharset(ShowCharset { + is_shorthand: false, + filter: None + }) + ); + mysql().verified_stmt("SHOW CHARACTER SET LIKE 'utf8mb4%'"); + mysql().verified_stmt("SHOW CHARSET WHERE charset = 'utf8mb4%'"); + mysql().verified_stmt("SHOW CHARSET LIKE 'utf8mb4%'"); } From 4a73878dd7e0676982eef96705a4378f3eb5ee61 Mon Sep 17 00:00:00 2001 From: etgarperets Date: Tue, 29 Jul 2025 11:51:42 +0300 Subject: [PATCH 3/3] Update src/ast/mod.rs Co-authored-by: Ifeanyi Ubah --- src/ast/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index bdfcdf937..c55d22602 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -9804,7 +9804,7 @@ impl fmt::Display for ShowStatementIn { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ShowCharset { - /// The statement can be written as SHOW CHARSET or SHOW CHARACTER SET + /// The statement can be written as `SHOW CHARSET` or `SHOW CHARACTER SET` /// true means CHARSET was used and false means CHARACTER SET was used pub is_shorthand: bool, pub filter: Option,