Skip to content

Commit 221e9c2

Browse files
authored
feat: Support SET NAMES literal [COLLATE literal] (apache#558)
* feat: Support SET NAMES literal [COLLATE literal] * feat: Support SET NAMES DEFAULT * clippy
1 parent aabafc9 commit 221e9c2

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

src/ast/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,17 @@ pub enum Statement {
992992
variable: ObjectName,
993993
value: Vec<SetVariableValue>,
994994
},
995+
/// SET NAMES 'charset_name' [COLLATE 'collation_name']
996+
///
997+
/// Note: this is a MySQL-specific statement.
998+
SetNames {
999+
charset_name: String,
1000+
collation_name: Option<String>,
1001+
},
1002+
/// SET NAMES DEFAULT
1003+
///
1004+
/// Note: this is a MySQL-specific statement.
1005+
SetNamesDefault {},
9951006
/// SHOW <variable>
9961007
///
9971008
/// Note: this is a PostgreSQL-specific statement.
@@ -1788,6 +1799,25 @@ impl fmt::Display for Statement {
17881799
value = display_comma_separated(value)
17891800
)
17901801
}
1802+
Statement::SetNames {
1803+
charset_name,
1804+
collation_name,
1805+
} => {
1806+
f.write_str("SET NAMES ")?;
1807+
f.write_str(charset_name)?;
1808+
1809+
if let Some(collation) = collation_name {
1810+
f.write_str(" COLLATE ")?;
1811+
f.write_str(collation)?;
1812+
};
1813+
1814+
Ok(())
1815+
}
1816+
Statement::SetNamesDefault {} => {
1817+
f.write_str("SET NAMES DEFAULT")?;
1818+
1819+
Ok(())
1820+
}
17911821
Statement::ShowVariable { variable } => {
17921822
write!(f, "SHOW")?;
17931823
if !variable.is_empty() {

src/parser.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3652,7 +3652,25 @@ impl<'a> Parser<'a> {
36523652
}
36533653

36543654
let variable = self.parse_object_name()?;
3655-
if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
3655+
if variable.to_string().eq_ignore_ascii_case("NAMES")
3656+
&& dialect_of!(self is MySqlDialect | GenericDialect)
3657+
{
3658+
if self.parse_keyword(Keyword::DEFAULT) {
3659+
return Ok(Statement::SetNamesDefault {});
3660+
}
3661+
3662+
let charset_name = self.parse_literal_string()?;
3663+
let collation_name = if self.parse_one_of_keywords(&[Keyword::COLLATE]).is_some() {
3664+
Some(self.parse_literal_string()?)
3665+
} else {
3666+
None
3667+
};
3668+
3669+
Ok(Statement::SetNames {
3670+
charset_name,
3671+
collation_name,
3672+
})
3673+
} else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
36563674
let mut values = vec![];
36573675
loop {
36583676
let token = self.peek_token();

tests/sqlparser_mysql.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,41 @@ fn parse_table_colum_option_on_update() {
890890
}
891891
}
892892

893+
#[test]
894+
fn parse_set_names() {
895+
let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4");
896+
assert_eq!(
897+
stmt,
898+
Statement::SetNames {
899+
charset_name: "utf8mb4".to_string(),
900+
collation_name: None,
901+
}
902+
);
903+
904+
let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4 COLLATE bogus");
905+
assert_eq!(
906+
stmt,
907+
Statement::SetNames {
908+
charset_name: "utf8mb4".to_string(),
909+
collation_name: Some("bogus".to_string()),
910+
}
911+
);
912+
913+
let stmt = mysql_and_generic()
914+
.parse_sql_statements("set names utf8mb4 collate bogus")
915+
.unwrap();
916+
assert_eq!(
917+
stmt,
918+
vec![Statement::SetNames {
919+
charset_name: "utf8mb4".to_string(),
920+
collation_name: Some("bogus".to_string()),
921+
}]
922+
);
923+
924+
let stmt = mysql_and_generic().verified_stmt("SET NAMES DEFAULT");
925+
assert_eq!(stmt, Statement::SetNamesDefault {});
926+
}
927+
893928
fn mysql() -> TestedDialects {
894929
TestedDialects {
895930
dialects: vec![Box::new(MySqlDialect {})],

0 commit comments

Comments
 (0)