diff --git a/tests/Functional/Schema/AlterTableTest.php b/tests/Functional/Schema/AlterTableTest.php new file mode 100644 index 00000000000..9dbf1554216 --- /dev/null +++ b/tests/Functional/Schema/AlterTableTest.php @@ -0,0 +1,218 @@ +connection->getDatabasePlatform() instanceof SQLitePlatform) { + self::markTestSkipped( + 'SQLite will automatically set up auto-increment behavior on the primary key column, which this test' + . ' does not expect.', + ); + } + + $table = new Table('alter_pk'); + $table->addColumn('id', Types::INTEGER); + $table->addColumn('val', Types::INTEGER); + + $this->testMigration($table, static function (Table $table): void { + $table->setPrimaryKey(['id']); + }); + } + + public function testAddPrimaryKeyOnNewAutoIncrementColumn(): void + { + if ($this->connection->getDatabasePlatform() instanceof DB2Platform) { + self::markTestSkipped( + 'IBM DB2 LUW does not support adding identity columns to an existing table.', + ); + } + + $table = new Table('alter_pk'); + $table->addColumn('val', Types::INTEGER); + + $this->testMigration($table, static function (Table $table): void { + $table->addColumn('id', Types::INTEGER, ['autoincrement' => true]); + $table->setPrimaryKey(['id']); + }); + } + + public function testAlterPrimaryKeyFromAutoincrementToNonAutoincrementColumn(): void + { + $platform = $this->connection->getDatabasePlatform(); + + if ($platform instanceof AbstractMySQLPlatform) { + self::markTestIncomplete( + 'DBAL should not allow this migration on MySQL because an auto-increment column must be part of the' + . ' primary key constraint.', + ); + } + + if ($platform instanceof SQLitePlatform) { + self::markTestSkipped( + 'SQLite does not support auto-increment columns that are not part the primary key constraint', + ); + } + + $this->ensureDroppingPrimaryKeyConstraintIsSupported(); + + $table = new Table('alter_pk'); + $table->addColumn('id1', Types::INTEGER, ['autoincrement' => true]); + $table->addColumn('id2', Types::INTEGER); + $table->setPrimaryKey(['id1']); + + $this->testMigration($table, static function (Table $table): void { + $table->dropPrimaryKey(); + $table->setPrimaryKey(['id2']); + }); + } + + public function testDropPrimaryKeyWithAutoincrementColumn(): void + { + $platform = $this->connection->getDatabasePlatform(); + + if ($platform instanceof AbstractMySQLPlatform) { + self::markTestIncomplete( + 'DBAL should not allow this migration on MySQL because an auto-increment column must be part of the' + . ' primary key constraint.', + ); + } + + if ($platform instanceof SQLitePlatform) { + self::markTestSkipped( + 'SQLite does not support auto-increment columns as part of composite primary key constraint', + ); + } + + $this->ensureDroppingPrimaryKeyConstraintIsSupported(); + + $table = new Table('alter_pk'); + $table->addColumn('id1', Types::INTEGER, ['autoincrement' => true]); + $table->addColumn('id2', Types::INTEGER); + $table->setPrimaryKey(['id1', 'id2']); + + $this->testMigration($table, static function (Table $table): void { + $table->dropPrimaryKey(); + }); + } + + public function testDropNonAutoincrementColumnFromCompositePrimaryKeyWithAutoincrementColumn(): void + { + if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) { + self::markTestIncomplete( + 'DBAL does not restore the auto-increment attribute after dropping and adding the constraint,' + . ' which is a bug.', + ); + } + + $this->ensureDroppingPrimaryKeyConstraintIsSupported(); + + $table = new Table('alter_pk'); + $table->addColumn('id1', Types::INTEGER, ['autoincrement' => true]); + $table->addColumn('id2', Types::INTEGER); + $table->setPrimaryKey(['id1', 'id2']); + + $this->testMigration($table, static function (Table $table): void { + $table->dropPrimaryKey(); + $table->setPrimaryKey(['id1']); + }); + } + + public function testAddNonAutoincrementColumnToPrimaryKeyWithAutoincrementColumn(): void + { + $platform = $this->connection->getDatabasePlatform(); + + if ($platform instanceof AbstractMySQLPlatform) { + self::markTestIncomplete( + 'DBAL does not restore the auto-increment attribute after dropping and adding the constraint,' + . ' which is a bug.', + ); + } + + if ($platform instanceof SQLitePlatform) { + self::markTestSkipped( + 'SQLite does not support auto-increment columns as part of composite primary key constraint', + ); + } + + $this->ensureDroppingPrimaryKeyConstraintIsSupported(); + + $table = new Table('alter_pk'); + $table->addColumn('id1', Types::INTEGER, ['autoincrement' => true]); + $table->addColumn('id2', Types::INTEGER); + $table->setPrimaryKey(['id1']); + + $this->testMigration($table, static function (Table $table): void { + $table->dropPrimaryKey(); + $table->setPrimaryKey(['id1', 'id2']); + }); + } + + public function testAddNewColumnToPrimaryKey(): void + { + $this->ensureDroppingPrimaryKeyConstraintIsSupported(); + + $table = new Table('alter_pk'); + $table->addColumn('id1', Types::INTEGER); + $table->setPrimaryKey(['id1']); + + $this->testMigration($table, static function (Table $table): void { + $table->addColumn('id2', Types::INTEGER); + $table->dropPrimaryKey(); + $table->setPrimaryKey(['id1', 'id2']); + }); + } + + private function ensureDroppingPrimaryKeyConstraintIsSupported(): void + { + $platform = $this->connection->getDatabasePlatform(); + + if ( + ! ($platform instanceof DB2Platform) + && ! ($platform instanceof OraclePlatform) + && ! ($platform instanceof SQLServerPlatform) + ) { + return; + } + + self::markTestIncomplete( + 'Dropping primary key constraint on the currently used database platform is not implemented.', + ); + } + + private function testMigration(Table $oldTable, callable $migration): void + { + $this->dropAndCreateTable($oldTable); + + $newTable = clone $oldTable; + + $migration($newTable); + + $schemaManager = $this->connection->createSchemaManager(); + + $diff = $schemaManager->createComparator() + ->compareTables($oldTable, $newTable); + + $schemaManager->alterTable($diff); + + $introspectedTable = $schemaManager->introspectTable($newTable->getName()); + + $diff = $schemaManager->createComparator() + ->compareTables($newTable, $introspectedTable); + + self::assertTrue($diff->isEmpty()); + } +} diff --git a/tests/Platforms/AbstractMySQLPlatformTestCase.php b/tests/Platforms/AbstractMySQLPlatformTestCase.php index 266fa2c48b5..59c4aac1152 100644 --- a/tests/Platforms/AbstractMySQLPlatformTestCase.php +++ b/tests/Platforms/AbstractMySQLPlatformTestCase.php @@ -282,172 +282,6 @@ public function testBlobTypeDeclarationSQL(): void self::assertEquals('LONGBLOB', $this->platform->getBlobTypeDeclarationSQL([])); } - public function testAlterTableAddPrimaryKey(): void - { - $table = new Table('alter_table_add_pk'); - $table->addColumn('id', Types::INTEGER); - $table->addColumn('foo', Types::INTEGER); - $table->addIndex(['id'], 'idx_id'); - - $diffTable = clone $table; - - $diffTable->dropIndex('idx_id'); - $diffTable->setPrimaryKey(['id']); - - $diff = $this->createComparator() - ->compareTables($table, $diffTable); - - self::assertEquals( - ['DROP INDEX idx_id ON alter_table_add_pk', 'ALTER TABLE alter_table_add_pk ADD PRIMARY KEY (id)'], - $this->platform->getAlterTableSQL($diff), - ); - } - - public function testAlterPrimaryKeyWithAutoincrementColumn(): void - { - $table = new Table('alter_primary_key'); - $table->addColumn('id', Types::INTEGER, ['autoincrement' => true]); - $table->addColumn('foo', Types::INTEGER); - $table->setPrimaryKey(['id']); - - $diffTable = clone $table; - - $diffTable->dropPrimaryKey(); - $diffTable->setPrimaryKey(['foo']); - - $diff = $this->createComparator() - ->compareTables($table, $diffTable); - - self::assertEquals( - [ - 'ALTER TABLE alter_primary_key MODIFY id INT NOT NULL', - 'DROP INDEX `primary` ON alter_primary_key', - 'ALTER TABLE alter_primary_key ADD PRIMARY KEY (foo)', - ], - $this->platform->getAlterTableSQL($diff), - ); - } - - public function testDropPrimaryKeyWithAutoincrementColumn(): void - { - $table = new Table('drop_primary_key'); - $table->addColumn('id', Types::INTEGER, ['autoincrement' => true]); - $table->addColumn('foo', Types::INTEGER); - $table->addColumn('bar', Types::INTEGER); - $table->setPrimaryKey(['id', 'foo']); - - $diffTable = clone $table; - - $diffTable->dropPrimaryKey(); - - $diff = $this->createComparator() - ->compareTables($table, $diffTable); - - self::assertEquals( - [ - 'ALTER TABLE drop_primary_key MODIFY id INT NOT NULL', - 'DROP INDEX `primary` ON drop_primary_key', - ], - $this->platform->getAlterTableSQL($diff), - ); - } - - public function testDropNonAutoincrementColumnFromCompositePrimaryKeyWithAutoincrementColumn(): void - { - $table = new Table('tbl'); - $table->addColumn('id', Types::INTEGER, ['autoincrement' => true]); - $table->addColumn('foo', Types::INTEGER); - $table->addColumn('bar', Types::INTEGER); - $table->setPrimaryKey(['id', 'foo']); - - $diffTable = clone $table; - - $diffTable->dropPrimaryKey(); - $diffTable->setPrimaryKey(['id']); - - $diff = $this->createComparator() - ->compareTables($table, $diffTable); - - self::assertSame( - [ - 'ALTER TABLE tbl MODIFY id INT NOT NULL', - 'DROP INDEX `primary` ON tbl', - 'ALTER TABLE tbl ADD PRIMARY KEY (id)', - ], - $this->platform->getAlterTableSQL($diff), - ); - } - - public function testAddNonAutoincrementColumnToPrimaryKeyWithAutoincrementColumn(): void - { - $table = new Table('tbl'); - $table->addColumn('id', Types::INTEGER, ['autoincrement' => true]); - $table->addColumn('foo', Types::INTEGER); - $table->addColumn('bar', Types::INTEGER); - $table->setPrimaryKey(['id']); - - $diffTable = clone $table; - - $diffTable->dropPrimaryKey(); - $diffTable->setPrimaryKey(['id', 'foo']); - - $diff = $this->createComparator() - ->compareTables($table, $diffTable); - - self::assertSame( - [ - 'ALTER TABLE tbl MODIFY id INT NOT NULL', - 'DROP INDEX `primary` ON tbl', - 'ALTER TABLE tbl ADD PRIMARY KEY (id, foo)', - ], - $this->platform->getAlterTableSQL($diff), - ); - } - - public function testAddAutoIncrementPrimaryKey(): void - { - $keyTable = new Table('foo'); - $keyTable->addColumn('id', Types::INTEGER, ['autoincrement' => true]); - $keyTable->addColumn('baz', Types::STRING, ['length' => 32]); - $keyTable->setPrimaryKey(['id']); - - $oldTable = new Table('foo'); - $oldTable->addColumn('baz', Types::STRING, ['length' => 32]); - - $diff = $this->createComparator() - ->compareTables($oldTable, $keyTable); - - $sql = $this->platform->getAlterTableSQL($diff); - - self::assertEquals(['ALTER TABLE foo ADD id INT AUTO_INCREMENT NOT NULL, ADD PRIMARY KEY (id)'], $sql); - } - - public function testAlterPrimaryKeyWithNewColumn(): void - { - $table = new Table('yolo'); - $table->addColumn('pkc1', Types::INTEGER); - $table->addColumn('col_a', Types::INTEGER); - $table->setPrimaryKey(['pkc1']); - - $diffTable = clone $table; - - $diffTable->addColumn('pkc2', Types::INTEGER); - $diffTable->dropPrimaryKey(); - $diffTable->setPrimaryKey(['pkc1', 'pkc2']); - - $diff = $this->createComparator() - ->compareTables($table, $diffTable); - - self::assertSame( - [ - 'DROP INDEX `primary` ON yolo', - 'ALTER TABLE yolo ADD pkc2 INT NOT NULL', - 'ALTER TABLE yolo ADD PRIMARY KEY (pkc1, pkc2)', - ], - $this->platform->getAlterTableSQL($diff), - ); - } - public function testInitializesDoctrineTypeMappings(): void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('binary'));