Commit a996bea8 authored by Steve Müller's avatar Steve Müller

add support for renaming indexes

parent 84ac8d98
......@@ -21,6 +21,7 @@ namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Schema\Identifier;
use Doctrine\DBAL\Types;
use Doctrine\DBAL\Schema\Constraint;
use Doctrine\DBAL\Schema\Sequence;
......@@ -1823,10 +1824,12 @@ abstract class AbstractPlatform
: $diff->getName()->getQuotedName($this);
$sql = array();
if ($this->supportsForeignKeyConstraints()) {
foreach ($diff->addedForeignKeys as $foreignKey) {
$sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
}
foreach ($diff->changedForeignKeys as $foreignKey) {
$sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
}
......@@ -1835,13 +1838,39 @@ abstract class AbstractPlatform
foreach ($diff->addedIndexes as $index) {
$sql[] = $this->getCreateIndexSQL($index, $tableName);
}
foreach ($diff->changedIndexes as $index) {
$sql[] = $this->getCreateIndexSQL($index, $tableName);
}
foreach ($diff->renamedIndexes as $oldIndexName => $index) {
$oldIndexName = new Identifier($oldIndexName);
$sql = array_merge(
$sql,
$this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
);
}
return $sql;
}
/**
* Returns the SQL for renaming an index on a table.
*
* @param string $oldIndexName The name of the index to rename from.
* @param \Doctrine\DBAL\Schema\Index $index The definition of the index to rename to.
* @param string $tableName The table to rename the given index on.
*
* @return array The sequence of SQL statements for renaming the given index.
*/
protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
{
return array(
$this->getDropIndexSQL($oldIndexName, $tableName),
$this->getCreateIndexSQL($index, $tableName)
);
}
/**
* Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
*
......
......@@ -19,7 +19,6 @@
namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\TableDiff;
......@@ -575,6 +574,14 @@ class DB2Platform extends AbstractPlatform
return $sql;
}
/**
* {@inheritdoc}
*/
protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
{
return array('RENAME INDEX ' . $oldIndexName . ' TO ' . $index->getQuotedName($this));
}
/**
* {@inheritDoc}
*/
......
......@@ -762,6 +762,14 @@ LEFT JOIN user_cons_columns r_cols
return $name . ' ' . $columnDef;
}
/**
* {@inheritdoc}
*/
protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
{
return array('ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this));
}
/**
* {@inheritDoc}
*/
......
......@@ -21,6 +21,7 @@ namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ColumnDiff;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\BinaryType;
use Doctrine\DBAL\Types\BlobType;
......@@ -582,6 +583,14 @@ class PostgreSqlPlatform extends AbstractPlatform
return count(array_diff($columnDiff->changedProperties, array('length', 'fixed'))) === 0;
}
/**
* {@inheritdoc}
*/
protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
{
return array('ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this));
}
/**
* {@inheritdoc}
*/
......
......@@ -1417,6 +1417,16 @@ class SQLAnywherePlatform extends AbstractPlatform
return $type;
}
/**
* {@inheritdoc}
*/
protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
{
return array(
'ALTER INDEX ' . $oldIndexName . ' ON ' . $tableName . ' RENAME TO ' . $index->getQuotedName($this)
);
}
/**
* {@inheritdoc}
*/
......
......@@ -22,7 +22,6 @@ namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
......@@ -659,6 +658,21 @@ class SQLServerPlatform extends AbstractPlatform
);
}
/**
* {@inheritdoc}
*/
protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
{
return array(
sprintf(
"EXEC sp_RENAME N'%s.%s', N'%s', N'INDEX'",
$tableName,
$oldIndexName,
$index->getQuotedName($this)
)
);
}
/**
* Returns the SQL statement for adding an extended property to a database object.
*
......
......@@ -849,6 +849,7 @@ class SqlitePlatform extends AbstractPlatform
if ( ! empty($diff->renamedColumns) || ! empty($diff->addedForeignKeys) || ! empty($diff->addedIndexes)
|| ! empty($diff->changedColumns) || ! empty($diff->changedForeignKeys) || ! empty($diff->changedIndexes)
|| ! empty($diff->removedColumns) || ! empty($diff->removedForeignKeys) || ! empty($diff->removedIndexes)
|| ! empty($diff->renamedIndexes)
) {
return false;
}
......@@ -969,7 +970,7 @@ class SqlitePlatform extends AbstractPlatform
}
}
foreach (array_merge($diff->changedIndexes, $diff->addedIndexes) as $index) {
foreach (array_merge($diff->changedIndexes, $diff->addedIndexes, $diff->renamedIndexes) as $index) {
$indexName = strtolower($index->getName());
if (strlen($indexName)) {
$indexes[$indexName] = $index;
......
......@@ -227,6 +227,11 @@ class Comparator
foreach ($table2Indexes as $index2Name => $index2Definition) {
foreach ($table1Indexes as $index1Name => $index1Definition) {
if ($this->diffIndex($index1Definition, $index2Definition) === false) {
if ( ! $index1Definition->isPrimary() && $index1Name != $index2Name) {
$tableDifferences->renamedIndexes[$index1Name] = $index2Definition;
$changes++;
}
unset($table1Indexes[$index1Name]);
unset($table2Indexes[$index2Name]);
} else {
......
......@@ -206,6 +206,52 @@ class Table extends AbstractAsset
return $this->_createIndex($columnNames, $indexName, true, false);
}
/**
* Renames an index.
*
* @param string $oldIndexName The name of the index to rename from.
* @param string|null $newIndexName The name of the index to rename to.
* If null is given, the index name will be auto-generated.
*
* @return \Doctrine\DBAL\Schema\Table This table instance.
*
* @throws SchemaException if no index exists for the given current name
* or if an index with the given new name already exists on this table.
*/
public function renameIndex($oldIndexName, $newIndexName = null)
{
$oldIndexName = strtolower($oldIndexName);
$normalizedNewIndexName = strtolower($newIndexName);
if ($oldIndexName === $normalizedNewIndexName) {
return $this;
}
if ( ! $this->hasIndex($oldIndexName)) {
throw SchemaException::indexDoesNotExist($oldIndexName, $this->_name);
}
if ($this->hasIndex($normalizedNewIndexName)) {
throw SchemaException::indexAlreadyExists($normalizedNewIndexName, $this->_name);
}
$oldIndex = $this->_indexes[$oldIndexName];
if ($oldIndex->isPrimary()) {
$this->dropPrimaryKey();
return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName);
}
unset($this->_indexes[$oldIndexName]);
if ($oldIndex->isUnique()) {
return $this->addUniqueIndex($oldIndex->getColumns(), $newIndexName);
}
return $this->addIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getFlags());
}
/**
* Checks if an index begins in the order of the given columns.
*
......
......@@ -87,6 +87,13 @@ class TableDiff
*/
public $removedIndexes = array();
/**
* Indexes that are only renamed but are identical otherwise.
*
* @var \Doctrine\DBAL\Schema\Index[]
*/
public $renamedIndexes = array();
/**
* All added foreign key definitions
*
......
......@@ -425,7 +425,21 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
$tableDiff->fromTable = $table;
$tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test'));
$tableDiff->renamedIndexes['foo_idx'] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test'));
$this->_sm->alterTable($tableDiff);
$table = $this->_sm->listTableDetails('alter_table');
$this->assertEquals(2, count($table->getIndexes()));
$this->assertTrue($table->hasIndex('bar_idx'));
$this->assertFalse($table->hasIndex('foo_idx'));
$this->assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('bar_idx')->getColumns()));
$this->assertFalse($table->getIndex('bar_idx')->isPrimary());
$this->assertFalse($table->getIndex('bar_idx')->isUnique());
$tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
$tableDiff->fromTable = $table;
$tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test'));
$fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('foreign_key_test'), 'alter_table_foreign', array('id'));
$tableDiff->addedForeignKeys[] = $fk;
......@@ -433,7 +447,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$table = $this->_sm->listTableDetails('alter_table');
// dont check for index size here, some platforms automatically add indexes for foreign keys.
$this->assertFalse($table->hasIndex('foo_idx'));
$this->assertFalse($table->hasIndex('bar_idx'));
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$fks = $table->getForeignKeys();
......
......@@ -6,6 +6,7 @@ use Doctrine\Common\EventManager;
use Doctrine\DBAL\Events;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\Type;
......@@ -601,4 +602,67 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase
$this->_platform->getJsonTypeDeclarationSQL($column)
);
}
/**
* @group DBAL-234
*/
public function testAlterTableRenameIndex()
{
$tableDiff = new TableDiff('mytable');
$tableDiff->fromTable = new Table('mytable');
$tableDiff->fromTable->addColumn('id', 'integer');
$tableDiff->fromTable->setPrimaryKey(array('id'));
$tableDiff->renamedIndexes = array(
'idx_foo' => new Index('idx_bar', array('id'))
);
$this->assertSame(
$this->getAlterTableRenameIndexSQL(),
$this->_platform->getAlterTableSQL($tableDiff)
);
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
'DROP INDEX idx_foo',
'CREATE INDEX idx_bar ON mytable (id)',
);
}
/**
* @group DBAL-234
*/
public function testQuotesAlterTableRenameIndex()
{
$tableDiff = new TableDiff('table');
$tableDiff->fromTable = new Table('table');
$tableDiff->fromTable->addColumn('id', 'integer');
$tableDiff->fromTable->setPrimaryKey(array('id'));
$tableDiff->renamedIndexes = array(
'create' => new Index('select', array('id')),
'`foo`' => new Index('`bar`', array('id')),
);
$this->assertSame(
$this->getQuotedAlterTableRenameIndexSQL(),
$this->_platform->getAlterTableSQL($tableDiff)
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
'DROP INDEX "create"',
'CREATE INDEX "select" ON "table" (id)',
'DROP INDEX "foo"',
'CREATE INDEX "bar" ON "table" (id)',
);
}
}
......@@ -384,4 +384,25 @@ class DB2PlatformTest extends AbstractPlatformTestCase
$this->assertSame('BINARY(32704)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 32704)));
$this->assertSame('BLOB(1M)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 32705)));
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
'RENAME INDEX idx_foo TO idx_bar',
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
'RENAME INDEX "create" TO "select"',
'RENAME INDEX "foo" TO "bar"',
);
}
}
......@@ -484,4 +484,28 @@ class MySqlPlatformTest extends AbstractPlatformTestCase
$this->_platform->getAlterTableSQL($tableDiff)
);
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
'DROP INDEX idx_foo ON mytable',
'CREATE INDEX idx_bar ON mytable (id)',
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
'DROP INDEX `create` ON `table`',
'CREATE INDEX `select` ON `table` (id)',
'DROP INDEX `foo` ON `table`',
'CREATE INDEX `bar` ON `table` (id)',
);
}
}
......@@ -417,4 +417,25 @@ class OraclePlatformTest extends AbstractPlatformTestCase
array(3, 'CACHE 3')
);
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
'ALTER INDEX idx_foo RENAME TO idx_bar',
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
'ALTER INDEX "create" RENAME TO "select"',
'ALTER INDEX "foo" RENAME TO "bar"',
);
}
}
......@@ -506,4 +506,25 @@ class PostgreSqlPlatformTest extends AbstractPlatformTestCase
// BLOB -> BLOB
$this->assertEmpty($this->_platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
'ALTER INDEX idx_foo RENAME TO idx_bar',
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
'ALTER INDEX "create" RENAME TO "select"',
'ALTER INDEX "foo" RENAME TO "bar"',
);
}
}
......@@ -784,4 +784,25 @@ class SQLAnywherePlatformTest extends AbstractPlatformTestCase
$this->assertSame('BINARY(32767)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 32767)));
$this->assertSame('LONG BINARY', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 32768)));
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
'ALTER INDEX idx_foo ON mytable RENAME TO idx_bar',
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
'ALTER INDEX "create" ON "table" RENAME TO "select"',
'ALTER INDEX "foo" ON "table" RENAME TO "bar"',
);
}
}
......@@ -694,4 +694,25 @@ class SQLServerPlatformTest extends AbstractPlatformTestCase
$this->assertSame('BINARY(8000)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 8000)));
$this->assertSame('VARBINARY(MAX)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 8001)));
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
"EXEC sp_RENAME N'mytable.idx_foo', N'idx_bar', N'INDEX'",
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
"EXEC sp_RENAME N'[table].[create]', N'[select]', N'INDEX'",
"EXEC sp_RENAME N'[table].[foo]', N'[bar]', N'INDEX'",
);
}
}
......@@ -323,4 +323,35 @@ class SqlitePlatformTest extends AbstractPlatformTestCase
$this->assertSame('BLOB', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 0)));
$this->assertSame('BLOB', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 9999999)));
}
/**
* @group DBAL-234
*/
protected function getAlterTableRenameIndexSQL()
{
return array(
'CREATE TEMPORARY TABLE __temp__mytable AS SELECT id FROM mytable',
'DROP TABLE mytable',
'CREATE TABLE mytable (id INTEGER NOT NULL, PRIMARY KEY(id))',
'INSERT INTO mytable (id) SELECT id FROM __temp__mytable',
'DROP TABLE __temp__mytable',
'CREATE INDEX idx_bar ON mytable (id)',
);
}
/**
* @group DBAL-234
*/
protected function getQuotedAlterTableRenameIndexSQL()
{
return array(
'CREATE TEMPORARY TABLE __temp__table AS SELECT id FROM "table"',
'DROP TABLE "table"',
'CREATE TABLE "table" (id INTEGER NOT NULL, PRIMARY KEY(id))',
'INSERT INTO "table" (id) SELECT id FROM __temp__table',
'DROP TABLE __temp__table',
'CREATE INDEX "select" ON table (id)',
'CREATE INDEX "bar" ON table (id)',
);
}
}
......@@ -617,9 +617,14 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$tableB->addIndex(array("id"), "bar_foo_idx");
$c = new Comparator();
$tableDiff = $c->diffTable($tableA, $tableB);
$tableDiff = new TableDiff('foo');
$tableDiff->fromTable = $tableA;
$tableDiff->renamedIndexes['foo_bar_idx'] = new Index('bar_foo_idx', array('id'));
$this->assertFalse($tableDiff);
$this->assertEquals(
$tableDiff,
$c->diffTable($tableA, $tableB)
);
}
public function testCompareForeignKeyBasedOnPropertiesNotName()
......
......@@ -525,4 +525,104 @@ class TableTest extends \Doctrine\Tests\DbalTestCase
$table->dropPrimaryKey();
$this->assertFalse($table->hasPrimaryKey());
}
/**
* @group DBAL-234
*/
public function testRenameIndex()
{
$table = new Table("test");
$table->addColumn('id', 'integer');
$table->addColumn('foo', 'integer');
$table->addColumn('bar', 'integer');
$table->addColumn('baz', 'integer');
$table->setPrimaryKey(array('id'), 'pk');
$table->addIndex(array('foo'), 'idx', array('flag'));
$table->addUniqueIndex(array('bar', 'baz'), 'uniq');
// Rename to custom name.
$this->assertSame($table, $table->renameIndex('pk', 'pk_new'));
$this->assertSame($table, $table->renameIndex('idx', 'idx_new'));
$this->assertSame($table, $table->renameIndex('uniq', 'uniq_new'));
$this->assertTrue($table->hasPrimaryKey());
$this->assertTrue($table->hasIndex('pk_new'));
$this->assertTrue($table->hasIndex('idx_new'));
$this->assertTrue($table->hasIndex('uniq_new'));
$this->assertFalse($table->hasIndex('pk'));
$this->assertFalse($table->hasIndex('idx'));
$this->assertFalse($table->hasIndex('uniq'));
$this->assertEquals(new Index('pk_new', array('id'), true, true), $table->getPrimaryKey());
$this->assertEquals(new Index('pk_new', array('id'), true, true), $table->getIndex('pk_new'));
$this->assertEquals(
new Index('idx_new', array('foo'), false, false, array('flag')),
$table->getIndex('idx_new')
);
$this->assertEquals(new Index('uniq_new', array('bar', 'baz'), true), $table->getIndex('uniq_new'));
// Rename to auto-generated name.
$this->assertSame($table, $table->renameIndex('pk_new', null));
$this->assertSame($table, $table->renameIndex('idx_new', null));
$this->assertSame($table, $table->renameIndex('uniq_new', null));
$this->assertTrue($table->hasPrimaryKey());
$this->assertTrue($table->hasIndex('primary'));
$this->assertTrue($table->hasIndex('IDX_D87F7E0C8C736521'));
$this->assertTrue($table->hasIndex('UNIQ_D87F7E0C76FF8CAA78240498'));
$this->assertFalse($table->hasIndex('pk_new'));
$this->assertFalse($table->hasIndex('idx_new'));
$this->assertFalse($table->hasIndex('uniq_new'));
$this->assertEquals(new Index('primary', array('id'), true, true), $table->getPrimaryKey());
$this->assertEquals(new Index('primary', array('id'), true, true), $table->getIndex('primary'));
$this->assertEquals(
new Index('IDX_D87F7E0C8C736521', array('foo'), false, false, array('flag')),
$table->getIndex('IDX_D87F7E0C8C736521')
);
$this->assertEquals(
new Index('UNIQ_D87F7E0C76FF8CAA78240498', array('bar', 'baz'), true),
$table->getIndex('UNIQ_D87F7E0C76FF8CAA78240498')
);
// Rename to same name (changed case).
$this->assertSame($table, $table->renameIndex('primary', 'PRIMARY'));
$this->assertSame($table, $table->renameIndex('IDX_D87F7E0C8C736521', 'idx_D87F7E0C8C736521'));
$this->assertSame($table, $table->renameIndex('UNIQ_D87F7E0C76FF8CAA78240498', 'uniq_D87F7E0C76FF8CAA78240498'));
$this->assertTrue($table->hasPrimaryKey());
$this->assertTrue($table->hasIndex('primary'));
$this->assertTrue($table->hasIndex('IDX_D87F7E0C8C736521'));
$this->assertTrue($table->hasIndex('UNIQ_D87F7E0C76FF8CAA78240498'));
}
/**
* @group DBAL-234
* @expectedException \Doctrine\DBAL\Schema\SchemaException
*/
public function testThrowsExceptionOnRenamingNonExistingIndex()
{
$table = new Table("test");
$table->addColumn('id', 'integer');
$table->addIndex(array('id'), 'idx');
$table->renameIndex('foo', 'bar');
}
/**
* @group DBAL-234
* @expectedException \Doctrine\DBAL\Schema\SchemaException
*/
public function testThrowsExceptionOnRenamingToAlreadyExistingIndex()
{
$table = new Table("test");
$table->addColumn('id', 'integer');
$table->addColumn('foo', 'integer');
$table->addIndex(array('id'), 'idx_id');
$table->addIndex(array('foo'), 'idx_foo');
$table->renameIndex('idx_id', 'idx_foo');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment