Skip to content

Commit 46b3989

Browse files
mvzinkQuenKar
authored andcommitted
Parse SET NAMES syntax in Postgres (apache#1752)
1 parent f38d2de commit 46b3989

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
@@ -2957,10 +2957,8 @@ pub enum Statement {
29572957
/// ```sql
29582958
/// SET NAMES 'charset_name' [COLLATE 'collation_name']
29592959
/// ```
2960-
///
2961-
/// Note: this is a MySQL-specific statement.
29622960
SetNames {
2963-
charset_name: String,
2961+
charset_name: Ident,
29642962
collation_name: Option<String>,
29652963
},
29662964
/// ```sql
@@ -4685,8 +4683,7 @@ impl fmt::Display for Statement {
46854683
charset_name,
46864684
collation_name,
46874685
} => {
4688-
f.write_str("SET NAMES ")?;
4689-
f.write_str(charset_name)?;
4686+
write!(f, "SET NAMES {}", charset_name)?;
46904687

46914688
if let Some(collation) = collation_name {
46924689
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
@@ -980,6 +980,16 @@ pub trait Dialect: Debug + Any {
980980
fn supports_order_by_all(&self) -> bool {
981981
false
982982
}
983+
984+
/// Returns true if the dialect supports `SET NAMES <charset_name> [COLLATE <collation_name>]`.
985+
///
986+
/// - [MySQL](https://dev.mysql.com/doc/refman/8.4/en/set-names.html)
987+
/// - [Postgres](https://www.postgresql.org/docs/17/sql-set.html)
988+
///
989+
/// Note: Postgres doesn't support the `COLLATE` clause, but we permissively parse it anyway.
990+
fn supports_set_names(&self) -> bool {
991+
false
992+
}
983993
}
984994

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

src/dialect/mysql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ impl Dialect for MySqlDialect {
137137
fn supports_match_against(&self) -> bool {
138138
true
139139
}
140+
141+
fn supports_set_names(&self) -> bool {
142+
true
143+
}
140144
}
141145

142146
/// `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
@@ -14631,3 +14631,11 @@ fn parse_array_type_def_with_brackets() {
1463114631
dialects.verified_stmt("SELECT x::INT[]");
1463214632
dialects.verified_stmt("SELECT STRING_TO_ARRAY('1,2,3', ',')::INT[3]");
1463314633
}
14634+
14635+
#[test]
14636+
fn parse_set_names() {
14637+
let dialects = all_dialects_where(|d| d.supports_set_names());
14638+
dialects.verified_stmt("SET NAMES 'UTF8'");
14639+
dialects.verified_stmt("SET NAMES 'utf8'");
14640+
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
14641+
}

tests/sqlparser_mysql.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2696,7 +2696,7 @@ fn parse_set_names() {
26962696
assert_eq!(
26972697
stmt,
26982698
Statement::SetNames {
2699-
charset_name: "utf8mb4".to_string(),
2699+
charset_name: "utf8mb4".into(),
27002700
collation_name: None,
27012701
}
27022702
);
@@ -2705,7 +2705,7 @@ fn parse_set_names() {
27052705
assert_eq!(
27062706
stmt,
27072707
Statement::SetNames {
2708-
charset_name: "utf8mb4".to_string(),
2708+
charset_name: "utf8mb4".into(),
27092709
collation_name: Some("bogus".to_string()),
27102710
}
27112711
);
@@ -2716,7 +2716,7 @@ fn parse_set_names() {
27162716
assert_eq!(
27172717
stmt,
27182718
vec![Statement::SetNames {
2719-
charset_name: "utf8mb4".to_string(),
2719+
charset_name: "utf8mb4".into(),
27202720
collation_name: Some("bogus".to_string()),
27212721
}]
27222722
);

0 commit comments

Comments
 (0)