diff --git a/src/Platforms/AbstractMySQLPlatform.php b/src/Platforms/AbstractMySQLPlatform.php index 04e903f397..529d9441a8 100644 --- a/src/Platforms/AbstractMySQLPlatform.php +++ b/src/Platforms/AbstractMySQLPlatform.php @@ -467,7 +467,7 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff): array $sql = array_merge($sql, $this->getPreAlterTableAlterPrimaryKeySQL($diff, $droppedIndex)); foreach ($diff->getAddedIndexes() as $addedIndex) { - if ($droppedIndex->getColumns() !== $addedIndex->getColumns()) { + if ($droppedIndex->getUnquotedColumns() !== $addedIndex->getUnquotedColumns()) { continue; } diff --git a/tests/Functional/Schema/SchemaManagerTest.php b/tests/Functional/Schema/SchemaManagerTest.php index 4981ae00ac..8711a71198 100644 --- a/tests/Functional/Schema/SchemaManagerTest.php +++ b/tests/Functional/Schema/SchemaManagerTest.php @@ -505,6 +505,87 @@ public function testDropForeignKey(): void ); } + public function testReplaceIndexBackingForeignKey(): void + { + $this->dropTableIfExists('index_replacement_child'); + $this->dropTableIfExists('index_replacement_parent'); + + $parentTable = Table::editor() + ->setUnquotedName('index_replacement_parent') + ->setColumns( + Column::editor() + ->setUnquotedName('id') + ->setTypeName(Types::INTEGER) + ->create(), + ) + ->setPrimaryKeyConstraint( + PrimaryKeyConstraint::editor() + ->setUnquotedColumnNames('id') + ->create(), + ) + ->create(); + + // The unique index spans exactly the referencing column of the foreign key, so no implicit + // index is created, and it remains the only index covering the constraint. On MySQL, InnoDB + // refuses to drop such an index unless another index takes over the cover in the same + // ALTER TABLE statement. + $childTable = Table::editor() + ->setUnquotedName('index_replacement_child') + ->setColumns( + Column::editor() + ->setUnquotedName('id') + ->setTypeName(Types::INTEGER) + ->create(), + Column::editor() + ->setUnquotedName('parent_id') + ->setTypeName(Types::INTEGER) + ->create(), + ) + ->setPrimaryKeyConstraint( + PrimaryKeyConstraint::editor() + ->setUnquotedColumnNames('id') + ->create(), + ) + ->setIndexes( + Index::editor() + ->setUnquotedName('uniq_parent_id') + ->setUnquotedColumnNames('parent_id') + ->setType(IndexType::UNIQUE) + ->create(), + ) + ->setForeignKeyConstraints( + ForeignKeyConstraint::editor() + ->setUnquotedName('fk_index_replacement') + ->setUnquotedReferencingColumnNames('parent_id') + ->setUnquotedReferencedTableName('index_replacement_parent') + ->setUnquotedReferencedColumnNames('id') + ->create(), + ) + ->create(); + + $this->schemaManager->createTable($parentTable); + $this->schemaManager->createTable($childTable); + + $oldTable = $this->schemaManager->introspectTableByUnquotedName('index_replacement_child'); + + $newIndex = Index::editor() + ->setUnquotedName('idx_parent_id') + ->setUnquotedColumnNames('parent_id') + ->create(); + + $newTable = $oldTable->edit() + ->setIndexes($newIndex) + ->create(); + + $diff = $this->schemaManager->createComparator()->compareTables($oldTable, $newTable); + $this->schemaManager->alterTable($diff); + + $table = $this->schemaManager->introspectTableByUnquotedName('index_replacement_child'); + + self::assertFalse($table->hasIndex('uniq_parent_id')); + $this->assertIndexEquals($newIndex, $table->getIndex('idx_parent_id')); + } + /** @param callable(AbstractSchemaManager): list $introspect */ #[DataProvider('quotedAndUnquotedIndexIntrospection')] public function testIntrospectTableIndexes(