From b97971b4de0eab08540bc847a6b7e2f0e83bb113 Mon Sep 17 00:00:00 2001 From: Fabrizio Balliano Date: Wed, 10 Jun 2026 08:50:47 +0100 Subject: [PATCH 1/4] fix(SQLite): preserve indexes and foreign keys when altering an introspected table The table-recreation path maps index and foreign-key columns to the altered table through getDiffColumnNameMap(), which is keyed by the bare column names (Column::getName()). The index and foreign-key column accessors of an introspected table return the names in their quoted form ('"sku"'), so every map lookup missed and the branch meant to drop indexes referencing dropped columns silently dropped every index and foreign key of the table instead. Unquote the column names before the lookup, so only indexes and foreign keys whose columns were actually dropped are removed. Signed-off-by: Fabrizio Balliano --- src/Platforms/SQLitePlatform.php | 6 ++ .../Schema/SQLiteSchemaManagerTest.php | 63 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/Platforms/SQLitePlatform.php b/src/Platforms/SQLitePlatform.php index 6fcce9a285a..c854577f0ad 100644 --- a/src/Platforms/SQLitePlatform.php +++ b/src/Platforms/SQLitePlatform.php @@ -837,6 +837,9 @@ private function getIndexesInAlteredTable(TableDiff $diff): array $changed = false; $indexColumns = []; foreach ($index->getColumns() as $columnName) { + // the column names of an introspected index are quoted while the name map is keyed + // by the unquoted column names, so unquote before the lookup + $columnName = (new Identifier($columnName))->getName(); $normalizedColumnName = strtolower($columnName); if (! isset($nameMap[$normalizedColumnName])) { unset($indexes[$key]); @@ -904,6 +907,9 @@ private function getForeignKeysInAlteredTable(TableDiff $diff): array $changed = false; $localColumns = []; foreach ($constraint->getLocalColumns() as $columnName) { + // the referencing column names of an introspected foreign key constraint are quoted + // while the name map is keyed by the unquoted column names, so unquote before the lookup + $columnName = (new Identifier($columnName))->getName(); $normalizedColumnName = strtolower($columnName); if (! isset($nameMap[$normalizedColumnName])) { unset($foreignKeys[$key]); diff --git a/tests/Functional/Schema/SQLiteSchemaManagerTest.php b/tests/Functional/Schema/SQLiteSchemaManagerTest.php index a101fd8835c..edc708c2b7e 100644 --- a/tests/Functional/Schema/SQLiteSchemaManagerTest.php +++ b/tests/Functional/Schema/SQLiteSchemaManagerTest.php @@ -9,8 +9,10 @@ use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\ColumnDiff; +use Doctrine\DBAL\Schema\ColumnEditor; use Doctrine\DBAL\Schema\ForeignKeyConstraint; use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Index\IndexedColumn; use Doctrine\DBAL\Schema\Name\UnqualifiedName; use Doctrine\DBAL\Schema\PrimaryKeyConstraint; use Doctrine\DBAL\Schema\SQLiteSchemaManager; @@ -26,6 +28,7 @@ use function array_shift; use function array_values; use function assert; +use function ksort; class SQLiteSchemaManagerTest extends SchemaManagerFunctionalTestCase { @@ -316,6 +319,66 @@ public function testNonSimpleAlterTableCreatedFromDDL(): void self::assertSame(['name'], $index->getColumns()); } + public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void + { + $this->dropTableIfExists('tree_nodes'); + + $ddl = <<<'DDL' + CREATE TABLE tree_nodes ( + id INTEGER NOT NULL, + parent_id INTEGER, + name TEXT, + weight INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (parent_id) REFERENCES tree_nodes (id) + ) + DDL; + + $this->connection->executeStatement($ddl); + $this->connection->executeStatement('CREATE UNIQUE INDEX idx_tree_name ON tree_nodes (name)'); + $this->connection->executeStatement('CREATE INDEX idx_tree_parent ON tree_nodes (parent_id)'); + + $schemaManager = $this->connection->createSchemaManager(); + + $oldTable = $schemaManager->introspectTableByUnquotedName('tree_nodes'); + $newTable = $oldTable->edit() + ->modifyColumnByUnquotedName( + 'weight', + static function (ColumnEditor $editor): void { + $editor->setTypeName(Types::STRING) + ->setLength(32); + }, + ) + ->create(); + + $diff = $schemaManager->createComparator()->compareTables($oldTable, $newTable); + $schemaManager->alterTable($diff); + + $table = $schemaManager->introspectTableByUnquotedName('tree_nodes'); + + self::assertCount(1, $table->getForeignKeys()); + + $indexes = []; + foreach ($table->getIndexes() as $index) { + $indexName = $index->getObjectName()->getIdentifier()->getValue(); + if ($indexName === 'primary') { + continue; + } + + $indexes[$indexName] = array_map( + static fn (IndexedColumn $indexedColumn): string => $indexedColumn + ->getColumnName() + ->getIdentifier() + ->getValue(), + $index->getIndexedColumns(), + ); + } + + ksort($indexes); + + self::assertSame(['idx_tree_name' => ['name'], 'idx_tree_parent' => ['parent_id']], $indexes); + } + public function testAlterTableWithSchema(): void { $this->dropTableIfExists('t'); From a03a27d37a826b97a785d4e8b8817fd450485154 Mon Sep 17 00:00:00 2001 From: Fabrizio Balliano Date: Wed, 10 Jun 2026 17:01:03 +0100 Subject: [PATCH 2/4] fix(SQLite): preserve indexes and foreign keys when altering an introspected table When the altered table is obtained through the introspection API, its index and foreign-key column names are marked as quoted, so the legacy Index::getColumns() / ForeignKeyConstraint::getLocalColumns() accessors return them in quoted form ('"sku"'). The SQLite table-recreation path maps those columns to the altered table through getDiffColumnNameMap(), which is keyed by the unquoted column names, so every lookup missed and the branch meant to drop indexes referencing dropped columns silently dropped every index and foreign key (and the primary key) of the table instead. Read the referencing column names through the non-deprecated Index::getIndexedColumns() and ForeignKeyConstraint::getReferencingColumnNames() accessors and compare their unquoted identifier values, so the lookup is agnostic of whether the table was introspected or built in memory. Add a regression test to SchemaManagerFunctionalTestCase so the scenario, which is not platform-specific, runs against every platform. Signed-off-by: Fabrizio Balliano --- src/Platforms/SQLitePlatform.php | 16 +-- .../Schema/SQLiteSchemaManagerTest.php | 63 --------- .../SchemaManagerFunctionalTestCase.php | 122 ++++++++++++++++++ 3 files changed, 130 insertions(+), 71 deletions(-) diff --git a/src/Platforms/SQLitePlatform.php b/src/Platforms/SQLitePlatform.php index c854577f0ad..b0d3a38afe5 100644 --- a/src/Platforms/SQLitePlatform.php +++ b/src/Platforms/SQLitePlatform.php @@ -836,10 +836,10 @@ private function getIndexesInAlteredTable(TableDiff $diff): array $changed = false; $indexColumns = []; - foreach ($index->getColumns() as $columnName) { - // the column names of an introspected index are quoted while the name map is keyed - // by the unquoted column names, so unquote before the lookup - $columnName = (new Identifier($columnName))->getName(); + foreach ($index->getIndexedColumns() as $indexedColumn) { + // Use the unquoted identifier value so the lookup is agnostic of whether the index + // was introspected (which marks its column names as quoted) or built in memory. + $columnName = $indexedColumn->getColumnName()->getIdentifier()->getValue(); $normalizedColumnName = strtolower($columnName); if (! isset($nameMap[$normalizedColumnName])) { unset($indexes[$key]); @@ -906,10 +906,10 @@ private function getForeignKeysInAlteredTable(TableDiff $diff): array foreach ($foreignKeys as $key => $constraint) { $changed = false; $localColumns = []; - foreach ($constraint->getLocalColumns() as $columnName) { - // the referencing column names of an introspected foreign key constraint are quoted - // while the name map is keyed by the unquoted column names, so unquote before the lookup - $columnName = (new Identifier($columnName))->getName(); + foreach ($constraint->getReferencingColumnNames() as $referencingColumnName) { + // Use the unquoted identifier value so the lookup is agnostic of whether the constraint + // was introspected (which marks its column names as quoted) or built in memory. + $columnName = $referencingColumnName->getIdentifier()->getValue(); $normalizedColumnName = strtolower($columnName); if (! isset($nameMap[$normalizedColumnName])) { unset($foreignKeys[$key]); diff --git a/tests/Functional/Schema/SQLiteSchemaManagerTest.php b/tests/Functional/Schema/SQLiteSchemaManagerTest.php index edc708c2b7e..a101fd8835c 100644 --- a/tests/Functional/Schema/SQLiteSchemaManagerTest.php +++ b/tests/Functional/Schema/SQLiteSchemaManagerTest.php @@ -9,10 +9,8 @@ use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\ColumnDiff; -use Doctrine\DBAL\Schema\ColumnEditor; use Doctrine\DBAL\Schema\ForeignKeyConstraint; use Doctrine\DBAL\Schema\Index; -use Doctrine\DBAL\Schema\Index\IndexedColumn; use Doctrine\DBAL\Schema\Name\UnqualifiedName; use Doctrine\DBAL\Schema\PrimaryKeyConstraint; use Doctrine\DBAL\Schema\SQLiteSchemaManager; @@ -28,7 +26,6 @@ use function array_shift; use function array_values; use function assert; -use function ksort; class SQLiteSchemaManagerTest extends SchemaManagerFunctionalTestCase { @@ -319,66 +316,6 @@ public function testNonSimpleAlterTableCreatedFromDDL(): void self::assertSame(['name'], $index->getColumns()); } - public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void - { - $this->dropTableIfExists('tree_nodes'); - - $ddl = <<<'DDL' - CREATE TABLE tree_nodes ( - id INTEGER NOT NULL, - parent_id INTEGER, - name TEXT, - weight INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (parent_id) REFERENCES tree_nodes (id) - ) - DDL; - - $this->connection->executeStatement($ddl); - $this->connection->executeStatement('CREATE UNIQUE INDEX idx_tree_name ON tree_nodes (name)'); - $this->connection->executeStatement('CREATE INDEX idx_tree_parent ON tree_nodes (parent_id)'); - - $schemaManager = $this->connection->createSchemaManager(); - - $oldTable = $schemaManager->introspectTableByUnquotedName('tree_nodes'); - $newTable = $oldTable->edit() - ->modifyColumnByUnquotedName( - 'weight', - static function (ColumnEditor $editor): void { - $editor->setTypeName(Types::STRING) - ->setLength(32); - }, - ) - ->create(); - - $diff = $schemaManager->createComparator()->compareTables($oldTable, $newTable); - $schemaManager->alterTable($diff); - - $table = $schemaManager->introspectTableByUnquotedName('tree_nodes'); - - self::assertCount(1, $table->getForeignKeys()); - - $indexes = []; - foreach ($table->getIndexes() as $index) { - $indexName = $index->getObjectName()->getIdentifier()->getValue(); - if ($indexName === 'primary') { - continue; - } - - $indexes[$indexName] = array_map( - static fn (IndexedColumn $indexedColumn): string => $indexedColumn - ->getColumnName() - ->getIdentifier() - ->getValue(), - $index->getIndexedColumns(), - ); - } - - ksort($indexes); - - self::assertSame(['idx_tree_name' => ['name'], 'idx_tree_parent' => ['parent_id']], $indexes); - } - public function testAlterTableWithSchema(): void { $this->dropTableIfExists('t'); diff --git a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php index ea6b018f150..bee5627843a 100644 --- a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -763,6 +763,128 @@ public function testAlterTableScenario(): void self::assertEquals(['id'], array_map('strtolower', $foreignKey->getForeignColumns())); } + public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void + { + $referencedTable = Table::editor() + ->setUnquotedName('alter_introspected_ref') + ->setColumns( + Column::editor() + ->setUnquotedName('id') + ->setTypeName(Types::INTEGER) + ->create(), + ) + ->setPrimaryKeyConstraint( + PrimaryKeyConstraint::editor() + ->setUnquotedColumnNames('id') + ->create(), + ) + ->create(); + + $table = Table::editor() + ->setUnquotedName('alter_introspected') + ->setColumns( + Column::editor() + ->setUnquotedName('id') + ->setTypeName(Types::INTEGER) + ->create(), + Column::editor() + ->setUnquotedName('ref_id') + ->setTypeName(Types::INTEGER) + ->create(), + Column::editor() + ->setUnquotedName('name') + ->setTypeName(Types::STRING) + ->setLength(32) + ->create(), + Column::editor() + ->setUnquotedName('weight') + ->setTypeName(Types::INTEGER) + ->create(), + ) + ->setPrimaryKeyConstraint( + PrimaryKeyConstraint::editor() + ->setUnquotedColumnNames('id') + ->create(), + ) + ->setIndexes( + Index::editor() + ->setUnquotedName('idx_intro_name') + ->setUnquotedColumnNames('name') + ->setType(IndexType::UNIQUE) + ->create(), + Index::editor() + ->setUnquotedName('idx_intro_ref') + ->setUnquotedColumnNames('ref_id') + ->create(), + ) + ->setForeignKeyConstraints( + ForeignKeyConstraint::editor() + ->setUnquotedName('fk_intro_ref') + ->setUnquotedReferencingColumnNames('ref_id') + ->setUnquotedReferencedTableName('alter_introspected_ref') + ->setUnquotedReferencedColumnNames('id') + ->create(), + ) + ->create(); + + $platform = $this->connection->getDatabasePlatform(); + + $this->dropTableIfExists($table->getObjectName()->toSQL($platform)); + $this->dropTableIfExists($referencedTable->getObjectName()->toSQL($platform)); + + $this->schemaManager->createTable($referencedTable); + $this->schemaManager->createTable($table); + + // Modify an unrelated column to force a table alteration that does not touch + // the indexed or referencing columns. + $oldTable = $this->schemaManager->introspectTableByUnquotedName('alter_introspected'); + $newTable = $oldTable->edit() + ->modifyColumnByUnquotedName('weight', static function (ColumnEditor $editor): void { + $editor->setTypeName(Types::STRING) + ->setLength(32); + }) + ->create(); + + $diff = $this->schemaManager->createComparator()->compareTables($oldTable, $newTable); + $this->schemaManager->alterTable($diff); + + $table = $this->schemaManager->introspectTableByUnquotedName('alter_introspected'); + + // Read indexed column names through the non-deprecated accessors so the result is independent + // of how the index was obtained (introspection marks the column names as quoted). + $indexedColumnNames = static function (Index $index): array { + return array_map( + static function (IndexedColumn $column): string { + return strtolower($column->getColumnName()->getIdentifier()->getValue()); + }, + $index->getIndexedColumns(), + ); + }; + + // The indexes and foreign keys must survive the alteration. + self::assertTrue($table->hasIndex('idx_intro_name')); + self::assertSame(['name'], $indexedColumnNames($table->getIndex('idx_intro_name'))); + self::assertSame(IndexType::UNIQUE, $table->getIndex('idx_intro_name')->getType()); + + self::assertTrue($table->hasIndex('idx_intro_ref')); + self::assertSame(['ref_id'], $indexedColumnNames($table->getIndex('idx_intro_ref'))); + + /** @var list $foreignKeys */ + $foreignKeys = array_values($table->getForeignKeys()); + self::assertCount(1, $foreignKeys); + self::assertSame( + ['ref_id'], + array_map( + static fn (UnqualifiedName $name): string => strtolower($name->getIdentifier()->getValue()), + $foreignKeys[0]->getReferencingColumnNames(), + ), + ); + self::assertSame( + 'alter_introspected_ref', + strtolower($foreignKeys[0]->getReferencedTableName()->getUnqualifiedName()->getValue()), + ); + } + public function testTableInNamespace(): void { $platform = $this->connection->getDatabasePlatform(); From 42cb23a33cf4297a53752ad4465716469f661f41 Mon Sep 17 00:00:00 2001 From: Fabrizio Balliano Date: Thu, 23 Jul 2026 08:53:49 +0100 Subject: [PATCH 3/4] address review: use getUnquoted* accessors and quote-aware test assertions --- src/Platforms/SQLitePlatform.php | 14 ++-- .../SchemaManagerFunctionalTestCase.php | 77 +++++++------------ 2 files changed, 32 insertions(+), 59 deletions(-) diff --git a/src/Platforms/SQLitePlatform.php b/src/Platforms/SQLitePlatform.php index b0d3a38afe5..aab1ce3056e 100644 --- a/src/Platforms/SQLitePlatform.php +++ b/src/Platforms/SQLitePlatform.php @@ -836,10 +836,9 @@ private function getIndexesInAlteredTable(TableDiff $diff): array $changed = false; $indexColumns = []; - foreach ($index->getIndexedColumns() as $indexedColumn) { - // Use the unquoted identifier value so the lookup is agnostic of whether the index - // was introspected (which marks its column names as quoted) or built in memory. - $columnName = $indexedColumn->getColumnName()->getIdentifier()->getValue(); + // Use the unquoted column names so the lookup is agnostic of whether the index + // was introspected (which marks its column names as quoted) or built in memory. + foreach ($index->getUnquotedColumns() as $columnName) { $normalizedColumnName = strtolower($columnName); if (! isset($nameMap[$normalizedColumnName])) { unset($indexes[$key]); @@ -906,10 +905,9 @@ private function getForeignKeysInAlteredTable(TableDiff $diff): array foreach ($foreignKeys as $key => $constraint) { $changed = false; $localColumns = []; - foreach ($constraint->getReferencingColumnNames() as $referencingColumnName) { - // Use the unquoted identifier value so the lookup is agnostic of whether the constraint - // was introspected (which marks its column names as quoted) or built in memory. - $columnName = $referencingColumnName->getIdentifier()->getValue(); + // Use the unquoted column names so the lookup is agnostic of whether the constraint + // was introspected (which marks its column names as quoted) or built in memory. + foreach ($constraint->getUnquotedLocalColumns() as $columnName) { $normalizedColumnName = strtolower($columnName); if (! isset($nameMap[$normalizedColumnName])) { unset($foreignKeys[$key]); diff --git a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php index bee5627843a..fd045b12eaf 100644 --- a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -780,6 +780,27 @@ public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void ) ->create(); + $indexes = [ + Index::editor() + ->setUnquotedName('idx_intro_name') + ->setUnquotedColumnNames('name') + ->setType(IndexType::UNIQUE) + ->create(), + Index::editor() + ->setUnquotedName('idx_intro_ref') + ->setUnquotedColumnNames('ref_id') + ->create(), + ]; + + $foreignKeyConstraints = [ + ForeignKeyConstraint::editor() + ->setUnquotedName('fk_intro_ref') + ->setUnquotedReferencingColumnNames('ref_id') + ->setUnquotedReferencedTableName('alter_introspected_ref') + ->setUnquotedReferencedColumnNames('id') + ->create(), + ]; + $table = Table::editor() ->setUnquotedName('alter_introspected') ->setColumns( @@ -806,25 +827,8 @@ public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void ->setUnquotedColumnNames('id') ->create(), ) - ->setIndexes( - Index::editor() - ->setUnquotedName('idx_intro_name') - ->setUnquotedColumnNames('name') - ->setType(IndexType::UNIQUE) - ->create(), - Index::editor() - ->setUnquotedName('idx_intro_ref') - ->setUnquotedColumnNames('ref_id') - ->create(), - ) - ->setForeignKeyConstraints( - ForeignKeyConstraint::editor() - ->setUnquotedName('fk_intro_ref') - ->setUnquotedReferencingColumnNames('ref_id') - ->setUnquotedReferencedTableName('alter_introspected_ref') - ->setUnquotedReferencedColumnNames('id') - ->create(), - ) + ->setIndexes(...$indexes) + ->setForeignKeyConstraints(...$foreignKeyConstraints) ->create(); $platform = $this->connection->getDatabasePlatform(); @@ -850,39 +854,10 @@ public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void $table = $this->schemaManager->introspectTableByUnquotedName('alter_introspected'); - // Read indexed column names through the non-deprecated accessors so the result is independent - // of how the index was obtained (introspection marks the column names as quoted). - $indexedColumnNames = static function (Index $index): array { - return array_map( - static function (IndexedColumn $column): string { - return strtolower($column->getColumnName()->getIdentifier()->getValue()); - }, - $index->getIndexedColumns(), - ); - }; - // The indexes and foreign keys must survive the alteration. - self::assertTrue($table->hasIndex('idx_intro_name')); - self::assertSame(['name'], $indexedColumnNames($table->getIndex('idx_intro_name'))); - self::assertSame(IndexType::UNIQUE, $table->getIndex('idx_intro_name')->getType()); - - self::assertTrue($table->hasIndex('idx_intro_ref')); - self::assertSame(['ref_id'], $indexedColumnNames($table->getIndex('idx_intro_ref'))); - - /** @var list $foreignKeys */ - $foreignKeys = array_values($table->getForeignKeys()); - self::assertCount(1, $foreignKeys); - self::assertSame( - ['ref_id'], - array_map( - static fn (UnqualifiedName $name): string => strtolower($name->getIdentifier()->getValue()), - $foreignKeys[0]->getReferencingColumnNames(), - ), - ); - self::assertSame( - 'alter_introspected_ref', - strtolower($foreignKeys[0]->getReferencedTableName()->getUnqualifiedName()->getValue()), - ); + $this->assertIndexEquals($indexes[0], $table->getIndex('idx_intro_name')); + $this->assertIndexEquals($indexes[1], $table->getIndex('idx_intro_ref')); + $this->assertForeignKeyConstraintListEquals($foreignKeyConstraints, array_values($table->getForeignKeys())); } public function testTableInNamespace(): void From 930c133dbbfb586bd43e2d55942f6cc9cbc01c32 Mon Sep 17 00:00:00 2001 From: Fabrizio Balliano Date: Thu, 23 Jul 2026 09:03:27 +0100 Subject: [PATCH 4/4] fix test on MariaDB: compare foreign keys against pre-alteration introspection The referential actions of a foreign key created without explicit actions are reported inconsistently across platforms (MariaDB reports RESTRICT, MySQL reports NO ACTION), so the post-alteration foreign keys are compared against the pre-alteration introspection instead of the in-memory definition. --- .../Schema/SchemaManagerFunctionalTestCase.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php index fd045b12eaf..45c3951d583 100644 --- a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -839,9 +839,13 @@ public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void $this->schemaManager->createTable($referencedTable); $this->schemaManager->createTable($table); + $oldTable = $this->schemaManager->introspectTableByUnquotedName('alter_introspected'); + + // Guard against a vacuous comparison of the foreign keys below. + self::assertCount(1, $oldTable->getForeignKeys()); + // Modify an unrelated column to force a table alteration that does not touch // the indexed or referencing columns. - $oldTable = $this->schemaManager->introspectTableByUnquotedName('alter_introspected'); $newTable = $oldTable->edit() ->modifyColumnByUnquotedName('weight', static function (ColumnEditor $editor): void { $editor->setTypeName(Types::STRING) @@ -854,10 +858,15 @@ public function testAlterIntrospectedTablePreservesIndexesAndForeignKeys(): void $table = $this->schemaManager->introspectTableByUnquotedName('alter_introspected'); - // The indexes and foreign keys must survive the alteration. + // The indexes and foreign keys must survive the alteration. The foreign keys are compared against + // the pre-alteration introspection because the referential actions of a foreign key created without + // explicit actions are reported inconsistently across platforms (e.g. MariaDB reports RESTRICT). $this->assertIndexEquals($indexes[0], $table->getIndex('idx_intro_name')); $this->assertIndexEquals($indexes[1], $table->getIndex('idx_intro_ref')); - $this->assertForeignKeyConstraintListEquals($foreignKeyConstraints, array_values($table->getForeignKeys())); + $this->assertForeignKeyConstraintListEquals( + array_values($oldTable->getForeignKeys()), + array_values($table->getForeignKeys()), + ); } public function testTableInNamespace(): void