Skip to content

Commit fd7d3e1

Browse files
authored
Merge pull request #6900 from morozov/rework-index
Remove support for deprecated Index features
2 parents 5a04320 + 0c3251b commit fd7d3e1

36 files changed

+1516
-1278
lines changed

UPGRADE.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,39 @@ awareness about deprecated code.
88

99
# Upgrade to 5.0
1010

11+
## BC BREAK: Changes in `Index` methods, properties and behavior
12+
13+
The following `Index` methods and properties have been removed:
14+
15+
- `Index::addFlag()`
16+
- `Index::getColumns()`
17+
- `Index::getFlags()`
18+
- `Index::getOption()`
19+
- `Index::getOptions()`
20+
- `Index::getQuotedColumns()`
21+
- `Index::getUnquotedColumns()`
22+
- `Index::hasColumnAtPosition()`
23+
- `Index::hasFlag()`
24+
- `Index::hasOption()`
25+
- `Index::isSimpleIndex()`
26+
- `Index::isUnique()`
27+
- `Index::overrules()`
28+
- `Index::removeFlag()`
29+
- `Index::$_columns`
30+
- `Index::$_flags`
31+
- `Index::$_isUnique`
32+
- `AbstractPlatform::supportsColumnLengthIndexes()`
33+
34+
Additionally,
35+
1. Instantiation of an index without columns is no longer allowed.
36+
2. Passing an empty string as partial index predicate is no longer allowed.
37+
38+
The following conflicting index configurations are no longer allowed:
39+
1. Spatial index with column lengths specified.
40+
2. Clustered fulltext or spatial index.
41+
3. Partial fulltext or spatial index.
42+
4. Clustered partial index.
43+
1144
## BC BREAK: Changes in features related to primary key constraints
1245

1346
1. The `Index` class can no longer represent a primary key constraint. As a result:

src/Platforms/AbstractMySQLPlatform.php

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
1010
use Doctrine\DBAL\Schema\ForeignKeyConstraint\MatchType;
1111
use Doctrine\DBAL\Schema\Index;
12+
use Doctrine\DBAL\Schema\Index\IndexType;
1213
use Doctrine\DBAL\Schema\MySQLSchemaManager;
1314
use Doctrine\DBAL\Schema\Name\OptionallyQualifiedName;
1415
use Doctrine\DBAL\Schema\Name\UnquotedIdentifierFolding;
1516
use Doctrine\DBAL\Schema\PrimaryKeyConstraint;
1617
use Doctrine\DBAL\Schema\TableDiff;
1718
use Doctrine\DBAL\TransactionIsolationLevel;
1819
use Doctrine\DBAL\Types\Types;
19-
use Doctrine\Deprecations\Deprecation;
2020

2121
use function array_map;
2222
use function array_merge;
@@ -281,6 +281,14 @@ protected function _getCreateTableSQL(OptionallyQualifiedName $tableName, array
281281
return $sql;
282282
}
283283

284+
public function getCreateIndexSQL(Index $index, string $table): string
285+
{
286+
$this->ensureIndexIsNotClustered($index);
287+
$this->ensureIndexIsNotPartial($index);
288+
289+
return parent::getCreateIndexSQL($index, $table);
290+
}
291+
284292
/**
285293
* Build SQL for table options
286294
*
@@ -387,22 +395,15 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff): array
387395

388396
foreach ($diff->getDroppedIndexes() as $droppedIndex) {
389397
foreach ($diff->getAddedIndexes() as $addedIndex) {
390-
if ($droppedIndex->getColumns() !== $addedIndex->getColumns()) {
398+
if (! $this->indexedColumnNamesEqual($droppedIndex, $addedIndex)) {
391399
continue;
392400
}
393401

394-
$indexClause = 'INDEX ' . $addedIndex->getObjectName()->toSQL($this);
395-
396-
if ($addedIndex->isUnique()) {
397-
$indexClause = 'UNIQUE ' . $indexClause;
398-
}
399-
400402
$sql[] = sprintf(
401-
'ALTER TABLE %s DROP INDEX %s, ADD %s (%s)',
403+
'ALTER TABLE %s DROP INDEX %s, ADD %s',
402404
$tableNameSQL,
403405
$droppedIndex->getObjectName()->toSQL($this),
404-
$indexClause,
405-
implode(', ', $addedIndex->getQuotedColumns($this)),
406+
$this->getIndexDeclarationSQL($addedIndex),
406407
);
407408

408409
$diff->unsetAddedIndex($addedIndex);
@@ -415,27 +416,46 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff): array
415416
return array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff));
416417
}
417418

419+
private function indexedColumnNamesEqual(Index $index1, Index $index2): bool
420+
{
421+
$columns1 = $index1->getIndexedColumns();
422+
$columns2 = $index2->getIndexedColumns();
423+
424+
if (count($columns1) !== count($columns2)) {
425+
return false;
426+
}
427+
428+
$folding = $this->getUnquotedIdentifierFolding();
429+
foreach ($columns1 as $i => $column1) {
430+
if (! $column1->getColumnName()->equals($columns2[$i]->getColumnName(), $folding)) {
431+
return false;
432+
}
433+
}
434+
435+
return true;
436+
}
437+
418438
/**
419439
* Returns the SQL fragment representing an index.
420440
*/
421441
private function getIndexDeclarationSQL(Index $index): string
422442
{
423-
return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $index->getObjectName()->toSQL($this)
424-
. ' (' . implode(', ', $index->getQuotedColumns($this)) . ')';
425-
}
443+
$chunks = [];
444+
$type = $index->getType();
426445

427-
protected function getCreateIndexSQLFlags(Index $index): string
428-
{
429-
$type = '';
430-
if ($index->isUnique()) {
431-
$type .= 'UNIQUE ';
432-
} elseif ($index->hasFlag('fulltext')) {
433-
$type .= 'FULLTEXT ';
434-
} elseif ($index->hasFlag('spatial')) {
435-
$type .= 'SPATIAL ';
446+
if ($type === IndexType::UNIQUE) {
447+
$chunks[] = 'UNIQUE';
448+
} elseif ($type === IndexType::FULLTEXT) {
449+
$chunks[] = 'FULLTEXT';
450+
} elseif ($type === IndexType::SPATIAL) {
451+
$chunks[] = 'SPATIAL';
436452
}
437453

438-
return $type;
454+
$chunks[] = 'INDEX';
455+
$chunks[] = $index->getObjectName()->toSQL($this);
456+
$chunks[] = $this->buildIndexedColumnListSQL($index->getIndexedColumns());
457+
458+
return implode(' ', $chunks);
439459
}
440460

441461
/**
@@ -664,19 +684,6 @@ public function getDefaultTransactionIsolationLevel(): TransactionIsolationLevel
664684
return TransactionIsolationLevel::REPEATABLE_READ;
665685
}
666686

667-
/** @deprecated */
668-
public function supportsColumnLengthIndexes(): bool
669-
{
670-
Deprecation::triggerIfCalledFromOutside(
671-
'doctrine/dbal',
672-
'https://github.com/doctrine/dbal/pull/6886',
673-
'%s is deprecated.',
674-
__METHOD__,
675-
);
676-
677-
return true;
678-
}
679-
680687
public function createSchemaManager(Connection $connection): MySQLSchemaManager
681688
{
682689
return new MySQLSchemaManager($connection, $this);

src/Platforms/AbstractPlatform.php

Lines changed: 87 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Doctrine\DBAL\LockMode;
1717
use Doctrine\DBAL\Platforms\Exception\NoColumnsSpecifiedForTable;
1818
use Doctrine\DBAL\Platforms\Exception\NotSupported;
19+
use Doctrine\DBAL\Platforms\Exception\UnsupportedIndexDefinition;
1920
use Doctrine\DBAL\Platforms\Exception\UnsupportedPrimaryKeyConstraintDefinition;
2021
use Doctrine\DBAL\Schema\AbstractSchemaManager;
2122
use Doctrine\DBAL\Schema\Column;
@@ -24,6 +25,8 @@
2425
use Doctrine\DBAL\Schema\ForeignKeyConstraint\ReferentialAction;
2526
use Doctrine\DBAL\Schema\Identifier;
2627
use Doctrine\DBAL\Schema\Index;
28+
use Doctrine\DBAL\Schema\Index\IndexedColumn;
29+
use Doctrine\DBAL\Schema\Index\IndexType;
2730
use Doctrine\DBAL\Schema\Name\OptionallyQualifiedName;
2831
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
2932
use Doctrine\DBAL\Schema\Name\UnquotedIdentifierFolding;
@@ -44,7 +47,6 @@
4447
use Doctrine\DBAL\Types\Exception\TypeNotFound;
4548
use Doctrine\DBAL\Types\Exception\TypesException;
4649
use Doctrine\DBAL\Types\Type;
47-
use Doctrine\Deprecations\Deprecation;
4850

4951
use function addcslashes;
5052
use function array_map;
@@ -1093,41 +1095,34 @@ public function getDropSequenceSQL(string $name): string
10931095
*/
10941096
public function getCreateIndexSQL(Index $index, string $table): string
10951097
{
1096-
$name = $index->getObjectName()->toSQL($this);
1097-
$columns = $index->getColumns();
1098+
$chunks = ['CREATE'];
1099+
$type = $index->getType();
10981100

1099-
if (count($columns) === 0) {
1100-
throw new InvalidArgumentException(sprintf(
1101-
'Incomplete or invalid index definition %s on table %s',
1102-
$name,
1103-
$table,
1104-
));
1101+
if ($type === IndexType::UNIQUE) {
1102+
$chunks[] = 'UNIQUE';
1103+
} elseif ($type === IndexType::FULLTEXT) {
1104+
$chunks[] = 'FULLTEXT';
1105+
} elseif ($type === IndexType::SPATIAL) {
1106+
$chunks[] = 'SPATIAL';
11051107
}
11061108

1107-
$query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1108-
$query .= ' (' . implode(', ', $index->getQuotedColumns($this)) . ')' . $this->getPartialIndexSQL($index);
1109+
if ($index->isClustered()) {
1110+
$chunks[] = 'CLUSTERED';
1111+
}
11091112

1110-
return $query;
1111-
}
1113+
$chunks[] = 'INDEX';
1114+
$chunks[] = $index->getObjectName()->toSQL($this);
1115+
$chunks[] = 'ON';
1116+
$chunks[] = $table;
1117+
$chunks[] = $this->buildIndexedColumnListSQL($index->getIndexedColumns());
11121118

1113-
/**
1114-
* Adds condition for partial index.
1115-
*/
1116-
protected function getPartialIndexSQL(Index $index): string
1117-
{
1118-
if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1119-
return ' WHERE ' . $index->getOption('where');
1119+
$predicate = $index->getPredicate();
1120+
if ($predicate !== null) {
1121+
$chunks[] = 'WHERE';
1122+
$chunks[] = $predicate;
11201123
}
11211124

1122-
return '';
1123-
}
1124-
1125-
/**
1126-
* Adds additional flags for index generation.
1127-
*/
1128-
protected function getCreateIndexSQLFlags(Index $index): string
1129-
{
1130-
return $index->isUnique() ? 'UNIQUE ' : '';
1125+
return implode(' ', $chunks);
11311126
}
11321127

11331128
/**
@@ -1494,6 +1489,51 @@ final protected function ensurePrimaryKeyConstraintIsClustered(PrimaryKeyConstra
14941489
throw UnsupportedPrimaryKeyConstraintDefinition::fromNonClusteredConstraint(static::class);
14951490
}
14961491

1492+
final protected function ensureIndexHasNoColumnLengths(Index $index): void
1493+
{
1494+
foreach ($index->getIndexedColumns() as $column) {
1495+
if ($column->getLength() !== null) {
1496+
throw UnsupportedIndexDefinition::fromIndexWithColumnLengths(static::class);
1497+
}
1498+
}
1499+
}
1500+
1501+
final protected function ensureIndexIsNotFulltext(Index $index): void
1502+
{
1503+
if ($index->getType() !== IndexType::FULLTEXT) {
1504+
return;
1505+
}
1506+
1507+
throw UnsupportedIndexDefinition::fromFulltextIndex(static::class);
1508+
}
1509+
1510+
final protected function ensureIndexIsNotSpatial(Index $index): void
1511+
{
1512+
if ($index->getType() !== IndexType::SPATIAL) {
1513+
return;
1514+
}
1515+
1516+
throw UnsupportedIndexDefinition::fromSpatialIndex(static::class);
1517+
}
1518+
1519+
final protected function ensureIndexIsNotClustered(Index $index): void
1520+
{
1521+
if (! $index->isClustered()) {
1522+
return;
1523+
}
1524+
1525+
throw UnsupportedIndexDefinition::fromClusteredIndex(static::class);
1526+
}
1527+
1528+
final protected function ensureIndexIsNotPartial(Index $index): void
1529+
{
1530+
if ($index->getPredicate() === null) {
1531+
return;
1532+
}
1533+
1534+
throw UnsupportedIndexDefinition::fromPartialIndex(static::class);
1535+
}
1536+
14971537
/**
14981538
* Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
14991539
* of a column declaration to be used in statements like CREATE TABLE.
@@ -1602,6 +1642,24 @@ private function buildUnqualifiedNameListSQL(array $names): string
16021642
)));
16031643
}
16041644

1645+
/** @param non-empty-list<IndexedColumn> $indexedColumns */
1646+
protected function buildIndexedColumnListSQL(array $indexedColumns): string
1647+
{
1648+
return sprintf('(%s)', implode(', ', array_map(
1649+
function (IndexedColumn $indexedColumn): string {
1650+
$sql = $indexedColumn->getColumnName()->toSQL($this);
1651+
1652+
$length = $indexedColumn->getLength();
1653+
if ($length !== null) {
1654+
$sql .= sprintf('(%s)', $length);
1655+
}
1656+
1657+
return $sql;
1658+
},
1659+
$indexedColumns,
1660+
)));
1661+
}
1662+
16051663
/**
16061664
* Some platforms need the boolean values to be converted.
16071665
*
@@ -1841,31 +1899,6 @@ public function supportsIdentityColumns(): bool
18411899
return false;
18421900
}
18431901

1844-
/**
1845-
* Whether the platform supports partial indexes.
1846-
*/
1847-
protected function supportsPartialIndexes(): bool
1848-
{
1849-
return false;
1850-
}
1851-
1852-
/**
1853-
* Whether the platform supports indexes with column length definitions.
1854-
*
1855-
* @deprecated
1856-
*/
1857-
public function supportsColumnLengthIndexes(): bool
1858-
{
1859-
Deprecation::triggerIfCalledFromOutside(
1860-
'doctrine/dbal',
1861-
'https://github.com/doctrine/dbal/pull/6886',
1862-
'%s is deprecated.',
1863-
__METHOD__,
1864-
);
1865-
1866-
return false;
1867-
}
1868-
18691902
/**
18701903
* Whether the platform supports savepoints.
18711904
*/

src/Platforms/DB2Platform.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,17 @@ protected function _getCreateTableSQL(OptionallyQualifiedName $tableName, array
255255
return $sql;
256256
}
257257

258+
public function getCreateIndexSQL(Index $index, string $table): string
259+
{
260+
$this->ensureIndexHasNoColumnLengths($index);
261+
$this->ensureIndexIsNotFulltext($index);
262+
$this->ensureIndexIsNotSpatial($index);
263+
$this->ensureIndexIsNotClustered($index);
264+
$this->ensureIndexIsNotPartial($index);
265+
266+
return parent::getCreateIndexSQL($index, $table);
267+
}
268+
258269
/**
259270
* {@inheritDoc}
260271
*/

0 commit comments

Comments
 (0)