Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/Platforms/SQLitePlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,9 @@ private function getIndexesInAlteredTable(TableDiff $diff): array

$changed = false;
$indexColumns = [];
foreach ($index->getColumns() as $columnName) {
// 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]);
Expand Down Expand Up @@ -903,7 +905,9 @@ private function getForeignKeysInAlteredTable(TableDiff $diff): array
foreach ($foreignKeys as $key => $constraint) {
$changed = false;
$localColumns = [];
foreach ($constraint->getLocalColumns() as $columnName) {
// 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]);
Expand Down
106 changes: 106 additions & 0 deletions tests/Functional/Schema/SchemaManagerFunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,112 @@ 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();

$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(
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(...$indexes)
->setForeignKeyConstraints(...$foreignKeyConstraints)
->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);

$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.
$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');

// 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(
array_values($oldTable->getForeignKeys()),
array_values($table->getForeignKeys()),
);
}

public function testTableInNamespace(): void
{
$platform = $this->connection->getDatabasePlatform();
Expand Down