Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate alter add/change column with explicit position for MySQL #4276

Closed
Closed
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
48 changes: 41 additions & 7 deletions lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,8 @@ public function getAlterTableSQL(TableDiff $diff)
'comment' => $this->getColumnComment($column),
]);

$queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
$queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray)
. $this->getColumnDeclarationPositionSQL($columnArray['name'], $diff->toTable);
}

foreach ($diff->removedColumns as $column) {
Expand Down Expand Up @@ -599,7 +600,8 @@ public function getAlterTableSQL(TableDiff $diff)

$columnArray['comment'] = $this->getColumnComment($column);
$queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' '
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray)
. $this->getColumnDeclarationPositionSQL($columnArray['name'], $diff->toTable);
}

foreach ($diff->renamedColumns as $oldColumnName => $column) {
Expand All @@ -611,7 +613,8 @@ public function getAlterTableSQL(TableDiff $diff)
$columnArray = $column->toArray();
$columnArray['comment'] = $this->getColumnComment($column);
$queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' '
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray)
. $this->getColumnDeclarationPositionSQL($columnArray['name'], $diff->toTable);
}

if (isset($diff->addedIndexes['primary'])) {
Expand Down Expand Up @@ -650,6 +653,31 @@ public function getAlterTableSQL(TableDiff $diff)
return array_merge($sql, $tableSql, $columnSql);
}

protected function getColumnDeclarationPositionSQL(string $columnName, ?Table $toTable): ?string
{
if ($toTable === null) {
return null;
}

$columnFound = false;
$prevColumn = null;
foreach ($toTable->getColumns() as $k => $column) {
if ($k === $columnName) {
$columnFound = true;

break;
}

$prevColumn = $column;
}

if (! $columnFound) {
throw new InvalidArgumentException('Column name "' . $columnName . '" not found');
Copy link
Member

@morozov morozov Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to avoid having this exception by using a more suitable method signature? Each column is either first or goes after some other column. See #4145 for example. Otherwise, this will need a functional test that demonstrates the exception being thrown.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can call $toTable->getColumn() before the foreach loop which should check if the column exists or not

please sudgest ideal approach to this

Copy link
Member

@morozov morozov Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might work if instead of having the $toTable in the SchemaDiff, the ColumnDiff had a property like $afterColumn that would contain the column name and be non-empty only if the column position has changed. This assumes that a similar SQL syntax could be used on other supported platforms. This would also solve the problem of having the FIRST and AFTER fragments unnecessarily generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ColumnDiff can not be used as we need position also for Column. @morozov I would like to finish this PR asap, please advise, if the $toTable is ok - used like $fromTable already used - or if you have a better alternative. Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ColumnDiff can not be used as we need position also for Column

I do not understand what this means. Can you please elaborate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ColumnDiff can not be used as we need position also for Column

I do not understand what this means. Can you please elaborate?

if column already exists, then ColumnDiff instance is returned from the comparator

if the column is new (not renamed/modified), then there is no ColumnDiff for it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exception is covered by added test

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvorisek please make sure you don't resolve the conversations that you didn't start unless you're resolving one on the starter's behalf.

}

return $prevColumn === null ? ' FIRST' : ' AFTER ' . $prevColumn->getQuotedName($this);
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -740,8 +768,11 @@ private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $inde

$column->setAutoincrement(false);

$sql[] = 'ALTER TABLE ' . $tableName . ' MODIFY ' .
$this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
$columnArray = $column->toArray();

$sql[] = 'ALTER TABLE ' . $tableName . ' MODIFY '
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray)
. $this->getColumnDeclarationPositionSQL($columnArray['name'], $diff->toTable);

// original autoincrement information might be needed later on by other parts of the table alteration
$column->setAutoincrement(true);
Expand Down Expand Up @@ -778,8 +809,11 @@ private function getPreAlterTableAlterIndexForeignKeySQL(TableDiff $diff)
// before we can drop and recreate the primary key.
$column->setAutoincrement(false);

$sql[] = 'ALTER TABLE ' . $table . ' MODIFY ' .
$this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
$columnArray = $column->toArray();

$sql[] = 'ALTER TABLE ' . $table . ' MODIFY '
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray)
. $this->getColumnDeclarationPositionSQL($columnArray['name'], $diff->toTable);

// Restore the autoincrement attribute as it might be needed later on
// by other parts of the table alteration.
Expand Down
1 change: 1 addition & 0 deletions lib/Doctrine/DBAL/Schema/Comparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public function diffTable(Table $fromTable, Table $toTable)
$changes = 0;
$tableDifferences = new TableDiff($fromTable->getName());
$tableDifferences->fromTable = $fromTable;
$tableDifferences->toTable = $toTable;

$fromTableColumns = $fromTable->getColumns();
$toTableColumns = $toTable->getColumns();
Expand Down
7 changes: 6 additions & 1 deletion lib/Doctrine/DBAL/Schema/TableDiff.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ class TableDiff
/** @var Table|null */
public $fromTable;

/** @var Table|null */
public $toTable;

/**
* Constructs an TableDiff object.
*
Expand All @@ -114,7 +117,8 @@ public function __construct(
$addedIndexes = [],
$changedIndexes = [],
$removedIndexes = [],
?Table $fromTable = null
?Table $fromTable = null,
?Table $toTable = null
) {
$this->name = $tableName;
$this->addedColumns = $addedColumns;
Expand All @@ -124,6 +128,7 @@ public function __construct(
$this->changedIndexes = $changedIndexes;
$this->removedIndexes = $removedIndexes;
$this->fromTable = $fromTable;
$this->toTable = $toTable;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;
use Doctrine\Tests\Types\MySqlPointType;
use InvalidArgumentException;

use function array_keys;

class MySqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
{
Expand Down Expand Up @@ -216,6 +219,55 @@ public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes(): vo
self::assertFalse($onlineTable->getColumn('def_blob_null')->getNotnull());
}

public function testAlterTableExplicitColumnPosition(): void
{
$tableName = 'test_column_position';
$table = new Table($tableName);
$table->addColumn('id', 'integer');
$table->addColumn('a', 'integer');
$table->addColumn('b', 'integer');

$this->schemaManager->createTable($table);

self::assertSame(['id', 'a', 'b'], array_keys($this->schemaManager->listTableColumns($tableName)));

$table2 = new Table($tableName);
$table2->addColumn('id', 'float');
$table2->addColumn('new', 'float');
$table2->addColumn('b', 'float');
$table2->addColumn('a', 'float');

$comparator = new Comparator();
$diff = $comparator->diffTable($table, $table2);
self::assertNotFalse($diff);
$this->schemaManager->alterTable($diff);

self::assertSame(['id', 'new', 'b', 'a'], array_keys($this->schemaManager->listTableColumns($tableName)));
}

public function testAlterTableExplicitColumnPositionColumnNotFoundException(): void
{
$tableName = 'test_column_position_exception';
$table = new Table($tableName);
$table->addColumn('id', 'integer');

$this->schemaManager->createTable($table);

$table2 = new Table($tableName);
$table2->addColumn('id', 'float');
$table2WithoutAColumn = clone $table2;
$table2->addColumn('a', 'float');

$comparator = new Comparator();
$diff = $comparator->diffTable($table, $table2);
self::assertNotFalse($diff);
$diff->toTable = $table2WithoutAColumn;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the diff is generated from the two tables, why should it be possible to change the referenced table via the API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was meant to be added to document the case when this exception can happen because IMO it shouldn't be possible in the first place (https://github.com/doctrine/dbal/pull/4276/files#r493065750). The test doesn't show a valid case. Which means that there is no justification for this API to throw an exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the diff object is built using Comparator::diff which will add the input, then this exception can not happen.

However, the toTable is public property - like fromTable already present - and if the table is replaced by the user with different table that has not all the column names set - this exception is legit and this test cover it.


$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Column name "a" not found');
$this->schemaManager->alterTable($diff);
}

public function testColumnCharset(): void
{
$table = new Table('test_column_charset');
Expand Down Expand Up @@ -272,7 +324,7 @@ public function testColumnCharsetChange(): void
$diff = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform());
self::assertContains(
'ALTER TABLE test_column_charset_change CHANGE col_string'
. ' col_string VARCHAR(100) CHARACTER SET ascii NOT NULL',
. ' col_string VARCHAR(100) CHARACTER SET ascii NOT NULL FIRST',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we expect the SQL to contain the FIRST/AFTER qualifiers if the column position doesn't change? I believe these should be only generated when necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we generate this for ALTER TABLE only, for TABLE CREATE, position is not generated

if position is the same, we regenerate whole column definition

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we generate the column position only if it's changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add a condition, if the previous column is the same for fromTable and toTable, then to not add the position. Tests may however need more changes as currently, we expect that SQL column definition is always fully regenerated.

Let solve this as the last step before merge, firstly, I want to make sure toTable property will stay

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think toTable should stay since the other solution with ColumnDiff instance will not handle the case of new columns, which means we can resume this conversation. Let's generate the position only when necessary please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's generate the position only when necessary please.

I understand we want to generate minimalistic diff, but I think we do not want it. ALTER TABLE ADD/MODIFY column is always generated fully even if there is a minor column definition change like column comment. Adding position based on the original table will violate this definition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@morozov @greg0ire can we agree on this and can we merge this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we agree on this

If it's always generated fully indeed then it's ok with me.

can we merge this PR

In theory yes, in practice the tests fail

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI fixed

$diff
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ public function testAlterPrimaryKeyWithAutoincrementColumn(): void

self::assertEquals(
[
'ALTER TABLE alter_primary_key MODIFY id INT NOT NULL',
'ALTER TABLE alter_primary_key MODIFY id INT NOT NULL AFTER foo',
'ALTER TABLE alter_primary_key DROP PRIMARY KEY',
'ALTER TABLE alter_primary_key ADD PRIMARY KEY (foo)',
],
Expand All @@ -440,7 +440,7 @@ public function testDropPrimaryKeyWithAutoincrementColumn(): void

self::assertEquals(
[
'ALTER TABLE drop_primary_key MODIFY id INT NOT NULL',
'ALTER TABLE drop_primary_key MODIFY id INT NOT NULL FIRST',
'ALTER TABLE drop_primary_key DROP PRIMARY KEY',
],
$this->platform->getAlterTableSQL($diff)
Expand All @@ -465,7 +465,7 @@ public function testDropNonAutoincrementColumnFromCompositePrimaryKeyWithAutoinc

self::assertSame(
[
'ALTER TABLE tbl MODIFY id INT NOT NULL',
'ALTER TABLE tbl MODIFY id INT NOT NULL FIRST',
'ALTER TABLE tbl DROP PRIMARY KEY',
'ALTER TABLE tbl ADD PRIMARY KEY (id)',
],
Expand All @@ -491,7 +491,7 @@ public function testAddNonAutoincrementColumnToPrimaryKeyWithAutoincrementColumn

self::assertSame(
[
'ALTER TABLE tbl MODIFY id INT NOT NULL',
'ALTER TABLE tbl MODIFY id INT NOT NULL FIRST',
'ALTER TABLE tbl DROP PRIMARY KEY',
'ALTER TABLE tbl ADD PRIMARY KEY (id, foo)',
],
Expand All @@ -514,7 +514,7 @@ public function testAddAutoIncrementPrimaryKey(): void

$sql = $this->platform->getAlterTableSQL($diff);

self::assertEquals(['ALTER TABLE foo ADD id INT AUTO_INCREMENT NOT NULL, ADD PRIMARY KEY (id)'], $sql);
self::assertEquals(['ALTER TABLE foo ADD id INT AUTO_INCREMENT NOT NULL FIRST, ADD PRIMARY KEY (id)'], $sql);
}

public function testNamedPrimaryKey(): void
Expand Down Expand Up @@ -549,7 +549,7 @@ public function testAlterPrimaryKeyWithNewColumn(): void
self::assertSame(
[
'ALTER TABLE yolo DROP PRIMARY KEY',
'ALTER TABLE yolo ADD pkc2 INT NOT NULL',
'ALTER TABLE yolo ADD pkc2 INT NOT NULL AFTER pkc1',
'ALTER TABLE yolo ADD PRIMARY KEY (pkc1, pkc2)',
],
$this->platform->getAlterTableSQL($diff)
Expand Down Expand Up @@ -781,15 +781,15 @@ public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes(): vo
protected function getQuotedAlterTableRenameColumnSQL(): array
{
return ['ALTER TABLE mytable ' .
"CHANGE unquoted1 unquoted INT NOT NULL COMMENT 'Unquoted 1', " .
"CHANGE unquoted2 `where` INT NOT NULL COMMENT 'Unquoted 2', " .
"CHANGE unquoted3 `foo` INT NOT NULL COMMENT 'Unquoted 3', " .
"CHANGE `create` reserved_keyword INT NOT NULL COMMENT 'Reserved keyword 1', " .
"CHANGE `table` `from` INT NOT NULL COMMENT 'Reserved keyword 2', " .
"CHANGE `select` `bar` INT NOT NULL COMMENT 'Reserved keyword 3', " .
"CHANGE quoted1 quoted INT NOT NULL COMMENT 'Quoted 1', " .
"CHANGE quoted2 `and` INT NOT NULL COMMENT 'Quoted 2', " .
"CHANGE quoted3 `baz` INT NOT NULL COMMENT 'Quoted 3'",
"CHANGE unquoted1 unquoted INT NOT NULL COMMENT 'Unquoted 1' FIRST, " .
"CHANGE unquoted2 `where` INT NOT NULL COMMENT 'Unquoted 2' AFTER unquoted, " .
"CHANGE unquoted3 `foo` INT NOT NULL COMMENT 'Unquoted 3' AFTER `where`, " .
"CHANGE `create` reserved_keyword INT NOT NULL COMMENT 'Reserved keyword 1' AFTER `foo`, " .
"CHANGE `table` `from` INT NOT NULL COMMENT 'Reserved keyword 2' AFTER reserved_keyword, " .
"CHANGE `select` `bar` INT NOT NULL COMMENT 'Reserved keyword 3' AFTER `from`, " .
"CHANGE quoted1 quoted INT NOT NULL COMMENT 'Quoted 1' AFTER `bar`, " .
"CHANGE quoted2 `and` INT NOT NULL COMMENT 'Quoted 2' AFTER quoted, " .
"CHANGE quoted3 `baz` INT NOT NULL COMMENT 'Quoted 3' AFTER `and`",
];
}

Expand All @@ -799,12 +799,12 @@ protected function getQuotedAlterTableRenameColumnSQL(): array
protected function getQuotedAlterTableChangeColumnLengthSQL(): array
{
return ['ALTER TABLE mytable ' .
"CHANGE unquoted1 unquoted1 VARCHAR(255) NOT NULL COMMENT 'Unquoted 1', " .
"CHANGE unquoted2 unquoted2 VARCHAR(255) NOT NULL COMMENT 'Unquoted 2', " .
"CHANGE unquoted3 unquoted3 VARCHAR(255) NOT NULL COMMENT 'Unquoted 3', " .
"CHANGE `create` `create` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 1', " .
"CHANGE `table` `table` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 2', " .
"CHANGE `select` `select` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 3'",
"CHANGE unquoted1 unquoted1 VARCHAR(255) NOT NULL COMMENT 'Unquoted 1' FIRST, " .
"CHANGE unquoted2 unquoted2 VARCHAR(255) NOT NULL COMMENT 'Unquoted 2' AFTER unquoted1, " .
"CHANGE unquoted3 unquoted3 VARCHAR(255) NOT NULL COMMENT 'Unquoted 3' AFTER unquoted2, " .
"CHANGE `create` `create` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 1' AFTER unquoted3, " .
"CHANGE `table` `table` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 2' AFTER `create`, " .
"CHANGE `select` `select` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 3' AFTER `table`",
];
}

Expand Down
9 changes: 9 additions & 0 deletions tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public function testCompareMissingField(): void
);
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$expected->changedTables['bugdb']->toTable = $schema2->getTable('bugdb');
mvorisek marked this conversation as resolved.
Show resolved Hide resolved

self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
}
Expand Down Expand Up @@ -183,6 +184,7 @@ public function testCompareNewField(): void
);
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$expected->changedTables['bugdb']->toTable = $schema2->getTable('bugdb');

self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
}
Expand Down Expand Up @@ -313,6 +315,7 @@ public function testCompareRemovedIndex(): void
);
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$expected->changedTables['bugdb']->toTable = $schema2->getTable('bugdb');

self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
}
Expand Down Expand Up @@ -365,6 +368,7 @@ public function testCompareNewIndex(): void
);
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$expected->changedTables['bugdb']->toTable = $schema2->getTable('bugdb');

self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
}
Expand Down Expand Up @@ -428,6 +432,7 @@ public function testCompareChangedIndex(): void
);
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$expected->changedTables['bugdb']->toTable = $schema2->getTable('bugdb');

self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
}
Expand Down Expand Up @@ -476,6 +481,7 @@ public function testCompareChangedIndexFieldPositions(): void
);
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$expected->changedTables['bugdb']->toTable = $schema2->getTable('bugdb');

self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
}
Expand Down Expand Up @@ -670,6 +676,7 @@ public function testCompareIndexBasedOnPropertiesNotName(): void
$c = new Comparator();
$tableDiff = new TableDiff('foo');
$tableDiff->fromTable = $tableA;
$tableDiff->toTable = $tableB;
$tableDiff->renamedIndexes['foo_bar_idx'] = new Index('bar_foo_idx', ['id']);

self::assertEquals(
Expand Down Expand Up @@ -1041,6 +1048,7 @@ public function testCompareChangedColumn(): void

$tableDiff = $expected->changedTables['foo'] = new TableDiff('foo');
$tableDiff->fromTable = $tableFoo;
$tableDiff->toTable = $table;

$columnDiff = $tableDiff->changedColumns['id'] = new ColumnDiff('id', $table->getColumn('id'));

Expand All @@ -1066,6 +1074,7 @@ public function testCompareChangedBinaryColumn(): void

$tableDiff = $expected->changedTables['foo'] = new TableDiff('foo');
$tableDiff->fromTable = $tableFoo;
$tableDiff->toTable = $table;

$columnDiff = $tableDiff->changedColumns['id'] = new ColumnDiff('id', $table->getColumn('id'));

Expand Down