From 0a1d8b83a9ba7355fcf756ab57e80f8181c2cd2e Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 19 Jun 2011 10:56:19 +0200 Subject: [PATCH] DDC-887 - Fix problem with MySQL renaming of foreign keys columns. The FK has to be dropped, then column renamed, then readded --- .../DBAL/Platforms/AbstractPlatform.php | 51 +++++++++++++------ lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 6 ++- run-all.sh | 21 ++++++++ .../SchemaManagerFunctionalTestCase.php | 39 ++++++++++++++ 4 files changed, 101 insertions(+), 16 deletions(-) create mode 100755 run-all.sh diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index b4fbf197ba4..537aad7dca0 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -1174,13 +1174,31 @@ public function getAlterTableSQL(TableDiff $diff) throw DBALException::notSupported(__METHOD__); } - /** - * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions. - * - * @param TableDiff $diff - * @return array - */ - protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $tableName = $diff->name; + + $sql = array(); + if ($this->supportsForeignKeyConstraints()) { + foreach ($diff->removedForeignKeys AS $foreignKey) { + $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); + } + foreach ($diff->changedForeignKeys AS $foreignKey) { + $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); + } + } + + foreach ($diff->removedIndexes AS $index) { + $sql[] = $this->getDropIndexSQL($index, $tableName); + } + foreach ($diff->changedIndexes AS $index) { + $sql[] = $this->getDropIndexSQL($index, $tableName); + } + + return $sql; + } + + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) { if ($diff->newName !== false) { $tableName = $diff->newName; @@ -1190,14 +1208,10 @@ protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) $sql = array(); if ($this->supportsForeignKeyConstraints()) { - foreach ($diff->removedForeignKeys AS $foreignKey) { - $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); - } foreach ($diff->addedForeignKeys AS $foreignKey) { $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); } foreach ($diff->changedForeignKeys AS $foreignKey) { - $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); } } @@ -1205,16 +1219,23 @@ protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) foreach ($diff->addedIndexes AS $index) { $sql[] = $this->getCreateIndexSQL($index, $tableName); } - foreach ($diff->removedIndexes AS $index) { - $sql[] = $this->getDropIndexSQL($index, $tableName); - } foreach ($diff->changedIndexes AS $index) { - $sql[] = $this->getDropIndexSQL($index, $tableName); $sql[] = $this->getCreateIndexSQL($index, $tableName); } return $sql; } + + /** + * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions. + * + * @param TableDiff $diff + * @return array + */ + protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) + { + return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff)); + } /** * Get declaration of a number of fields in bulk diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 7776f6d3f20..4dca7cef9ad 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -487,7 +487,11 @@ public function getAlterTableSQL(TableDiff $diff) if (count($queryParts) > 0) { $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts); } - $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff)); + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); return $sql; } diff --git a/run-all.sh b/run-all.sh new file mode 100755 index 00000000000..80712eebc7e --- /dev/null +++ b/run-all.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# This script is a small convenience wrapper for running the doctrine testsuite against a large bunch of databases. +# Just create the phpunit.xmls as described in the array below and configure the specific files section +# to connect to that database. Just omit a file if you dont have that database and the tests will be skipped. + +configs[1]="mysql.phpunit.xml" +configs[2]='postgres.phpunit.xml' +configs[3]='sqlite.phpunit.xml' +configs[4]='oracle.phpunit.xml' +configs[5]='db2.phpunit.xml' +configs[6]='pdo-ibm.phpunit.xml' +configs[7]='sqlsrv.phpunit.xml' + +for i in "${configs[@]}"; do + if [ -f "$i" ]; + then + echo "RUNNING TESTS WITH CONFIG $i" + phpunit -c "$i" "$@" + fi; +done diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php index 5e25c0aaa0d..2e744b91dca 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -4,6 +4,7 @@ use Doctrine\DBAL\Types\Type, Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\Platforms\AbstractPlatform; require_once __DIR__ . '/../../../TestInit.php'; @@ -398,6 +399,44 @@ public function testAutoincrementDetection() $this->assertTrue($inferredTable->hasColumn('id')); $this->assertTrue($inferredTable->getColumn('id')->getAutoincrement()); } + + /** + * @group DDC-887 + */ + public function testUpdateSchemaWithForeignKeyRenaming() + { + if (!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); + } + + $table = new \Doctrine\DBAL\Schema\Table('test_fk_base'); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $tableFK = new \Doctrine\DBAL\Schema\Table('test_fk_rename'); + $tableFK->setSchemaConfig($this->_sm->createSchemaConfig()); + $tableFK->addColumn('id', 'integer'); + $tableFK->addColumn('fk_id', 'integer'); + $tableFK->setPrimaryKey(array('id')); + $tableFK->addIndex(array('fk_id'), 'fk_idx'); + $tableFK->addForeignKeyConstraint('test_fk_base', array('fk_id'), array('id')); + + $this->_sm->createTable($table); + $this->_sm->createTable($tableFK); + + $tableFKNew = new \Doctrine\DBAL\Schema\Table('test_fk_rename'); + $tableFKNew->setSchemaConfig($this->_sm->createSchemaConfig()); + $tableFKNew->addColumn('id', 'integer'); + $tableFKNew->addColumn('rename_fk_id', 'integer'); + $tableFKNew->setPrimaryKey(array('id')); + $tableFKNew->addIndex(array('rename_fk_id'), 'fk_idx'); + $tableFKNew->addForeignKeyConstraint('test_fk_base', array('rename_fk_id'), array('id')); + + $c = new \Doctrine\DBAL\Schema\Comparator(); + $tableDiff = $c->diffTable($tableFK, $tableFKNew); + + $this->_sm->alterTable($tableDiff); + } /** * @group DBAL-42