Skip to content

Commit c71f5c4

Browse files
committed
Parse SET NAMES syntax
1 parent ed41654 commit c71f5c4

File tree

8 files changed

+55
-13
lines changed

8 files changed

+55
-13
lines changed

src/ast/mod.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -2956,10 +2956,8 @@ pub enum Statement {
29562956
/// ```sql
29572957
/// SET NAMES 'charset_name' [COLLATE 'collation_name']
29582958
/// ```
2959-
///
2960-
/// Note: this is a MySQL-specific statement.
29612959
SetNames {
2962-
charset_name: String,
2960+
charset_name: Ident,
29632961
collation_name: Option<String>,
29642962
},
29652963
/// ```sql
@@ -4684,8 +4682,7 @@ impl fmt::Display for Statement {
46844682
charset_name,
46854683
collation_name,
46864684
} => {
4687-
f.write_str("SET NAMES ")?;
4688-
f.write_str(charset_name)?;
4685+
write!(f, "SET NAMES {}", charset_name)?;
46894686

46904687
if let Some(collation) = collation_name {
46914688
f.write_str(" COLLATE ")?;

src/dialect/generic.rs

+8
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,12 @@ impl Dialect for GenericDialect {
155155
fn supports_match_against(&self) -> bool {
156156
true
157157
}
158+
159+
fn supports_set_names(&self) -> bool {
160+
true
161+
}
162+
163+
fn supports_set_names_collation(&self) -> bool {
164+
true
165+
}
158166
}

src/dialect/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,21 @@ pub trait Dialect: Debug + Any {
953953
fn supports_order_by_all(&self) -> bool {
954954
false
955955
}
956+
957+
/// Returns true if the dialect supports `SET NAMES <charset_name>`.
958+
///
959+
/// - [MySQL](https://dev.mysql.com/doc/refman/8.4/en/set-names.html)
960+
/// - [Postgres](https://www.postgresql.org/docs/17/sql-set.html)
961+
fn supports_set_names(&self) -> bool {
962+
false
963+
}
964+
965+
/// Returns true if the dialect supports `SET NAMES <charset_name> [COLLATE <collation_name>]`.
966+
///
967+
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/set-names.html)
968+
fn supports_set_names_collation(&self) -> bool {
969+
false
970+
}
956971
}
957972

958973
/// This represents the operators for which precedence must be defined

src/dialect/mysql.rs

+8
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ impl Dialect for MySqlDialect {
133133
fn supports_match_against(&self) -> bool {
134134
true
135135
}
136+
137+
fn supports_set_names(&self) -> bool {
138+
true
139+
}
140+
141+
fn supports_set_names_collation(&self) -> bool {
142+
true
143+
}
136144
}
137145

138146
/// `LOCK TABLES`

src/dialect/postgresql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,8 @@ impl Dialect for PostgreSqlDialect {
254254
fn supports_geometric_types(&self) -> bool {
255255
true
256256
}
257+
258+
fn supports_set_names(&self) -> bool {
259+
true
260+
}
257261
}

src/parser/mod.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -10962,15 +10962,17 @@ impl<'a> Parser<'a> {
1096210962
OneOrManyWithParens::One(self.parse_object_name(false)?)
1096310963
};
1096410964

10965-
if matches!(&variables, OneOrManyWithParens::One(variable) if variable.to_string().eq_ignore_ascii_case("NAMES")
10966-
&& dialect_of!(self is MySqlDialect | GenericDialect))
10967-
{
10965+
let names = matches!(&variables, OneOrManyWithParens::One(variable) if variable.to_string().eq_ignore_ascii_case("NAMES"));
10966+
10967+
if names && self.dialect.supports_set_names() {
1096810968
if self.parse_keyword(Keyword::DEFAULT) {
1096910969
return Ok(Statement::SetNamesDefault {});
1097010970
}
1097110971

10972-
let charset_name = self.parse_literal_string()?;
10973-
let collation_name = if self.parse_one_of_keywords(&[Keyword::COLLATE]).is_some() {
10972+
let charset_name = self.parse_identifier()?;
10973+
let collation_name = if self.dialect.supports_set_names_collation()
10974+
&& self.parse_one_of_keywords(&[Keyword::COLLATE]).is_some()
10975+
{
1097410976
Some(self.parse_literal_string()?)
1097510977
} else {
1097610978
None

tests/sqlparser_mysql.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2685,7 +2685,7 @@ fn parse_set_names() {
26852685
assert_eq!(
26862686
stmt,
26872687
Statement::SetNames {
2688-
charset_name: "utf8mb4".to_string(),
2688+
charset_name: "utf8mb4".into(),
26892689
collation_name: None,
26902690
}
26912691
);
@@ -2694,7 +2694,7 @@ fn parse_set_names() {
26942694
assert_eq!(
26952695
stmt,
26962696
Statement::SetNames {
2697-
charset_name: "utf8mb4".to_string(),
2697+
charset_name: "utf8mb4".into(),
26982698
collation_name: Some("bogus".to_string()),
26992699
}
27002700
);
@@ -2705,7 +2705,7 @@ fn parse_set_names() {
27052705
assert_eq!(
27062706
stmt,
27072707
vec![Statement::SetNames {
2708-
charset_name: "utf8mb4".to_string(),
2708+
charset_name: "utf8mb4".into(),
27092709
collation_name: Some("bogus".to_string()),
27102710
}]
27112711
);

tests/sqlparser_postgres.rs

+8
Original file line numberDiff line numberDiff line change
@@ -5533,3 +5533,11 @@ fn parse_varbit_datatype() {
55335533
_ => unreachable!(),
55345534
}
55355535
}
5536+
5537+
#[test]
5538+
fn parse_set_names() {
5539+
pg_and_generic().verified_stmt("SET NAMES 'UTF8'");
5540+
pg_and_generic().verified_stmt("SET NAMES 'utf8'");
5541+
pg().parse_sql_statements("SET NAMES 'UTF8' COLLATE bogus")
5542+
.expect_err("Postgres does not support COLLATE");
5543+
}

0 commit comments

Comments
 (0)