fix(MySQL): combine the drop and the creation of an index over the same columns - #7475
Merged
morozov merged 4 commits intoAug 10, 2026
Merged
Conversation
…me columns
When an index is dropped and another one over the same columns is added,
AbstractMySQLPlatform combines both into a single ALTER TABLE statement,
so that the columns are never left unindexed. It compares the two column
lists through the legacy Index::getColumns() accessor, which returns the
raw map keys: the introspection API marks them as quoted ('"parent_id"'),
while an index built in memory keeps them bare ('parent_id'). The two
lists therefore never match when the dropped index comes from an
introspected table, the statements are not combined, and the drop is
emitted on its own.
That makes the alteration fail whenever the dropped index is the one
backing a foreign key: InnoDB rejects the drop with "Cannot drop index
'X': needed in a foreign key constraint" (which disabling
foreign_key_checks does not lift), even though the added index would
provide the same cover.
Read the column names through the non-deprecated
Index::getIndexedColumns() accessor and compare their unquoted identifier
values, so the comparison is agnostic of whether the index was
introspected or built in memory, as done in doctrine#7392 for the same accessor
in the SQLite table-recreation path.
Signed-off-by: Fabrizio Balliano <fabrizio.balliano@gmail.com>
morozov
reviewed
Aug 1, 2026
morozov
left a comment
Member
There was a problem hiding this comment.
@fballiano thank you for the patch. Please see inline comments.
…make the test platform-agnostic The dropped and added index columns are now compared pairwise through UnqualifiedName::equals() with the platform's unquoted-identifier folding, instead of comparing extracted values. The test moves to SchemaManagerTest and builds the tables through the editor API, with no platform-specific SQL. The unique index spans exactly the referencing column of the foreign key, so that no implicit index is created and the unique index remains the only cover of the constraint: with an extra covering index, InnoDB would allow the uncombined drop and the test would pass even without the fix. Verified failing with error 1553 on MySQL without the fix. Signed-off-by: Fabrizio Balliano <fabrizio.balliano@gmail.com>
Contributor
Author
|
Hi @morozov, thank you for the review and sorry for the mistakes, I've rewritten the whole thing with your suggestions, let's see if CI agrees. 🙏 |
morozov
reviewed
Aug 1, 2026
Index::getIndexedColumns() throws InvalidState on an index without valid columns, which would be a behavior break in 4.x. Compare the lists returned by Index::getUnquotedColumns() instead, as done in the SQLite table-recreation path. Signed-off-by: Fabrizio Balliano <fabrizio.balliano@gmail.com>
Signed-off-by: Fabrizio Balliano <fabrizio.balliano@gmail.com>
Contributor
Author
|
it was so easy 🤦🏻 sorry 😅 |
morozov
approved these changes
Aug 10, 2026
Member
|
Merged. Thanks, @fballiano! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AbstractMySQLPlatformcombines the drop of an index and the creation of another one over the same columns into a singleALTER TABLE ... DROP INDEX a, ADD INDEX b (...)statement, so that the columns are never left unindexed in between. The two column lists are compared through the legacyIndex::getColumns()accessor, which returns the raw map keys: the introspection API marks them as quoted ('"parent_id"'), while an index built in memory keeps them bare ('parent_id'). They therefore never match when the dropped index comes from an introspected table, the statements are not combined, and the drop is emitted on its own.That makes
alterTable()fail whenever the dropped index is the one backing a foreign key. InnoDB rejects the drop even though the added index would provide the same cover, and disablingforeign_key_checksdoes not lift the restriction:Emitted before the fix, where the drop runs on its own and never reaches the creation:
and after:
Fix
Read the column names through the non-deprecated
Index::getIndexedColumns()accessor and compare their unquoted identifier values, so the comparison is agnostic of whether the index was introspected or built in memory. This is the same treatment #7392 applied to the same accessor in the SQLite table-recreation path.The regression test goes to
MySQLSchemaManagerTest: the combining is MySQL-specific, and so is the foreign-key index requirement that makes the uncombined form fail. It errors with 1553 on4.4.xand passes with the fix.