Skip to content

Commit

Permalink
feat: Support SET NAMES literal [COLLATE literal] (#558)
Browse files Browse the repository at this point in the history
* feat: Support SET NAMES literal [COLLATE literal]

* feat: Support SET NAMES DEFAULT

* clippy
  • Loading branch information
ovr committed Aug 11, 2022
1 parent aabafc9 commit 221e9c2
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
30 changes: 30 additions & 0 deletions src/ast/mod.rs
Expand Up @@ -992,6 +992,17 @@ pub enum Statement {
variable: ObjectName,
value: Vec<SetVariableValue>,
},
/// SET NAMES 'charset_name' [COLLATE 'collation_name']
///
/// Note: this is a MySQL-specific statement.
SetNames {
charset_name: String,
collation_name: Option<String>,
},
/// SET NAMES DEFAULT
///
/// Note: this is a MySQL-specific statement.
SetNamesDefault {},
/// SHOW <variable>
///
/// Note: this is a PostgreSQL-specific statement.
Expand Down Expand Up @@ -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() {
Expand Down
20 changes: 19 additions & 1 deletion src/parser.rs
Expand Up @@ -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();
Expand Down
35 changes: 35 additions & 0 deletions tests/sqlparser_mysql.rs
Expand Up @@ -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 {})],
Expand Down

0 comments on commit 221e9c2

Please sign in to comment.