diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 97b647bc9..86c0f2e92 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -992,6 +992,17 @@ pub enum Statement { variable: ObjectName, value: Vec, }, + /// SET NAMES 'charset_name' [COLLATE 'collation_name'] + /// + /// Note: this is a MySQL-specific statement. + SetNames { + charset_name: String, + collation_name: Option, + }, + /// SET NAMES DEFAULT + /// + /// Note: this is a MySQL-specific statement. + SetNamesDefault {}, /// SHOW /// /// Note: this is a PostgreSQL-specific statement. @@ -1788,6 +1799,25 @@ impl fmt::Display for Statement { value = display_comma_separated(value) ) } + Statement::SetNames { + charset_name, + collation_name, + } => { + f.write_str("SET NAMES ")?; + f.write_str(charset_name)?; + + if let Some(collation) = collation_name { + f.write_str(" COLLATE ")?; + f.write_str(collation)?; + }; + + Ok(()) + } + Statement::SetNamesDefault {} => { + f.write_str("SET NAMES DEFAULT")?; + + Ok(()) + } Statement::ShowVariable { variable } => { write!(f, "SHOW")?; if !variable.is_empty() { diff --git a/src/parser.rs b/src/parser.rs index 50f8a2d53..5bea35e79 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3652,7 +3652,25 @@ impl<'a> Parser<'a> { } let variable = self.parse_object_name()?; - if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) { + if variable.to_string().eq_ignore_ascii_case("NAMES") + && dialect_of!(self is MySqlDialect | GenericDialect) + { + if self.parse_keyword(Keyword::DEFAULT) { + return Ok(Statement::SetNamesDefault {}); + } + + let charset_name = self.parse_literal_string()?; + let collation_name = if self.parse_one_of_keywords(&[Keyword::COLLATE]).is_some() { + Some(self.parse_literal_string()?) + } else { + None + }; + + Ok(Statement::SetNames { + charset_name, + collation_name, + }) + } else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) { let mut values = vec![]; loop { let token = self.peek_token(); diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index ab28b879b..a514b1e8e 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -890,6 +890,41 @@ fn parse_table_colum_option_on_update() { } } +#[test] +fn parse_set_names() { + let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4"); + assert_eq!( + stmt, + Statement::SetNames { + charset_name: "utf8mb4".to_string(), + collation_name: None, + } + ); + + let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4 COLLATE bogus"); + assert_eq!( + stmt, + Statement::SetNames { + charset_name: "utf8mb4".to_string(), + collation_name: Some("bogus".to_string()), + } + ); + + let stmt = mysql_and_generic() + .parse_sql_statements("set names utf8mb4 collate bogus") + .unwrap(); + assert_eq!( + stmt, + vec![Statement::SetNames { + charset_name: "utf8mb4".to_string(), + collation_name: Some("bogus".to_string()), + }] + ); + + let stmt = mysql_and_generic().verified_stmt("SET NAMES DEFAULT"); + assert_eq!(stmt, Statement::SetNamesDefault {}); +} + fn mysql() -> TestedDialects { TestedDialects { dialects: vec![Box::new(MySqlDialect {})],