Skip to content

Commit cb21477

Browse files
authored
MySQL: Allow optional constraint name after CONSTRAINT keyword (#2183)
1 parent d7f56e8 commit cb21477

File tree

5 files changed

+61
-1
lines changed

5 files changed

+61
-1
lines changed

src/dialect/generic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,4 +275,8 @@ impl Dialect for GenericDialect {
275275
fn supports_comment_optimizer_hint(&self) -> bool {
276276
true
277277
}
278+
279+
fn supports_constraint_keyword_without_name(&self) -> bool {
280+
true
281+
}
278282
}

src/dialect/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,23 @@ pub trait Dialect: Debug + Any {
11691169
false
11701170
}
11711171

1172+
/// Returns true if the dialect supports the `CONSTRAINT` keyword without a name
1173+
/// in table constraint definitions.
1174+
///
1175+
/// Example:
1176+
/// ```sql
1177+
/// CREATE TABLE t (a INT, CONSTRAINT CHECK (a > 0))
1178+
/// ```
1179+
///
1180+
/// This is a MySQL extension; the SQL standard requires a name after `CONSTRAINT`.
1181+
/// When the name is omitted, the output normalizes to just the constraint type
1182+
/// without the `CONSTRAINT` keyword (e.g., `CHECK (a > 0)`).
1183+
///
1184+
/// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
1185+
fn supports_constraint_keyword_without_name(&self) -> bool {
1186+
false
1187+
}
1188+
11721189
/// Returns true if the specified keyword is reserved and cannot be
11731190
/// used as an identifier without special handling like quoting.
11741191
fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {

src/dialect/mysql.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ impl Dialect for MySqlDialect {
190190
fn supports_comment_optimizer_hint(&self) -> bool {
191191
true
192192
}
193+
194+
/// See: <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
195+
fn supports_constraint_keyword_without_name(&self) -> bool {
196+
true
197+
}
193198
}
194199

195200
/// `LOCK TABLES`

src/parser/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9293,7 +9293,20 @@ impl<'a> Parser<'a> {
92939293
&mut self,
92949294
) -> Result<Option<TableConstraint>, ParserError> {
92959295
let name = if self.parse_keyword(Keyword::CONSTRAINT) {
9296-
Some(self.parse_identifier()?)
9296+
if self.dialect.supports_constraint_keyword_without_name()
9297+
&& self
9298+
.peek_one_of_keywords(&[
9299+
Keyword::CHECK,
9300+
Keyword::PRIMARY,
9301+
Keyword::UNIQUE,
9302+
Keyword::FOREIGN,
9303+
])
9304+
.is_some()
9305+
{
9306+
None
9307+
} else {
9308+
Some(self.parse_identifier()?)
9309+
}
92979310
} else {
92989311
None
92999312
};

tests/sqlparser_mysql.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3469,6 +3469,27 @@ fn parse_create_table_unallow_constraint_then_index() {
34693469
assert!(mysql_and_generic().parse_sql_statements(sql).is_ok());
34703470
}
34713471

3472+
#[test]
3473+
fn parse_create_table_constraint_check_without_name() {
3474+
let dialects = all_dialects_where(|d| d.supports_constraint_keyword_without_name());
3475+
dialects.one_statement_parses_to(
3476+
"CREATE TABLE t (x INT, CONSTRAINT PRIMARY KEY (x))",
3477+
"CREATE TABLE t (x INT, PRIMARY KEY (x))",
3478+
);
3479+
dialects.one_statement_parses_to(
3480+
"CREATE TABLE t (x INT, CONSTRAINT UNIQUE (x))",
3481+
"CREATE TABLE t (x INT, UNIQUE (x))",
3482+
);
3483+
dialects.one_statement_parses_to(
3484+
"CREATE TABLE t (x INT, CONSTRAINT FOREIGN KEY (x) REFERENCES t2(id))",
3485+
"CREATE TABLE t (x INT, FOREIGN KEY (x) REFERENCES t2(id))",
3486+
);
3487+
dialects.one_statement_parses_to(
3488+
"CREATE TABLE t (x INT, CONSTRAINT CHECK (x > 1))",
3489+
"CREATE TABLE t (x INT, CHECK (x > 1))",
3490+
);
3491+
}
3492+
34723493
#[test]
34733494
fn parse_create_table_with_fulltext_definition() {
34743495
mysql_and_generic().verified_stmt("CREATE TABLE tb (id INT, FULLTEXT (id))");

0 commit comments

Comments
 (0)