Fix drop constraint unique pk#19420
Conversation
Signed-off-by: anshikavashistha <anshikav1534@gmail.com>
Signed-off-by: anshikavashistha <anshikav1534@gmail.com>
b5e808e to
ddad7a6
Compare
Signed-off-by: anshikavashistha <anshikav1534@gmail.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #19420 +/- ##
==========================================
+ Coverage 69.62% 69.73% +0.11%
==========================================
Files 1614 1614
Lines 216398 216870 +472
==========================================
+ Hits 150658 151235 +577
+ Misses 65740 65635 -105 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Signed-off-by: anshikavashistha <anshikav1534@gmail.com>
|
@mattlord ,please take a look. |
There was a problem hiding this comment.
You accidentally left this Go toolchain artifact.
There was a problem hiding this comment.
I have removed this file
| case *sqlparser.IndexDefinition: | ||
| // Handle named UNIQUE/PRIMARY KEY constraints stored in IndexInfo.ConstraintName | ||
| if node.Info.ConstraintName.String() != "" { | ||
| oldName := node.Info.ConstraintName.String() | ||
| // For CREATE TABLE, named UNIQUE/PRIMARY KEY constraints should just append "_" suffix | ||
| // (hash suffixing is only for specific OnlineDDL flows, not regular CREATE TABLE) | ||
| newName := oldName + "_" | ||
| node.Info.ConstraintName = sqlparser.NewIdentifierCI(newName) | ||
| constraintMap[oldName] = newName | ||
| } | ||
| } |
There was a problem hiding this comment.
I might be missing something, but why do we need this?
There was a problem hiding this comment.
Good catch on the inconsistency. Named UNIQUE/PRIMARY constraints stored in IndexInfo.ConstraintName are part of MySQL's schema-wide constraint namespace, so they do need renaming during table duplication — but you're right that "_" suffix is wrong here. I've updated this to use generateConstraintNameWithHash consistent with how FK/check constraints are handled.
go/vt/sqlparser/parser.go
Outdated
| b.WriteString(sql[start:]) | ||
| } | ||
| sql = b.String() | ||
| } |
There was a problem hiding this comment.
This logic is really brittle. It matches the substring anywhere, including inside string literals, comments, or DEFAULT values. For example, drop constraint primary_key would become invalid drop primary key_key.
Furthermore, DROP CONSTRAINT PRIMARY (unquoted) is not actually valid MySQL syntax. PRIMARY is a reserved keyword, not a constraint symbol. MySQL docs state that the type-specific form must be used for primary keys:
The SQL standard specifies that all types of constraints (primary key, unique index, foreign key, check) belong to the same namespace. In MySQL, each constraint type has its own namespace per schema. Consequently, names for each type of constraint must be unique per schema, but constraints of different types can have the same name. When multiple constraints have the same name, DROP CONSTRAINT and ADD CONSTRAINT are ambiguous and an error occurs. In such cases, constraint-specific syntax must be used to modify the constraint. For example, use DROP PRIMARY KEY or DROP FOREIGN KEY to drop a primary key or foreign key.
I suggest we drop this logic and any related logic. Was there a reason this was added in the first place? Am I missing some Vitess-specific behavior that requires this? In the case we would need this, it would better fit in the grammar and not as string replacements.
There was a problem hiding this comment.
You're absolutely right — the substring rewrite in parser.go was brittle and DROP CONSTRAINT PRIMARY is not valid MySQL syntax at the parser level.
I've removed the entire pre-parse string replacement block from parser.go and reverted ParseStrictDDL to its original state.
| case sqlparser.ConstraintType: | ||
| // ConstraintType can refer to any constraint type: foreign key, check, or named UNIQUE/PRIMARY KEY | ||
| // First check TableSpec.Constraints for foreign keys and check constraints | ||
| for i, constraint := range c.TableSpec.Constraints { | ||
| if strings.EqualFold(constraint.Name.String(), opt.Name.String()) { | ||
| found = true | ||
| c.TableSpec.Constraints = append(c.TableSpec.Constraints[0:i], c.TableSpec.Constraints[i+1:]...) | ||
| break | ||
| } | ||
| } | ||
| // If not found in Constraints, check TableSpec.Indexes for named UNIQUE/PRIMARY KEY constraints | ||
| if !found { | ||
| for i, index := range c.TableSpec.Indexes { | ||
| // Only match UNIQUE or PRIMARY KEY indexes | ||
| if index.Info.Type != sqlparser.IndexTypeUnique && index.Info.Type != sqlparser.IndexTypePrimary { | ||
| continue | ||
| } | ||
| // Prefer matching on ConstraintName when present | ||
| if index.Info.ConstraintName.String() != "" && | ||
| strings.EqualFold(index.Info.ConstraintName.String(), opt.Name.String()) { | ||
| found = true | ||
| c.TableSpec.Indexes = append(c.TableSpec.Indexes[0:i], c.TableSpec.Indexes[i+1:]...) | ||
| break | ||
| } | ||
| // Fallback: allow DROP CONSTRAINT <name> to target a UNIQUE KEY defined without the CONSTRAINT | ||
| // keyword (i.e. created via `UNIQUE KEY uk_name (...)`). In that case ConstraintName is empty | ||
| // and the index is identified by its Name. | ||
| if index.Info.ConstraintName.String() == "" && | ||
| strings.EqualFold(index.Info.Name.String(), opt.Name.String()) { | ||
| found = true | ||
| c.TableSpec.Indexes = append(c.TableSpec.Indexes[0:i], c.TableSpec.Indexes[i+1:]...) | ||
| break | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
This may not needed right now, but MySQL returns an error when multiple constraints have the same name (when using DROP CONSTRAINT). We should likely match that behavior.
Signed-off-by: anshikavashistha <anshikav1534@gmail.com>
34974f8 to
07209a3
Compare
…on case Signed-off-by: anshikavashistha <anshikav1534@gmail.com>
Signed-off-by: anshikavashistha <anshikav1534@gmail.com>
8e3e0cd to
55a8252
Compare
Signed-off-by: anshikavashistha <93611566+anshikavashistha@users.noreply.github.com>
Summary
This PR extends the
ALTER TABLE ... DROP CONSTRAINT <name>support in Vitess to correctly handle the dropping of named PRIMARY KEY and UNIQUE constraints, aligning with MySQL 8.0.19+ behavior.Previously, PR #19183 added support for dropping FOREIGN KEY and CHECK constraints using named constraints, but did not handle named UNIQUE and PRIMARY KEY constraints.
The root cause was that DROP CONSTRAINT logic only searched TableSpec.Constraints. However, named UNIQUE and PRIMARY KEY constraints are stored in TableSpec.Indexes under IndexDefinition.ConstraintName.
With this change, users can now drop explicitly named PRIMARY KEY or UNIQUE constraints using standard
ALTER TABLE ... DROP CONSTRAINT <name>syntax, matching MySQL behavior.What changed?
Related Issue(s)
Fixes #19232
Checklist
Deployment Notes
None.