From e37fc54d91a9bad1a7579520f2ee63c90e9099e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Thu, 8 Nov 2018 19:17:09 +0100 Subject: [PATCH] Add mysql specific indexes with lengths --- .../DBAL/Platforms/AbstractPlatform.php | 44 +++++++++++++------ lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 10 ++++- .../DBAL/Platforms/SQLServerPlatform.php | 2 +- .../DBAL/Schema/AbstractSchemaManager.php | 17 +++++-- lib/Doctrine/DBAL/Schema/Index.php | 14 +++++- .../DBAL/Schema/MySqlSchemaManager.php | 2 + .../SchemaManagerFunctionalTestCase.php | 20 +++++++++ 7 files changed, 88 insertions(+), 21 deletions(-) diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index aeac616d514..80a002b6072 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -1408,7 +1408,9 @@ public function getDropTableSQL($table) if ($table instanceof Table) { $table = $table->getQuotedName($this); - } elseif (! is_string($table)) { + } + + if (! is_string($table)) { throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); } @@ -1784,7 +1786,7 @@ public function getCreateIndexSQL(Index $index, $table) $table = $table->getQuotedName($this); } $name = $index->getQuotedName($this); - $columns = $index->getQuotedColumns($this); + $columns = $index->getColumns(); if (count($columns) === 0) { throw new InvalidArgumentException("Incomplete definition. 'columns' required."); @@ -1795,7 +1797,7 @@ public function getCreateIndexSQL(Index $index, $table) } $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table; - $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')' . $this->getPartialIndexSQL($index); + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); return $query; } @@ -1833,7 +1835,7 @@ protected function getCreateIndexSQLFlags(Index $index) */ public function getCreatePrimaryKeySQL(Index $index, $table) { - return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')'; + return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')'; } /** @@ -2337,7 +2339,7 @@ public function getCheckDeclarationSQL(array $definition) */ public function getUniqueConstraintDeclarationSQL($name, Index $index) { - $columns = $index->getQuotedColumns($this); + $columns = $index->getColumns(); $name = new Identifier($name); if (count($columns) === 0) { @@ -2345,7 +2347,7 @@ public function getUniqueConstraintDeclarationSQL($name, Index $index) } return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE (' - . $this->getIndexFieldDeclarationListSQL($columns) + . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); } @@ -2362,7 +2364,7 @@ public function getUniqueConstraintDeclarationSQL($name, Index $index) */ public function getIndexDeclarationSQL($name, Index $index) { - $columns = $index->getQuotedColumns($this); + $columns = $index->getColumns(); $name = new Identifier($name); if (count($columns) === 0) { @@ -2370,7 +2372,7 @@ public function getIndexDeclarationSQL($name, Index $index) } return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' (' - . $this->getIndexFieldDeclarationListSQL($columns) + . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); } @@ -2392,17 +2394,23 @@ public function getCustomTypeDeclarationSQL(array $columnDef) * Obtains DBMS specific SQL code portion needed to set an index * declaration to be used in statements like CREATE TABLE. * - * @param mixed[][] $fields - * - * @return string + * @param mixed[]|Index $columnsOrIndex array declaration is deprecated, prefer passing Index to this method */ - public function getIndexFieldDeclarationListSQL(array $fields) + public function getIndexFieldDeclarationListSQL($columnsOrIndex) : string { + if ($columnsOrIndex instanceof Index) { + return implode(', ', $columnsOrIndex->getQuotedColumns($this)); + } + + if (! is_array($columnsOrIndex)) { + throw new InvalidArgumentException('Fields argument should be an Index or array.'); + } + $ret = []; - foreach ($fields as $field => $definition) { + foreach ($columnsOrIndex as $column => $definition) { if (is_array($definition)) { - $ret[] = $field; + $ret[] = $column; } else { $ret[] = $definition; } @@ -3073,6 +3081,14 @@ public function supportsPartialIndexes() return false; } + /** + * Whether the platform supports indexes with column length definitions. + */ + public function supportsColumnLengthIndexes() : bool + { + return false; + } + /** * Whether the platform supports altering tables. * diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 744aa08a4bd..e17d3736041 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -645,7 +645,7 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) $query = 'ALTER TABLE ' . $table . ' DROP INDEX ' . $remIndex->getName() . ', '; $query .= 'ADD ' . $indexClause; - $query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex->getQuotedColumns($this)) . ')'; + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex) . ')'; $sql[] = $query; @@ -1132,4 +1132,12 @@ public function getDefaultTransactionIsolationLevel() { return TransactionIsolationLevel::REPEATABLE_READ; } + + /** + * {@inheritdoc} + */ + public function supportsColumnLengthIndexes() : bool + { + return true; + } } diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index 353cfe0b2a9..88578690d77 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -320,7 +320,7 @@ public function getCreatePrimaryKeySQL(Index $index, $table) $flags = ' NONCLUSTERED'; } - return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY' . $flags . ' (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')'; + return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY' . $flags . ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')'; } /** diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 06ee2c2b2aa..9b917427fd8 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -843,17 +843,26 @@ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = nu $keyName = strtolower($keyName); if (! isset($result[$keyName])) { + $options = [ + 'lengths' => [], + ]; + + if (isset($tableIndex['where'])) { + $options['where'] = $tableIndex['where']; + } + $result[$keyName] = [ 'name' => $indexName, - 'columns' => [$tableIndex['column_name']], + 'columns' => [], 'unique' => $tableIndex['non_unique'] ? false : true, 'primary' => $tableIndex['primary'], 'flags' => $tableIndex['flags'] ?? [], - 'options' => isset($tableIndex['where']) ? ['where' => $tableIndex['where']] : [], + 'options' => $options, ]; - } else { - $result[$keyName]['columns'][] = $tableIndex['column_name']; } + + $result[$keyName]['columns'][] = $tableIndex['column_name']; + $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null; } $eventManager = $this->_platform->getEventManager(); diff --git a/lib/Doctrine/DBAL/Schema/Index.php b/lib/Doctrine/DBAL/Schema/Index.php index cc6bce37a13..bae6d218cb6 100644 --- a/lib/Doctrine/DBAL/Schema/Index.php +++ b/lib/Doctrine/DBAL/Schema/Index.php @@ -7,6 +7,7 @@ use function array_keys; use function array_map; use function array_search; +use function array_shift; use function count; use function is_string; use function strtolower; @@ -97,10 +98,21 @@ public function getColumns() */ public function getQuotedColumns(AbstractPlatform $platform) { + $subParts = $platform->supportsColumnLengthIndexes() && $this->hasOption('lengths') + ? $this->getOption('lengths') : []; + $columns = []; foreach ($this->_columns as $column) { - $columns[] = $column->getQuotedName($platform); + $length = array_shift($subParts); + + $quotedColumn = $column->getQuotedName($platform); + + if ($length !== null) { + $quotedColumn .= '(' . $length . ')'; + } + + $columns[] = $quotedColumn; } return $columns; diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php index 37518cc15ce..d0f25cb6f79 100644 --- a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -67,6 +67,8 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null } elseif (strpos($v['index_type'], 'SPATIAL') !== false) { $v['flags'] = ['SPATIAL']; } + $v['length'] = $v['sub_part'] ?? null; + $tableIndexes[$k] = $v; } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php index 425039fa023..1c0afc93e66 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -1555,4 +1555,24 @@ public function testPrimaryKeyAutoIncrement() $this->assertGreaterThan($lastUsedIdBeforeDelete, $lastUsedIdAfterDelete); } + + public function testGenerateAnIndexWithPartialColumnLength() : void + { + if (! $this->schemaManager->getDatabasePlatform()->supportsColumnLengthIndexes()) { + self::markTestSkipped('This test is only supported on platforms that support indexes with column length definitions.'); + } + + $table = new Table('test_partial_column_index'); + $table->addColumn('long_column', 'string', ['length' => 40]); + $table->addColumn('standard_column', 'integer'); + $table->addIndex(['long_column'], 'partial_long_column_idx', [], ['lengths' => [4]]); + $table->addIndex(['standard_column', 'long_column'], 'standard_and_partial_idx', [], ['lengths' => [null, 2]]); + + $expected = $table->getIndexes(); + + $this->schemaManager->dropAndCreateTable($table); + + $onlineTable = $this->schemaManager->listTableDetails('test_partial_column_index'); + self::assertEquals($expected, $onlineTable->getIndexes()); + } }