diff --git a/psalm.xml.dist b/psalm.xml.dist index 31e4a8b6638..2ae40a21558 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -517,6 +517,13 @@ + + + + diff --git a/src/Platforms/AbstractMySQLPlatform.php b/src/Platforms/AbstractMySQLPlatform.php index 8651b82783d..8e17c47aba1 100644 --- a/src/Platforms/AbstractMySQLPlatform.php +++ b/src/Platforms/AbstractMySQLPlatform.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Exception; use Doctrine\DBAL\Schema\AbstractAsset; use Doctrine\DBAL\Schema\ForeignKeyConstraint; -use Doctrine\DBAL\Schema\Identifier; use Doctrine\DBAL\Schema\Index; use Doctrine\DBAL\Schema\MySQLSchemaManager; use Doctrine\DBAL\Schema\Table; @@ -684,36 +683,26 @@ public function getAlterTableSQL(TableDiff $diff) $queryParts[] = 'DROP ' . $column->getQuotedName($this); } - foreach ($diff->getModifiedColumns() as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { - continue; - } - + foreach ($diff->getChangedColumns() as $columnDiff) { $newColumn = $columnDiff->getNewColumn(); $newColumnProperties = array_merge($newColumn->toArray(), [ 'comment' => $this->getColumnComment($newColumn), ]); - $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); - - $queryParts[] = 'CHANGE ' . $oldColumn->getQuotedName($this) . ' ' - . $this->getColumnDeclarationSQL($newColumn->getQuotedName($this), $newColumnProperties); - } + $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); + $oldColumnName = $oldColumn->getName(); - foreach ($diff->getRenamedColumns() as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + if ($columnDiff->hasNameChanged()) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $newColumn, $diff, $columnSql)) { + continue; + } + } elseif ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } - $oldColumnName = new Identifier($oldColumnName); - - $columnProperties = array_merge($column->toArray(), [ - 'comment' => $this->getColumnComment($column), - ]); - - $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' - . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnProperties); + $queryParts[] = 'CHANGE ' . $oldColumn->getQuotedName($this) . ' ' + . $this->getColumnDeclarationSQL($newColumn->getQuotedName($this), $newColumnProperties); } $addedIndexes = $this->indexAssetsByLowerCaseName($diff->getAddedIndexes()); @@ -745,7 +734,7 @@ public function getAlterTableSQL(TableDiff $diff) $diff = new TableDiff( $diff->name, $diff->getAddedColumns(), - $diff->getModifiedColumns(), + $diff->getChangedColumns(), $diff->getDroppedColumns(), array_values($addedIndexes), array_values($modifiedIndexes), @@ -754,7 +743,6 @@ public function getAlterTableSQL(TableDiff $diff) $diff->getAddedForeignKeys(), $diff->getModifiedForeignKeys(), $diff->getDroppedForeignKeys(), - $diff->getRenamedColumns(), $diff->getRenamedIndexes(), ); } diff --git a/src/Platforms/AbstractPlatform.php b/src/Platforms/AbstractPlatform.php index c77882a1a53..9b99c10d2ae 100644 --- a/src/Platforms/AbstractPlatform.php +++ b/src/Platforms/AbstractPlatform.php @@ -2940,6 +2940,20 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) ]; } + /** + * Returns the SQL for renaming a column + * + * @param string $tableName The table to rename the column on. + * @param string $oldColumnName The name of the column we want to rename. + * @param string $newColumnName The name we should rename it to. + * + * @return string[] The sequence of SQL statements for renaming the given column. + */ + protected function getRenameColumnSQL(string $tableName, string $oldColumnName, string $newColumnName): array + { + return [sprintf('ALTER TABLE %s RENAME COLUMN %s TO %s', $tableName, $oldColumnName, $newColumnName)]; + } + /** * Gets declaration of a number of columns in bulk. * diff --git a/src/Platforms/DB2Platform.php b/src/Platforms/DB2Platform.php index 64fabc32d0a..4e3d4c63efd 100644 --- a/src/Platforms/DB2Platform.php +++ b/src/Platforms/DB2Platform.php @@ -623,16 +623,27 @@ public function getAlterTableSQL(TableDiff $diff) ); } + $needsReorg = false; foreach ($diff->getDroppedColumns() as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); + $needsReorg = true; } - foreach ($diff->getModifiedColumns() as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + foreach ($diff->getChangedColumns() as $columnDiff) { + $newColumn = $columnDiff->getNewColumn(); + $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); + + $oldColumnName = $oldColumn->getQuotedName($this); + + if ($columnDiff->hasNameChanged()) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $newColumn, $diff, $columnSql)) { + continue; + } + } elseif ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } @@ -650,17 +661,12 @@ public function getAlterTableSQL(TableDiff $diff) $sql, $queryParts, ); - } - foreach ($diff->getRenamedColumns() as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + if (empty($columnDiff->changedProperties)) { continue; } - $oldColumnName = new Identifier($oldColumnName); - - $queryParts[] = 'RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . - ' TO ' . $column->getQuotedName($this); + $needsReorg = true; } $tableSql = []; @@ -671,7 +677,7 @@ public function getAlterTableSQL(TableDiff $diff) } // Some table alteration operations require a table reorganization. - if (count($diff->getDroppedColumns()) > 0 || count($diff->getModifiedColumns()) > 0) { + if ($needsReorg) { $sql[] = "CALL SYSPROC.ADMIN_CMD ('REORG TABLE " . $tableNameSQL . "')"; } @@ -758,7 +764,10 @@ private function getAlterColumnClausesSQL(ColumnDiff $columnDiff): array { $newColumn = $columnDiff->getNewColumn()->toArray(); - $alterClause = 'ALTER COLUMN ' . $columnDiff->getNewColumn()->getQuotedName($this); + $newName = $columnDiff->getNewColumn()->getQuotedName($this); + $oldName = ($columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName())->getQuotedName($this); + + $alterClause = 'ALTER COLUMN ' . $newName; if ($newColumn['columnDefinition'] !== null) { return [$alterClause . ' ' . $newColumn['columnDefinition']]; @@ -766,6 +775,10 @@ private function getAlterColumnClausesSQL(ColumnDiff $columnDiff): array $clauses = []; + if ($columnDiff->hasNameChanged()) { + $clauses[] = 'RENAME COLUMN ' . $oldName . ' TO ' . $newName; + } + if ( $columnDiff->hasTypeChanged() || $columnDiff->hasLengthChanged() || diff --git a/src/Platforms/OraclePlatform.php b/src/Platforms/OraclePlatform.php index 1d4578979a1..eb9b2b36b76 100644 --- a/src/Platforms/OraclePlatform.php +++ b/src/Platforms/OraclePlatform.php @@ -897,13 +897,27 @@ public function getAlterTableSQL(TableDiff $diff) } $fields = []; - foreach ($diff->getModifiedColumns() as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + foreach ($diff->getChangedColumns() as $columnDiff) { + $newColumn = $columnDiff->getNewColumn(); + $newColumnName = $newColumn->getQuotedName($this); + $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); + + $oldColumnName = $oldColumn->getQuotedName($this); + + // Column names in Oracle are case insensitive and automatically uppercased on the server. + if ($columnDiff->hasNameChanged()) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $newColumn, $diff, $columnSql)) { + continue; + } + + $sql = array_merge( + $sql, + $this->getRenameColumnSQL($tableNameSQL, $oldColumnName, $newColumnName), + ); + } elseif ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } - $newColumn = $columnDiff->getNewColumn(); - // Do not generate column alteration clause if type is binary and only fixed property has changed. // Oracle only supports binary type columns with variable length. // Avoids unnecessary table alteration statements. @@ -920,7 +934,7 @@ public function getAlterTableSQL(TableDiff $diff) /** * Do not add query part if only comment has changed */ - if (! ($columnHasChangedComment && count($columnDiff->changedProperties) === 1)) { + if (count($columnDiff->changedProperties) > ($columnHasChangedComment ? 1 : 0)) { $newColumnProperties = $newColumn->toArray(); if (! $columnDiff->hasNotNullChanged()) { @@ -945,17 +959,6 @@ public function getAlterTableSQL(TableDiff $diff) $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' MODIFY (' . implode(', ', $fields) . ')'; } - foreach ($diff->getRenamedColumns() as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { - continue; - } - - $oldColumnName = new Identifier($oldColumnName); - - $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) - . ' TO ' . $column->getQuotedName($this); - } - $fields = []; foreach ($diff->getDroppedColumns() as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { diff --git a/src/Platforms/PostgreSQLPlatform.php b/src/Platforms/PostgreSQLPlatform.php index cb27ee007b7..510c922b586 100644 --- a/src/Platforms/PostgreSQLPlatform.php +++ b/src/Platforms/PostgreSQLPlatform.php @@ -569,11 +569,7 @@ public function getAlterTableSQL(TableDiff $diff) $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query; } - foreach ($diff->getModifiedColumns() as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { - continue; - } - + foreach ($diff->getChangedColumns() as $columnDiff) { if ($this->isUnchangedBinaryColumn($columnDiff)) { continue; } @@ -582,6 +578,20 @@ public function getAlterTableSQL(TableDiff $diff) $newColumn = $columnDiff->getNewColumn(); $oldColumnName = $oldColumn->getQuotedName($this); + $newColumnName = $newColumn->getQuotedName($this); + + if ($columnDiff->hasNameChanged()) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $newColumn, $diff, $columnSql)) { + continue; + } + + $sql = array_merge( + $sql, + $this->getRenameColumnSQL($tableNameSQL, $oldColumnName, $newColumnName), + ); + } elseif ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } if ( $columnDiff->hasTypeChanged() @@ -596,7 +606,7 @@ public function getAlterTableSQL(TableDiff $diff) $columnDefinition['autoincrement'] = false; // here was a server version check before, but DBAL API does not support this anymore. - $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSQLDeclaration($columnDefinition, $this); + $query = 'ALTER ' . $newColumnName . ' TYPE ' . $type->getSQLDeclaration($columnDefinition, $this); $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query; } @@ -605,12 +615,12 @@ public function getAlterTableSQL(TableDiff $diff) ? ' DROP DEFAULT' : ' SET' . $this->getDefaultValueDeclarationSQL($newColumn->toArray()); - $query = 'ALTER ' . $oldColumnName . $defaultClause; + $query = 'ALTER ' . $newColumnName . $defaultClause; $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query; } if ($columnDiff->hasNotNullChanged()) { - $query = 'ALTER ' . $oldColumnName . ' ' . ($newColumn->getNotnull() ? 'SET' : 'DROP') . ' NOT NULL'; + $query = 'ALTER ' . $newColumnName . ' ' . ($newColumn->getNotnull() ? 'SET' : 'DROP') . ' NOT NULL'; $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query; } @@ -619,16 +629,16 @@ public function getAlterTableSQL(TableDiff $diff) // add autoincrement $seqName = $this->getIdentitySequenceName( $table->getName(), - $oldColumnName, + $newColumnName, ); $sql[] = 'CREATE SEQUENCE ' . $seqName; - $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ') FROM ' + $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $newColumnName . ') FROM ' . $tableNameSQL . '))'; - $query = 'ALTER ' . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')"; + $query = 'ALTER ' . $newColumnName . " SET DEFAULT nextval('" . $seqName . "')"; } else { // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have - $query = 'ALTER ' . $oldColumnName . ' DROP DEFAULT'; + $query = 'ALTER ' . $newColumnName . ' DROP DEFAULT'; } $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query; @@ -657,17 +667,6 @@ public function getAlterTableSQL(TableDiff $diff) $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query; } - foreach ($diff->getRenamedColumns() as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { - continue; - } - - $oldColumnName = new Identifier($oldColumnName); - - $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) - . ' TO ' . $column->getQuotedName($this); - } - $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { diff --git a/src/Platforms/SQLServerPlatform.php b/src/Platforms/SQLServerPlatform.php index c8cd20b561c..48789b84acd 100644 --- a/src/Platforms/SQLServerPlatform.php +++ b/src/Platforms/SQLServerPlatform.php @@ -567,17 +567,38 @@ public function getAlterTableSQL(TableDiff $diff) $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); } - foreach ($diff->getModifiedColumns() as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + $tableNameSQL = $table->getQuotedName($this); + + foreach ($diff->getChangedColumns() as $columnDiff) { + $newColumn = $columnDiff->getNewColumn(); + $newColumnName = $newColumn->getQuotedName($this); + + $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); + $oldColumnName = $oldColumn->getQuotedName($this); + $nameChanged = $columnDiff->hasNameChanged(); + + // Column names in SQL server are case insensitive and automatically uppercased on the server. + if ($nameChanged) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $newColumn, $diff, $columnSql)) { + continue; + } + + $sql = array_merge( + $sql, + $this->getRenameColumnSQL($tableNameSQL, $oldColumnName, $newColumnName), + ); + + // Recreate default constraint with new column name if necessary (for future reference). + if ($newColumn->getDefault() === null) { + continue; + } + } elseif ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } - $newColumn = $columnDiff->getNewColumn(); $newComment = $this->getColumnComment($newColumn); $hasNewComment = ! empty($newComment) || is_numeric($newComment); - $oldColumn = $columnDiff->getOldColumn(); - if ($oldColumn instanceof Column) { $oldComment = $this->getColumnComment($oldColumn); $hasOldComment = ! empty($oldComment) || is_numeric($oldComment); @@ -602,33 +623,36 @@ public function getAlterTableSQL(TableDiff $diff) } } - // Do not add query part if only comment has changed. - if ($columnDiff->hasCommentChanged() && count($columnDiff->changedProperties) === 1) { + $columnNameSQL = $newColumn->getQuotedName($this); + + $newDeclarationSQL = $this->getColumnDeclarationSQL($columnNameSQL, $newColumn->toArray()); + if ($oldColumn instanceof Column) { + $oldDeclarationSQL = $this->getColumnDeclarationSQL($columnNameSQL, $oldColumn->toArray()); + $declarationSQLChanged = $newDeclarationSQL !== $oldDeclarationSQL; + } else { + $maxChanged = $columnDiff->hasCommentChanged() ? 1 : 0; + $declarationSQLChanged = count($columnDiff->changedProperties) > $maxChanged; + } + + $defaultChanged = $columnDiff->hasDefaultChanged(); + + if (! $declarationSQLChanged && ! $defaultChanged && ! $nameChanged) { continue; } $requireDropDefaultConstraint = $this->alterColumnRequiresDropDefaultConstraint($columnDiff); if ($requireDropDefaultConstraint) { - $oldColumn = $columnDiff->getOldColumn(); - - if ($oldColumn !== null) { - $oldColumnName = $oldColumn->getName(); - } else { - $oldColumnName = $columnDiff->oldColumnName; - } - $queryParts[] = $this->getAlterTableDropDefaultConstraintClause($tableName, $oldColumnName); } - $columnProperties = $newColumn->toArray(); - - $queryParts[] = 'ALTER COLUMN ' . - $this->getColumnDeclarationSQL($newColumn->getQuotedName($this), $columnProperties); + if ($declarationSQLChanged) { + $queryParts[] = 'ALTER COLUMN ' . $newDeclarationSQL; + } if ( - ! isset($columnProperties['default']) - || (! $requireDropDefaultConstraint && ! $columnDiff->hasDefaultChanged()) + $newColumn->getDefault() === null + || (! $requireDropDefaultConstraint && ! $defaultChanged) ) { continue; } @@ -636,30 +660,6 @@ public function getAlterTableSQL(TableDiff $diff) $queryParts[] = $this->getAlterTableAddDefaultConstraintClause($tableName, $newColumn); } - $tableNameSQL = $table->getQuotedName($this); - - foreach ($diff->getRenamedColumns() as $oldColumnName => $newColumn) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $newColumn, $diff, $columnSql)) { - continue; - } - - $oldColumnName = new Identifier($oldColumnName); - - $sql[] = "sp_rename '" . $tableNameSQL . '.' . $oldColumnName->getQuotedName($this) . - "', '" . $newColumn->getQuotedName($this) . "', 'COLUMN'"; - - // Recreate default constraint with new column name if necessary (for future reference). - if ($newColumn->getDefault() === null) { - continue; - } - - $queryParts[] = $this->getAlterTableDropDefaultConstraintClause( - $tableName, - $oldColumnName->getQuotedName($this), - ); - $queryParts[] = $this->getAlterTableAddDefaultConstraintClause($tableName, $newColumn); - } - $tableSql = []; if ($this->onSchemaAlterTable($diff, $tableSql)) { @@ -700,7 +700,7 @@ public function getAlterTableSQL(TableDiff $diff) public function getRenameTableSQL(string $oldName, string $newName): array { return [ - sprintf('sp_rename %s, %s', $this->quoteStringLiteral($oldName), $this->quoteStringLiteral($newName)), + sprintf('EXEC sp_rename %s, %s', $this->quoteStringLiteral($oldName), $this->quoteStringLiteral($newName)), /* Rename table's default constraints names * to match the new table name. @@ -783,7 +783,7 @@ private function alterColumnRequiresDropDefaultConstraint(ColumnDiff $columnDiff // We need to drop an existing default constraint if the column was // defined with a default value before and the native column type has changed. - return $columnDiff->hasTypeChanged() || $columnDiff->hasFixedChanged(); + return $columnDiff->hasTypeChanged() || $columnDiff->hasFixedChanged() || $columnDiff->hasNameChanged(); } /** @@ -878,6 +878,25 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) ]; } + /** + * Returns the SQL for renaming a column + * + * @param string $tableName The table to rename the column on. + * @param string $oldColumnName The name of the column we want to rename. + * @param string $newColumnName The name we should rename it to. + * + * @return string[] The sequence of SQL statements for renaming the given column. + */ + protected function getRenameColumnSQL(string $tableName, string $oldColumnName, string $newColumnName): array + { + return [sprintf( + "EXEC sp_rename %s, %s, 'COLUMN'", + $this->quoteStringLiteral($tableName . '.' . $oldColumnName), + $this->quoteStringLiteral($newColumnName), + ), + ]; + } + /** * Returns the SQL statement for adding an extended property to a database object. * diff --git a/src/Platforms/SqlitePlatform.php b/src/Platforms/SqlitePlatform.php index e35580c70cb..5d3f8c27f6d 100644 --- a/src/Platforms/SqlitePlatform.php +++ b/src/Platforms/SqlitePlatform.php @@ -1095,36 +1095,20 @@ public function getAlterTableSQL(TableDiff $diff) ); } - foreach ($diff->getRenamedColumns() as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { - continue; - } - - $oldColumnName = strtolower($oldColumnName); - - $columns = $this->replaceColumn( - $table->getName(), - $columns, - $oldColumnName, - $column, - ); - - if (! isset($newColumnNames[$oldColumnName])) { - continue; - } + foreach ($diff->getChangedColumns() as $columnDiff) { + $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); + $newColumn = $columnDiff->getNewColumn(); - $newColumnNames[$oldColumnName] = $column->getQuotedName($this); - } + $oldColumnName = strtolower($oldColumn->getName()); - foreach ($diff->getModifiedColumns() as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + if ($columnDiff->hasNameChanged()) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $newColumn, $diff, $columnSql)) { + continue; + } + } elseif ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } - $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); - - $oldColumnName = strtolower($oldColumn->getName()); - $columns = $this->replaceColumn( $table->getName(), $columns, @@ -1241,7 +1225,7 @@ private function replaceColumn($tableName, array $columns, $columnName, Column $ private function getSimpleAlterTableSQL(TableDiff $diff) { // Suppress changes on integer type autoincrement columns. - foreach ($diff->getModifiedColumns() as $columnDiff) { + foreach ($diff->getChangedColumns() as $columnDiff) { $oldColumn = $columnDiff->getOldColumn(); if ($oldColumn === null) { @@ -1272,9 +1256,8 @@ private function getSimpleAlterTableSQL(TableDiff $diff) } if ( - count($diff->getModifiedColumns()) > 0 + count($diff->getChangedColumns()) > 0 || count($diff->getDroppedColumns()) > 0 - || count($diff->getRenamedColumns()) > 0 || count($diff->getAddedIndexes()) > 0 || count($diff->getModifiedIndexes()) > 0 || count($diff->getDroppedIndexes()) > 0 @@ -1360,13 +1343,7 @@ private function getColumnNamesInAlteredTable(TableDiff $diff, Table $fromTable) unset($columns[$columnName]); } - foreach ($diff->getRenamedColumns() as $oldColumnName => $column) { - $columnName = $column->getName(); - $columns[strtolower($oldColumnName)] = $columnName; - $columns[strtolower($columnName)] = $columnName; - } - - foreach ($diff->getModifiedColumns() as $columnDiff) { + foreach ($diff->getChangedColumns() as $columnDiff) { $oldColumn = $columnDiff->getOldColumn() ?? $columnDiff->getOldColumnName(); $oldColumnName = $oldColumn->getName(); diff --git a/src/Schema/Column.php b/src/Schema/Column.php index e1580178656..95801176903 100644 --- a/src/Schema/Column.php +++ b/src/Schema/Column.php @@ -463,4 +463,13 @@ public function toArray() 'comment' => $this->_comment, ], $this->_platformOptions, $this->_customSchemaOptions); } + + /** @internal To be removed in 4.0 */ + public function cloneWithName(string $name): Column + { + $clone = clone $this; + $clone->_setName($name); + + return $clone; + } } diff --git a/src/Schema/ColumnDiff.php b/src/Schema/ColumnDiff.php index bd1b0eee05f..2ac4c9eb2b2 100644 --- a/src/Schema/ColumnDiff.php +++ b/src/Schema/ColumnDiff.php @@ -5,6 +5,7 @@ use Doctrine\Deprecations\Deprecation; use function in_array; +use function strcasecmp; /** * Represents the change of a column. @@ -78,6 +79,14 @@ public function getNewColumn(): Column return $this->column; } + public function hasNameChanged(): bool + { + $oldColumn = $this->getOldColumn() ?? $this->getOldColumnName(); + + // Column names are case insensitive + return strcasecmp($oldColumn->getName(), $this->getNewColumn()->getName()) !== 0; + } + public function hasTypeChanged(): bool { return $this->hasChanged('type'); diff --git a/src/Schema/Comparator.php b/src/Schema/Comparator.php index 28e7f2f73b2..04c58b80d38 100644 --- a/src/Schema/Comparator.php +++ b/src/Schema/Comparator.php @@ -363,7 +363,29 @@ public function compareTables(Table $fromTable, Table $toTable): TableDiff ); } - $renamedColumns = $this->detectRenamedColumns($addedColumns, $droppedColumns); + $renamedColumnNames = $toTable->getRenamedColumns(); + + foreach ($addedColumns as $addedColumnName => $addedColumn) { + if (! isset($renamedColumnNames[$addedColumn->getName()])) { + continue; + } + + $removedColumnName = $renamedColumnNames[$addedColumn->getName()]; + // Explicitly renamed columns need to be diffed, because their types can also have changed + $modifiedColumns[$removedColumnName] = new ColumnDiff( + $removedColumnName, + $addedColumn, + $this->diffColumn($droppedColumns[$removedColumnName], $addedColumn), + $droppedColumns[$removedColumnName], + ); + + unset( + $addedColumns[$addedColumnName], + $droppedColumns[$removedColumnName], + ); + } + + $this->detectRenamedColumns($modifiedColumns, $addedColumns, $droppedColumns); $fromTableIndexes = $fromTable->getIndexes(); $toTableIndexes = $toTable->getIndexes(); @@ -439,7 +461,6 @@ public function compareTables(Table $fromTable, Table $toTable): TableDiff $addedForeignKeys, $modifiedForeignKeys, $droppedForeignKeys, - $renamedColumns, $renamedIndexes, ); } @@ -448,14 +469,13 @@ public function compareTables(Table $fromTable, Table $toTable): TableDiff * Try to find columns that only changed their name, rename operations maybe cheaper than add/drop * however ambiguities between different possibilities should not lead to renaming at all. * - * @param array $addedColumns - * @param array $removedColumns - * - * @return array + * @param array $modifiedColumns + * @param array $addedColumns + * @param array $removedColumns * * @throws Exception */ - private function detectRenamedColumns(array &$addedColumns, array &$removedColumns): array + private function detectRenamedColumns(array &$modifiedColumns, array &$addedColumns, array &$removedColumns): void { $candidatesByName = []; @@ -469,8 +489,6 @@ private function detectRenamedColumns(array &$addedColumns, array &$removedColum } } - $renamedColumns = []; - foreach ($candidatesByName as $candidates) { if (count($candidates) !== 1) { continue; @@ -480,18 +498,22 @@ private function detectRenamedColumns(array &$addedColumns, array &$removedColum $removedColumnName = $removedColumn->getName(); $addedColumnName = strtolower($addedColumn->getName()); - if (isset($renamedColumns[$removedColumnName])) { + if (isset($modifiedColumns[$removedColumnName])) { continue; } - $renamedColumns[$removedColumnName] = $addedColumn; + $modifiedColumns[$removedColumnName] = new ColumnDiff( + $removedColumnName, + $addedColumn, + $this->diffColumn($addedColumn, $removedColumn), + $removedColumn, + ); + unset( $addedColumns[$addedColumnName], $removedColumns[strtolower($removedColumnName)], ); } - - return $renamedColumns; } /** diff --git a/src/Schema/Table.php b/src/Schema/Table.php index ce4cc3260f1..d2680cfceb8 100644 --- a/src/Schema/Table.php +++ b/src/Schema/Table.php @@ -7,12 +7,14 @@ use Doctrine\DBAL\Schema\Visitor\Visitor; use Doctrine\DBAL\Types\Type; use Doctrine\Deprecations\Deprecation; +use LogicException; use function array_filter; use function array_keys; use function array_merge; use function in_array; use function preg_match; +use function sprintf; use function strlen; use function strtolower; @@ -26,6 +28,9 @@ class Table extends AbstractAsset /** @var Column[] */ protected $_columns = []; + /** @var array keys are new names, values are old names */ + protected array $renamedColumns = []; + /** @var Index[] */ protected $_indexes = []; @@ -346,6 +351,48 @@ public function addColumn($name, $typeName, array $options = []) return $column; } + /** @return array */ + final public function getRenamedColumns(): array + { + return $this->renamedColumns; + } + + /** + * @throws LogicException + * @throws SchemaException + */ + final public function renameColumn(string $oldName, string $newName): Column + { + $oldName = $this->normalizeIdentifier($oldName); + $newName = $this->normalizeIdentifier($newName); + + if ($oldName === $newName) { + throw new LogicException(sprintf( + 'Attempt to rename column "%s.%s" to the same name.', + $this->getName(), + $oldName, + )); + } + + $column = $this->getColumn($oldName); + $column->_setName($newName); + unset($this->_columns[$oldName]); + $this->_addColumn($column); + + // If a column is renamed multiple times, we only want to know the original and last new name + if (isset($this->renamedColumns[$oldName])) { + $toRemove = $oldName; + $oldName = $this->renamedColumns[$oldName]; + unset($this->renamedColumns[$toRemove]); + } + + if ($newName !== $oldName) { + $this->renamedColumns[$newName] = $oldName; + } + + return $column; + } + /** * Change Column Details. * diff --git a/src/Schema/TableDiff.php b/src/Schema/TableDiff.php index 9aaf9e7702f..4d83fbf1a04 100644 --- a/src/Schema/TableDiff.php +++ b/src/Schema/TableDiff.php @@ -8,6 +8,9 @@ use function array_filter; use function array_values; use function count; +use function current; +use function func_get_arg; +use function func_num_args; /** * Table Diff. @@ -40,7 +43,7 @@ class TableDiff /** * All modified columns * - * @internal Use {@see getModifiedColumns()} instead. + * @internal Use {@see getChangedColumns()} instead. * * @var ColumnDiff[] */ @@ -55,15 +58,6 @@ class TableDiff */ public $removedColumns = []; - /** - * Columns that are only renamed from key to column instance name. - * - * @internal Use {@see getRenamedColumns()} instead. - * - * @var Column[] - */ - public $renamedColumns = []; - /** * All added indexes. * @@ -139,7 +133,6 @@ class TableDiff * * @internal The diff can be only instantiated by a {@see Comparator}. * - * @param string $tableName * @param array $addedColumns * @param array $modifiedColumns * @param array $droppedColumns @@ -149,28 +142,25 @@ class TableDiff * @param list $addedForeignKeys * @param list $changedForeignKeys * @param list $removedForeignKeys - * @param array $renamedColumns * @param array $renamedIndexes */ public function __construct( - $tableName, - $addedColumns = [], - $modifiedColumns = [], - $droppedColumns = [], - $addedIndexes = [], - $changedIndexes = [], - $removedIndexes = [], + string $tableName, + array $addedColumns = [], + array $modifiedColumns = [], + array $droppedColumns = [], + array $addedIndexes = [], + array $changedIndexes = [], + array $removedIndexes = [], ?Table $fromTable = null, - $addedForeignKeys = [], - $changedForeignKeys = [], - $removedForeignKeys = [], - $renamedColumns = [], - $renamedIndexes = [] + array $addedForeignKeys = [], + array $changedForeignKeys = [], + array $removedForeignKeys = [], + array $renamedIndexes = [] ) { $this->name = $tableName; $this->addedColumns = $addedColumns; $this->changedColumns = $modifiedColumns; - $this->renamedColumns = $renamedColumns; $this->removedColumns = $droppedColumns; $this->addedIndexes = $addedIndexes; $this->changedIndexes = $changedIndexes; @@ -189,9 +179,50 @@ public function __construct( ); } + if (func_num_args() > 12 || (count($renamedIndexes) > 0 && current($renamedIndexes) instanceof Column)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/6080', + 'Passing $renamedColumns to %s is deprecated and will no longer be possible in the next major.', + __METHOD__, + ); + /** @var array $renamedColumns */ + $renamedColumns = $renamedIndexes; + $this->convertLegacyRenamedColumn($renamedColumns); + $this->renamedIndexes = func_num_args() > 12 ? func_get_arg(12) : []; + } + $this->fromTable = $fromTable; } + /** @param array $renamedColumns */ + private function convertLegacyRenamedColumn(array $renamedColumns): void + { + $changedColumns = []; + foreach ($this->changedColumns as $key => $column) { + $oldName = isset($column->fromColumn) + ? $column->fromColumn->getName() + : $column->oldColumnName; + $changedColumns[$oldName] = $key; + } + + foreach ($renamedColumns as $oldName => $column) { + if (isset($changedColumns[$oldName])) { + $i = $changedColumns[$oldName]; + $existingCol = $this->changedColumns[$changedColumns[$oldName]]; + $column = $existingCol->getNewColumn()->cloneWithName($column->getName()); + $this->changedColumns[$i] = new ColumnDiff( + $oldName, + $column, + $existingCol->changedProperties, + $existingCol->getOldColumn(), + ); + } else { + $this->changedColumns[] = new ColumnDiff($oldName, $column, []); + } + } + } + /** * @deprecated Use {@see getOldTable()} instead. * @@ -238,8 +269,27 @@ public function getAddedColumns(): array return array_values($this->addedColumns); } - /** @return list */ + /** + * @deprecated Use {@see getChangedColumns()} instead. + * + * @return list + */ public function getModifiedColumns(): array + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/6080', + '%s is deprecated, use `getModifiedColumns()` instead.', + __METHOD__, + ); + + return array_values(array_filter($this->getChangedColumns(), static function (ColumnDiff $diff) { + return count($diff->changedProperties) > 0; + })); + } + + /** @return array */ + public function getChangedColumns(): array { return array_values($this->changedColumns); } @@ -250,10 +300,30 @@ public function getDroppedColumns(): array return array_values($this->removedColumns); } - /** @return array */ + /** + * @deprecated Use {@see getModifiedColumns()} instead. + * + * @return array + */ public function getRenamedColumns(): array { - return $this->renamedColumns; + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/6080', + '%s is deprecated, you should use `getModifiedColumns()` instead.', + __METHOD__, + ); + $renamed = []; + foreach ($this->getChangedColumns() as $diff) { + if (! $diff->hasNameChanged()) { + continue; + } + + $oldColumnName = ($diff->getOldColumn() ?? $diff->getOldColumnName())->getName(); + $renamed[$oldColumnName] = $diff->getNewColumn(); + } + + return $renamed; } /** @return list */ @@ -349,7 +419,6 @@ public function isEmpty(): bool return count($this->addedColumns) === 0 && count($this->changedColumns) === 0 && count($this->removedColumns) === 0 - && count($this->renamedColumns) === 0 && count($this->addedIndexes) === 0 && count($this->changedIndexes) === 0 && count($this->removedIndexes) === 0 @@ -358,4 +427,46 @@ public function isEmpty(): bool && count($this->changedForeignKeys) === 0 && count($this->removedForeignKeys) === 0; } + + /** Deprecation layer, to be removed in 4.0 */ + public function __isset(string $name): bool + { + return $name === 'renamedColumns'; + } + + /** @param mixed $val */ + public function __set(string $name, $val): void + { + if ($name === 'renamedColumns') { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/6080', + 'Modifying $renamedColumns is deprecated, this property will be removed in the next major. ' . + 'Set $modifiedColumns in the constructor instead', + __METHOD__, + ); + $this->convertLegacyRenamedColumn($val); + } else { + /** @phpstan-ignore-next-line */ + $this->$name = $val; + } + } + + /** @return mixed */ + public function __get(string $name) + { + if ($name === 'renamedColumns') { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/6080', + 'Property %s is deprecated, you should use `getModifiedColumns()` instead.', + $name, + ); + + return $this->getRenamedColumns(); + } + + /** @phpstan-ignore-next-line */ + return $this->$name; + } } diff --git a/tests/Functional/Platform/RenameColumnTest.php b/tests/Functional/Platform/RenameColumnTest.php index 9ec0c0a1394..cf1158006ea 100644 --- a/tests/Functional/Platform/RenameColumnTest.php +++ b/tests/Functional/Platform/RenameColumnTest.php @@ -5,15 +5,17 @@ use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Tests\FunctionalTestCase; +use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use function array_keys; +use function array_values; use function strtolower; class RenameColumnTest extends FunctionalTestCase { /** @dataProvider columnNameProvider */ - public function testColumnPositionRetainedAfterRenaming(string $columnName, string $newColumnName): void + public function testColumnPositionRetainedAfterImplicitRenaming(string $columnName, string $newColumnName): void { $table = new Table('test_rename'); $table->addColumn($columnName, Types::STRING); @@ -33,6 +35,34 @@ public function testColumnPositionRetainedAfterRenaming(string $columnName, stri $table = $sm->introspectTable('test_rename'); self::assertSame([strtolower($newColumnName), 'c2'], array_keys($table->getColumns())); + self::assertCount(1, $diff->getRenamedColumns()); + } + + /** @dataProvider columnNameProvider */ + public function testColumnPositionRetainedAfterExplicitRenaming(string $columnName, string $newColumnName): void + { + $table = new Table('test_rename'); + $table->addColumn($columnName, Types::INTEGER, ['length' => 16]); + $table->addColumn('c2', Types::INTEGER); + + $this->dropAndCreateTable($table); + + // Force a different type to make sure it's not being caught implicitly + $table->renameColumn($columnName, $newColumnName)->setType(Type::getType(Types::BIGINT))->setLength(32); + + $sm = $this->connection->createSchemaManager(); + $diff = $sm->createComparator() + ->compareTables($sm->introspectTable('test_rename'), $table); + + $sm->alterTable($diff); + + $table = $sm->introspectTable('test_rename'); + $columns = array_values($table->getColumns()); + + self::assertCount(1, $diff->getChangedColumns()); + self::assertCount(2, $columns); + self::assertEqualsIgnoringCase($newColumnName, $columns[0]->getName()); + self::assertEqualsIgnoringCase('c2', $columns[1]->getName()); } /** @return iterable */ diff --git a/tests/Functional/Schema/ComparatorTest.php b/tests/Functional/Schema/ComparatorTest.php index 9cf71c48376..7dc9f8fe124 100644 --- a/tests/Functional/Schema/ComparatorTest.php +++ b/tests/Functional/Schema/ComparatorTest.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Tests\FunctionalTestCase; +use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use function array_merge; @@ -52,6 +53,57 @@ public function testDefaultValueComparison(callable $comparatorFactory, string $ self::assertFalse($comparatorFactory($this->schemaManager)->diffTable($table, $onlineTable)); } + public function testRenameColumnComparison(): void + { + $comparator = new Comparator(); + + $table = new Table('rename_table'); + $table->addColumn('test', Types::STRING, ['default' => 'baz', 'length' => 20]); + $table->addColumn('test2', Types::STRING, ['default' => 'baz', 'length' => 20]); + $table->addColumn('test3', Types::STRING, ['default' => 'foo', 'length' => 10]); + + $onlineTable = clone $table; + $table->renameColumn('test', 'baz') + ->setLength(40) + ->setComment('Comment'); + + $table->renameColumn('test2', 'foo'); + + $table->getColumn('test3') + ->setAutoincrement(true) + ->setNotnull(false) + ->setType(Type::getType(Types::BIGINT)); + + $compareResult = $comparator->compareTables($onlineTable, $table); + self::assertCount(3, $compareResult->getChangedColumns()); + self::assertCount(2, $compareResult->getRenamedColumns()); + self::assertCount(2, $compareResult->getModifiedColumns()); + self::assertArrayHasKey('test2', $compareResult->getRenamedColumns()); + + $renamedOnly = $compareResult->changedColumns['test2']; + $renamedAndModified = $compareResult->changedColumns['test']; + $modifiedOnly = $compareResult->changedColumns['test3']; + + self::assertEquals('foo', $renamedOnly->getNewColumn()->getName()); + self::assertTrue($renamedOnly->hasNameChanged()); + self::assertCount(0, $renamedOnly->changedProperties); + + self::assertEquals('baz', $renamedAndModified->getNewColumn()->getName()); + self::assertTrue($renamedAndModified->hasNameChanged()); + self::assertTrue($renamedAndModified->hasLengthChanged()); + self::assertTrue($renamedAndModified->hasCommentChanged()); + self::assertFalse($renamedAndModified->hasTypeChanged()); + self::assertCount(2, $renamedAndModified->changedProperties); + + self::assertTrue($modifiedOnly->hasAutoIncrementChanged()); + self::assertTrue($modifiedOnly->hasNotNullChanged()); + self::assertTrue($modifiedOnly->hasTypeChanged()); + self::assertFalse($modifiedOnly->hasLengthChanged()); + self::assertFalse($modifiedOnly->hasCommentChanged()); + self::assertFalse($modifiedOnly->hasNameChanged()); + self::assertCount(3, $modifiedOnly->changedProperties); + } + /** @return iterable */ public static function defaultValueProvider(): iterable { diff --git a/tests/Platforms/AbstractMySQLPlatformTestCase.php b/tests/Platforms/AbstractMySQLPlatformTestCase.php index 8228b73ccb5..84c24b95037 100644 --- a/tests/Platforms/AbstractMySQLPlatformTestCase.php +++ b/tests/Platforms/AbstractMySQLPlatformTestCase.php @@ -756,9 +756,9 @@ protected function getQuotedAlterTableRenameColumnSQL(): array "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 `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'", ]; } diff --git a/tests/Platforms/AbstractPlatformTestCase.php b/tests/Platforms/AbstractPlatformTestCase.php index cf7dc522894..ac6927965d4 100644 --- a/tests/Platforms/AbstractPlatformTestCase.php +++ b/tests/Platforms/AbstractPlatformTestCase.php @@ -3,6 +3,12 @@ namespace Doctrine\DBAL\Tests\Platforms; use Doctrine\Common\EventManager; +use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs; +use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs; +use Doctrine\DBAL\Event\SchemaAlterTableEventArgs; +use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs; +use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs; +use Doctrine\DBAL\Event\SchemaEventArgs; use Doctrine\DBAL\Events; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception\InvalidLockMode; @@ -355,19 +361,24 @@ public function testGetAlterTableSqlDispatchEvent(): void $listenerMock = $this->createMock(GetAlterTableSqlDispatchEventListener::class); $listenerMock ->expects(self::once()) - ->method('onSchemaAlterTable'); + ->method('onSchemaAlterTable') + ->willReturnCallback(static fn (SchemaEventArgs $args) => $args->preventDefault()); $listenerMock ->expects(self::once()) - ->method('onSchemaAlterTableAddColumn'); + ->method('onSchemaAlterTableAddColumn') + ->willReturnCallback(static fn (SchemaEventArgs $args) => $args->preventDefault()); $listenerMock ->expects(self::once()) - ->method('onSchemaAlterTableRemoveColumn'); + ->method('onSchemaAlterTableRemoveColumn') + ->willReturnCallback(static fn (SchemaEventArgs $args) => $args->preventDefault()); $listenerMock ->expects(self::once()) - ->method('onSchemaAlterTableChangeColumn'); + ->method('onSchemaAlterTableChangeColumn') + ->willReturnCallback(static fn (SchemaEventArgs $args) => $args->preventDefault()); $listenerMock ->expects(self::once()) - ->method('onSchemaAlterTableRenameColumn'); + ->method('onSchemaAlterTableRenameColumn') + ->willReturnCallback(static fn (SchemaEventArgs $args) => $args->preventDefault()); $eventManager = new EventManager(); $events = [ @@ -393,13 +404,16 @@ public function testGetAlterTableSqlDispatchEvent(): void $tableDiff->changedColumns['changed'] = new ColumnDiff( 'changed', new Column( - 'changed2', + 'changed', Type::getType(Types::STRING), [], ), [], ); - $tableDiff->renamedColumns['renamed'] = new Column('renamed2', Type::getType(Types::INTEGER), []); + $tableDiff->changedColumns['renamed'] = new ColumnDiff( + 'renamed', + new Column('renamed2', Type::getType(Types::INTEGER), []), + ); $this->platform->getAlterTableSQL($tableDiff); } @@ -1196,8 +1210,8 @@ public function testReturnsGuidTypeDeclarationSQL(): void public function testGeneratesAlterTableRenameColumnSQL(): void { - $table = new Table('foo'); - $table->addColumn( + $table = new Table('foo'); + $oldColumn = $table->addColumn( 'bar', Types::INTEGER, ['notnull' => true, 'default' => 666, 'comment' => 'rename test'], @@ -1205,11 +1219,12 @@ public function testGeneratesAlterTableRenameColumnSQL(): void $tableDiff = new TableDiff('foo'); $tableDiff->fromTable = $table; - $tableDiff->renamedColumns['bar'] = new Column( + $newColumn = new Column( 'baz', Type::getType(Types::INTEGER), ['notnull' => true, 'default' => 666, 'comment' => 'rename test'], ); + $tableDiff->changedColumns['bar'] = new ColumnDiff('bar', $newColumn, [], $oldColumn); self::assertSame($this->getAlterTableRenameColumnSQL(), $this->platform->getAlterTableSQL($tableDiff)); } @@ -1431,15 +1446,15 @@ public function onSchemaCreateTableColumn(): void; interface GetAlterTableSqlDispatchEventListener { - public function onSchemaAlterTable(): void; + public function onSchemaAlterTable(SchemaAlterTableEventArgs $args): void; - public function onSchemaAlterTableAddColumn(): void; + public function onSchemaAlterTableAddColumn(SchemaAlterTableAddColumnEventArgs $args): void; - public function onSchemaAlterTableRemoveColumn(): void; + public function onSchemaAlterTableRemoveColumn(SchemaAlterTableRemoveColumnEventArgs $args): void; - public function onSchemaAlterTableChangeColumn(): void; + public function onSchemaAlterTableChangeColumn(SchemaAlterTableChangeColumnEventArgs $args): void; - public function onSchemaAlterTableRenameColumn(): void; + public function onSchemaAlterTableRenameColumn(SchemaAlterTableRenameColumnEventArgs $args): void; } interface GetDropTableSqlDispatchEventListener diff --git a/tests/Platforms/DB2PlatformTest.php b/tests/Platforms/DB2PlatformTest.php index 1faa038ffe0..377958963c0 100644 --- a/tests/Platforms/DB2PlatformTest.php +++ b/tests/Platforms/DB2PlatformTest.php @@ -128,7 +128,8 @@ public function getAlterTableColumnCommentsSQL(): array { return [ 'ALTER TABLE mytable ' . - 'ADD COLUMN quota INTEGER NOT NULL WITH DEFAULT', + 'ADD COLUMN quota INTEGER NOT NULL WITH DEFAULT ' . + 'RENAME COLUMN bar TO baz', "CALL SYSPROC.ADMIN_CMD ('REORG TABLE mytable')", "COMMENT ON COLUMN mytable.quota IS 'A comment'", "COMMENT ON COLUMN mytable.foo IS ''", @@ -479,9 +480,9 @@ protected function getQuotedAlterTableRenameColumnSQL(): array 'RENAME COLUMN "create" TO reserved_keyword ' . 'RENAME COLUMN "table" TO "from" ' . 'RENAME COLUMN "select" TO "bar" ' . - 'RENAME COLUMN quoted1 TO quoted ' . - 'RENAME COLUMN quoted2 TO "and" ' . - 'RENAME COLUMN quoted3 TO "baz"', + 'RENAME COLUMN "quoted1" TO quoted ' . + 'RENAME COLUMN "quoted2" TO "and" ' . + 'RENAME COLUMN "quoted3" TO "baz"', ]; } diff --git a/tests/Platforms/OraclePlatformTest.php b/tests/Platforms/OraclePlatformTest.php index 9593612d55c..f582b8ff27f 100644 --- a/tests/Platforms/OraclePlatformTest.php +++ b/tests/Platforms/OraclePlatformTest.php @@ -398,6 +398,7 @@ public function getAlterTableColumnCommentsSQL(): array { return [ 'ALTER TABLE mytable ADD (quota NUMBER(10) NOT NULL)', + 'ALTER TABLE mytable RENAME COLUMN bar TO baz', "COMMENT ON COLUMN mytable.quota IS 'A comment'", "COMMENT ON COLUMN mytable.foo IS ''", "COMMENT ON COLUMN mytable.baz IS 'B comment'", @@ -496,6 +497,7 @@ public function testAlterTableNotNULL(): void ); $expectedSql = [ + 'ALTER TABLE mytable RENAME COLUMN bar TO baz', "ALTER TABLE mytable MODIFY (foo VARCHAR2(255) DEFAULT 'bla', baz VARCHAR2(255) DEFAULT 'bla' NOT NULL, " . 'metar VARCHAR2(2000) DEFAULT NULL NULL)', ]; @@ -615,9 +617,9 @@ protected function getQuotedAlterTableRenameColumnSQL(): array 'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword', 'ALTER TABLE mytable RENAME COLUMN "table" TO "from"', 'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"', - 'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted', - 'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"', - 'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"', + 'ALTER TABLE mytable RENAME COLUMN "quoted1" TO quoted', + 'ALTER TABLE mytable RENAME COLUMN "quoted2" TO "and"', + 'ALTER TABLE mytable RENAME COLUMN "quoted3" TO "baz"', ]; } diff --git a/tests/Platforms/PostgreSQLPlatformTest.php b/tests/Platforms/PostgreSQLPlatformTest.php index 614eb45f8f7..d9687f0182f 100644 --- a/tests/Platforms/PostgreSQLPlatformTest.php +++ b/tests/Platforms/PostgreSQLPlatformTest.php @@ -361,6 +361,7 @@ public function getAlterTableColumnCommentsSQL(): array { return [ 'ALTER TABLE mytable ADD quota INT NOT NULL', + 'ALTER TABLE mytable RENAME COLUMN bar TO baz', "COMMENT ON COLUMN mytable.quota IS 'A comment'", 'COMMENT ON COLUMN mytable.foo IS NULL', "COMMENT ON COLUMN mytable.baz IS 'B comment'", @@ -783,9 +784,9 @@ protected function getQuotedAlterTableRenameColumnSQL(): array 'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword', 'ALTER TABLE mytable RENAME COLUMN "table" TO "from"', 'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"', - 'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted', - 'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"', - 'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"', + 'ALTER TABLE mytable RENAME COLUMN "quoted1" TO quoted', + 'ALTER TABLE mytable RENAME COLUMN "quoted2" TO "and"', + 'ALTER TABLE mytable RENAME COLUMN "quoted3" TO "baz"', ]; } diff --git a/tests/Platforms/SQLServerPlatformTest.php b/tests/Platforms/SQLServerPlatformTest.php index 2a38f0e7310..230b6d55e64 100644 --- a/tests/Platforms/SQLServerPlatformTest.php +++ b/tests/Platforms/SQLServerPlatformTest.php @@ -740,6 +740,7 @@ public function getCreateTableColumnCommentsSQL(): array public function getAlterTableColumnCommentsSQL(): array { return [ + "EXEC sp_rename 'mytable.bar', 'baz', 'COLUMN'", 'ALTER TABLE mytable ADD quota INT NOT NULL', "EXEC sp_addextendedproperty N'MS_Description', N'A comment', " . "N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', quota", @@ -895,8 +896,10 @@ public function testGeneratesAlterTableSQLWithColumnComments(): void $tableDiff->addedColumns['added_comment_with_string_literal_char'] = new Column('added_comment_with_string_literal_char', Type::getType(Types::STRING), ['comment' => "''"]); - $tableDiff->renamedColumns['comment_float_0'] - = new Column('comment_double_0', Type::getType(Types::DECIMAL), ['comment' => 'Double for real!']); + $tableDiff->changedColumns['comment_float_0'] = new ColumnDiff( + 'comment_float_0', + new Column('comment_double_0', Type::getType(Types::DECIMAL), ['comment' => 'Double for real!']), + ); // Add comment to non-commented column. $tableDiff->changedColumns['id'] = new ColumnDiff( @@ -990,7 +993,7 @@ public function testGeneratesAlterTableSQLWithColumnComments(): void $tableDiff->changedColumns['comment_with_string_literal_char'] = new ColumnDiff( 'comment_with_string_literal_char', new Column('comment_with_string_literal_char', Type::getType(Types::STRING), ['comment' => "'"]), - ['comment'], + ['comment', 'type'], new Column('comment_with_string_literal_char', Type::getType(Types::ARRAY), ['comment' => "O'Reilly"]), ); @@ -1000,7 +1003,7 @@ public function testGeneratesAlterTableSQLWithColumnComments(): void self::assertEquals( [ // Renamed columns. - "sp_rename 'mytable.comment_float_0', 'comment_double_0', 'COLUMN'", + "EXEC sp_rename 'mytable.comment_float_0', 'comment_double_0', 'COLUMN'", // Added columns. 'ALTER TABLE mytable ADD added_comment_none INT NOT NULL', @@ -1022,7 +1025,7 @@ public function testGeneratesAlterTableSQLWithColumnComments(): void 'ALTER TABLE mytable ALTER COLUMN [comment_quoted] VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN [create] VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN commented_type INT NOT NULL', - + 'ALTER TABLE mytable ALTER COLUMN comment_with_string_literal_char NVARCHAR(255) NOT NULL', // Added columns. "EXEC sp_addextendedproperty N'MS_Description', N'0', " . "N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_integer_0", @@ -1239,15 +1242,15 @@ public function testChangeColumnsTypeWithDefaultValue(): void protected function getQuotedAlterTableRenameColumnSQL(): array { return [ - "sp_rename 'mytable.unquoted1', 'unquoted', 'COLUMN'", - "sp_rename 'mytable.unquoted2', '[where]', 'COLUMN'", - "sp_rename 'mytable.unquoted3', '[foo]', 'COLUMN'", - "sp_rename 'mytable.[create]', 'reserved_keyword', 'COLUMN'", - "sp_rename 'mytable.[table]', '[from]', 'COLUMN'", - "sp_rename 'mytable.[select]', '[bar]', 'COLUMN'", - "sp_rename 'mytable.quoted1', 'quoted', 'COLUMN'", - "sp_rename 'mytable.quoted2', '[and]', 'COLUMN'", - "sp_rename 'mytable.quoted3', '[baz]', 'COLUMN'", + "EXEC sp_rename 'mytable.unquoted1', 'unquoted', 'COLUMN'", + "EXEC sp_rename 'mytable.unquoted2', '[where]', 'COLUMN'", + "EXEC sp_rename 'mytable.unquoted3', '[foo]', 'COLUMN'", + "EXEC sp_rename 'mytable.[create]', 'reserved_keyword', 'COLUMN'", + "EXEC sp_rename 'mytable.[table]', '[from]', 'COLUMN'", + "EXEC sp_rename 'mytable.[select]', '[bar]', 'COLUMN'", + "EXEC sp_rename 'mytable.[quoted1]', 'quoted', 'COLUMN'", + "EXEC sp_rename 'mytable.[quoted2]', '[and]', 'COLUMN'", + "EXEC sp_rename 'mytable.[quoted3]', '[baz]', 'COLUMN'", ]; } @@ -1427,7 +1430,6 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL(): iterable "CONSTRAINT DF_6B2BD609_4AD86123 DEFAULT 'foo'", 'ALTER TABLE mytable DROP COLUMN removecolumn', 'ALTER TABLE mytable DROP CONSTRAINT DF_6B2BD609_9BADD926', - 'ALTER TABLE mytable ALTER COLUMN mycolumn NVARCHAR(255) NOT NULL', "ALTER TABLE mytable ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'bar' FOR mycolumn", ], ], @@ -1451,7 +1453,6 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL(): iterable "CONSTRAINT DF_6B2BD609_4AD86123 DEFAULT 'foo'", 'ALTER TABLE [mytable] DROP COLUMN [removecolumn]', 'ALTER TABLE [mytable] DROP CONSTRAINT DF_6B2BD609_9BADD926', - 'ALTER TABLE [mytable] ALTER COLUMN [mycolumn] NVARCHAR(255) NOT NULL', "ALTER TABLE [mytable] ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'bar' FOR [mycolumn]", ], ], @@ -1475,7 +1476,6 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL(): iterable "CONSTRAINT DF_F6298F46_FD1A73E7 DEFAULT 'foo'", 'ALTER TABLE [table] DROP COLUMN [drop]', 'ALTER TABLE [table] DROP CONSTRAINT DF_F6298F46_4BF2EAC0', - 'ALTER TABLE [table] ALTER COLUMN [select] NVARCHAR(255) NOT NULL', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'bar' FOR [select]", ], ], @@ -1499,7 +1499,6 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL(): iterable "CONSTRAINT DF_F6298F46_FD1A73E7 DEFAULT 'foo'", 'ALTER TABLE [table] DROP COLUMN [drop]', 'ALTER TABLE [table] DROP CONSTRAINT DF_F6298F46_4BF2EAC0', - 'ALTER TABLE [table] ALTER COLUMN [select] NVARCHAR(255) NOT NULL', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'bar' FOR [select]", ], ], @@ -1517,7 +1516,7 @@ public function testReturnsGuidTypeDeclarationSQL(): void public function getAlterTableRenameColumnSQL(): array { return [ - "sp_rename 'foo.bar', 'baz', 'COLUMN'", + "EXEC sp_rename 'foo.bar', 'baz', 'COLUMN'", 'ALTER TABLE foo DROP CONSTRAINT DF_8C736521_76FF8CAA', 'ALTER TABLE foo ADD CONSTRAINT DF_8C736521_78240498 DEFAULT 666 FOR baz', ]; diff --git a/tests/Platforms/SqlitePlatformTest.php b/tests/Platforms/SqlitePlatformTest.php index 94de2f0db73..e6c7220af2e 100644 --- a/tests/Platforms/SqlitePlatformTest.php +++ b/tests/Platforms/SqlitePlatformTest.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Schema\Column; +use Doctrine\DBAL\Schema\ColumnDiff; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\TransactionIsolationLevel; @@ -333,7 +334,8 @@ public function testRenameNonExistingColumn(): void $tableDiff = new TableDiff('test'); $tableDiff->fromTable = $table; - $tableDiff->renamedColumns['value'] = new Column('data', Type::getType(Types::STRING)); + $newCol = new Column('data', Type::getType(Types::STRING)); + $tableDiff->changedColumns['value'] = new ColumnDiff('value', $newCol); $this->expectException(Exception::class); $this->platform->getAlterTableSQL($tableDiff); @@ -405,8 +407,14 @@ public function testAlterTable(): void $diff = new TableDiff('user'); $diff->fromTable = $table; $diff->newName = 'client'; - $diff->renamedColumns['id'] = new Column('key', Type::getType(Types::INTEGER), []); - $diff->renamedColumns['post'] = new Column('comment', Type::getType(Types::INTEGER), []); + $diff->changedColumns['id'] = new ColumnDiff( + 'id', + new Column('key', Type::getType(Types::INTEGER), []), + ); + $diff->changedColumns['post'] = new ColumnDiff( + 'post', + new Column('comment', Type::getType(Types::INTEGER), []), + ); $diff->removedColumns['parent'] = new Column('parent', Type::getType(Types::INTEGER), []); $diff->removedIndexes['index1'] = $table->getIndex('index1'); diff --git a/tests/Schema/AbstractComparatorTestCase.php b/tests/Schema/AbstractComparatorTestCase.php index a087202628f..569b28a5419 100644 --- a/tests/Schema/AbstractComparatorTestCase.php +++ b/tests/Schema/AbstractComparatorTestCase.php @@ -261,12 +261,12 @@ public function testCompareChangeColumnsMultipleNewColumnsRename(): void $tableDiff = $this->comparator->diffTable($tableA, $tableB); self::assertNotFalse($tableDiff); - self::assertCount(1, $tableDiff->renamedColumns); - self::assertArrayHasKey('datecolumn1', $tableDiff->renamedColumns); - self::assertCount(1, $tableDiff->addedColumns); + self::assertCount(1, $tableDiff->getRenamedColumns()); + self::assertArrayHasKey('datecolumn1', $tableDiff->getRenamedColumns()); + self::assertCount(1, $tableDiff->getAddedColumns()); self::assertArrayHasKey('new_datecolumn2', $tableDiff->addedColumns); - self::assertCount(0, $tableDiff->removedColumns); - self::assertCount(0, $tableDiff->changedColumns); + self::assertCount(0, $tableDiff->getDroppedColumns()); + self::assertCount(0, $tableDiff->getModifiedColumns()); } public function testCompareRemovedIndex(): void @@ -714,10 +714,10 @@ public function testDetectRenameColumn(): void $tableDiff = $this->comparator->diffTable($tableA, $tableB); self::assertNotFalse($tableDiff); - self::assertCount(0, $tableDiff->addedColumns); - self::assertCount(0, $tableDiff->removedColumns); - self::assertArrayHasKey('foo', $tableDiff->renamedColumns); - self::assertEquals('bar', $tableDiff->renamedColumns['foo']->getName()); + self::assertCount(0, $tableDiff->getAddedColumns()); + self::assertCount(0, $tableDiff->getDroppedColumns()); + self::assertArrayHasKey('foo', $tableDiff->changedColumns); + self::assertEquals('bar', $tableDiff->changedColumns['foo']->getNewColumn()->getName()); } /** @@ -742,7 +742,7 @@ public function testDetectRenameColumnAmbiguous(): void self::assertCount(2, $tableDiff->removedColumns); self::assertArrayHasKey('foo', $tableDiff->removedColumns); self::assertArrayHasKey('bar', $tableDiff->removedColumns); - self::assertCount(0, $tableDiff->renamedColumns); + self::assertCount(0, $tableDiff->getRenamedColumns()); } public function testDetectRenameIndex(): void @@ -825,7 +825,7 @@ public function testDiff(): void $tableDiff = $this->comparator->diffTable($table, $newtable); self::assertInstanceOf(TableDiff::class, $tableDiff); - self::assertEquals(['twitterId', 'displayName'], array_keys($tableDiff->renamedColumns)); + self::assertEquals(['twitterId', 'displayName'], array_keys($tableDiff->getRenamedColumns())); self::assertEquals(['logged_in_at'], array_keys($tableDiff->addedColumns)); self::assertCount(0, $tableDiff->removedColumns); } diff --git a/tests/Schema/TableDiffTest.php b/tests/Schema/TableDiffTest.php index b3349b293b1..6bdbff7f765 100644 --- a/tests/Schema/TableDiffTest.php +++ b/tests/Schema/TableDiffTest.php @@ -3,9 +3,13 @@ namespace Doctrine\DBAL\Tests\Schema; use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Schema\Column; +use Doctrine\DBAL\Schema\ColumnDiff; use Doctrine\DBAL\Schema\Identifier; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -29,6 +33,65 @@ public function testReturnsName(): void self::assertEquals(new Identifier('foo'), $tableDiff->getName($this->platform)); } + public function testRenamedColumnDeprecationLayer(): void + { + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/dbal/pull/6080'); + + /** @psalm-suppress InvalidArgument */ + $diff = new TableDiff( + 'foo', + [], + [ + new ColumnDiff( + 'foo', + new Column('foo', Type::getType(Types::INTEGER)), + ['type'], + new Column('foo', Type::getType(Types::BIGINT)), + ), + new ColumnDiff( + 'ba', + new Column('ba', Type::getType(Types::INTEGER)), + ['type'], + new Column('ba', Type::getType(Types::BIGINT)), + ), + ], + [], + [], + [], + [], + new Table('foo'), + [], + [], + [], + [ + 'foo' => new Column('baz', Type::getType(Types::INTEGER)), + 'bar' => new Column('renamed', Type::getType(Types::INTEGER)), + ], + [], + ); + + self::assertCount(3, $diff->getChangedColumns()); + self::assertCount(2, $diff->getModifiedColumns()); + self::assertEquals('foo', $diff->getChangedColumns()[0]->getOldColumnName()->getName()); + self::assertEquals('baz', $diff->getChangedColumns()[0]->getNewColumn()->getName()); + self::assertTrue($diff->getChangedColumns()[0]->hasTypeChanged()); + self::assertEquals(Type::getType(Types::INTEGER), $diff->getChangedColumns()[0]->getNewColumn()->getType()); + self::assertEquals('bar', $diff->getChangedColumns()[2]->getOldColumnName()->getName()); + self::assertEquals('renamed', $diff->getChangedColumns()[2]->getNewColumn()->getName()); + + self::assertCount(2, $diff->renamedColumns); + + $diff->renamedColumns = ['old_name' => new Column('new_name', Type::getType(Types::INTEGER))]; + self::assertCount(4, $diff->getChangedColumns()); + self::assertCount(3, $diff->renamedColumns); + + // Test that __isset __set and __get have the default php behavior + @$diff->foo = 'baz'; + self::assertTrue(isset($diff->renamedColumns)); + self::assertTrue(isset($diff->foo)); + self::assertEquals('baz', $diff->foo); + } + public function testPrefersNameFromTableObject(): void { $tableMock = $this->getMockBuilder(Table::class) diff --git a/tests/Schema/TableTest.php b/tests/Schema/TableTest.php index 58b39afa9a3..f1594af0989 100644 --- a/tests/Schema/TableTest.php +++ b/tests/Schema/TableTest.php @@ -12,6 +12,7 @@ use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; +use LogicException; use PHPUnit\Framework\TestCase; use function array_shift; @@ -50,6 +51,52 @@ public function testColumns(): void self::assertCount(2, $table->getColumns()); } + public function testRenameColumn(): void + { + $typeStr = Type::getType(Types::STRING); + $typeTxt = Type::getType(Types::TEXT); + $columns = []; + $columns[] = new Column('foo', $typeStr); + $table = new Table('foo', $columns, [], []); + + self::assertFalse($table->hasColumn('bar')); + self::assertTrue($table->hasColumn('foo')); + + $column = $table->renameColumn('foo', 'bar'); + $column->setType($typeTxt); + self::assertTrue($table->hasColumn('bar'), 'Should now have bar column'); + self::assertFalse($table->hasColumn('foo'), 'Should not have foo column anymore'); + self::assertCount(1, $table->getColumns()); + + self::assertEquals(['bar' => 'foo'], $table->getRenamedColumns()); + $table->renameColumn('bar', 'baz'); + + self::assertTrue($table->hasColumn('baz'), 'Should now have baz column'); + self::assertFalse($table->hasColumn('bar'), 'Should not have bar column anymore'); + self::assertEquals(['baz' => 'foo'], $table->getRenamedColumns()); + self::assertCount(1, $table->getColumns()); + } + + public function testRenameColumnException(): void + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Attempt to rename column "foo.baz" to the same name.'); + + $table = new Table('foo'); + $table->renameColumn('baz', '`BaZ`'); + } + + public function testRenameColumnLoop(): void + { + $table = new Table('foo'); + $table->addColumn('baz', Types::INTEGER); + $table->renameColumn('baz', '`foo`'); + self::assertCount(1, $table->getRenamedColumns()); + $table->renameColumn('foo', 'Baz'); + self::assertCount(1, $table->getColumns()); + self::assertCount(0, $table->getRenamedColumns()); + } + public function testColumnsCaseInsensitive(): void { $table = new Table('foo');