Skip to content

Commit 06c68ff

Browse files
committed
Parse SET NAMES syntax
1 parent ed41654 commit 06c68ff

File tree

8 files changed

+39
-12
lines changed

8 files changed

+39
-12
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

+4
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,8 @@ 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+
}
158162
}

src/dialect/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,16 @@ 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> [COLLATE <collation_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+
///
962+
/// Note: Postgres doesn't support the `COLLATE` clause, but we permissively parse it anyway.
963+
fn supports_set_names(&self) -> bool {
964+
false
965+
}
956966
}
957967

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

src/dialect/mysql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ 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+
}
136140
}
137141

138142
/// `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

+4-4
Original file line numberDiff line numberDiff line change
@@ -10962,14 +10962,14 @@ 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()?;
10972+
let charset_name = self.parse_identifier()?;
1097310973
let collation_name = if self.parse_one_of_keywords(&[Keyword::COLLATE]).is_some() {
1097410974
Some(self.parse_literal_string()?)
1097510975
} else {

tests/sqlparser_common.rs

+8
Original file line numberDiff line numberDiff line change
@@ -14617,3 +14617,11 @@ fn parse_array_type_def_with_brackets() {
1461714617
dialects.verified_stmt("SELECT x::INT[]");
1461814618
dialects.verified_stmt("SELECT STRING_TO_ARRAY('1,2,3', ',')::INT[3]");
1461914619
}
14620+
14621+
#[test]
14622+
fn parse_set_names() {
14623+
let dialects = all_dialects_where(|d| d.supports_set_names());
14624+
dialects.verified_stmt("SET NAMES 'UTF8'");
14625+
dialects.verified_stmt("SET NAMES 'utf8'");
14626+
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
14627+
}

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
);

0 commit comments

Comments
 (0)